| 
									
										
										
										
											2023-01-05 13:25:55 +01:00
										 |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*  os_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.                 */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							| 
									
										
										
										
											2015-01-10 17:35:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | #include "os_windows.h"
 | 
					
						
							| 
									
										
										
										
											2016-12-21 02:29:58 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-08 14:51:32 +02:00
										 |  |  | #include "display_server_windows.h"
 | 
					
						
							|  |  |  | #include "joypad_windows.h"
 | 
					
						
							|  |  |  | #include "lang_table.h"
 | 
					
						
							|  |  |  | #include "windows_terminal_logger.h"
 | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | #include "windows_utils.h"
 | 
					
						
							| 
									
										
										
										
											2023-06-08 14:51:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-27 03:30:20 +01:00
										 |  |  | #include "core/debugger/engine_debugger.h"
 | 
					
						
							|  |  |  | #include "core/debugger/script_debugger.h"
 | 
					
						
							| 
									
										
										
										
											2018-09-11 18:13:45 +02:00
										 |  |  | #include "core/io/marshalls.h"
 | 
					
						
							|  |  |  | #include "core/version_generated.gen.h"
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | #include "drivers/windows/dir_access_windows.h"
 | 
					
						
							|  |  |  | #include "drivers/windows/file_access_windows.h"
 | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | #include "drivers/windows/file_access_windows_pipe.h"
 | 
					
						
							| 
									
										
										
										
											2024-11-10 15:52:55 +01:00
										 |  |  | #include "drivers/windows/ip_windows.h"
 | 
					
						
							| 
									
										
										
										
											2024-11-08 13:34:14 +01:00
										 |  |  | #include "drivers/windows/net_socket_winsock.h"
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | #include "main/main.h"
 | 
					
						
							| 
									
										
										
										
											2017-06-10 10:15:33 -03:00
										 |  |  | #include "servers/audio_server.h"
 | 
					
						
							| 
									
										
										
										
											2020-12-03 18:09:47 -03:00
										 |  |  | #include "servers/rendering/rendering_server_default.h"
 | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | #include "servers/text_server.h"
 | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-12 15:43:54 +01:00
										 |  |  | #include <avrt.h>
 | 
					
						
							| 
									
										
										
										
											2022-02-07 17:33:55 +01:00
										 |  |  | #include <bcrypt.h>
 | 
					
						
							| 
									
										
										
										
											2019-02-20 13:00:19 +01:00
										 |  |  | #include <direct.h>
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:42:11 -07:00
										 |  |  | #include <knownfolders.h>
 | 
					
						
							| 
									
										
										
										
											2016-04-29 13:57:57 -03:00
										 |  |  | #include <process.h>
 | 
					
						
							| 
									
										
										
										
											2023-04-03 11:46:29 +03:00
										 |  |  | #include <psapi.h>
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | #include <regstr.h>
 | 
					
						
							|  |  |  | #include <shlobj.h>
 | 
					
						
							| 
									
										
										
										
											2022-10-11 12:39:41 +02:00
										 |  |  | #include <wbemcli.h>
 | 
					
						
							| 
									
										
										
										
											2023-04-13 21:17:55 +02:00
										 |  |  | #include <wincrypt.h>
 | 
					
						
							| 
									
										
										
										
											2015-02-12 04:17:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | #ifdef DEBUG_ENABLED
 | 
					
						
							|  |  |  | #pragma pack(push, before_imagehlp, 8)
 | 
					
						
							|  |  |  | #include <imagehlp.h>
 | 
					
						
							|  |  |  | #pragma pack(pop, before_imagehlp)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-17 02:48:35 +01:00
										 |  |  | extern "C" { | 
					
						
							| 
									
										
										
										
											2018-11-02 23:10:44 +01:00
										 |  |  | __declspec(dllexport) DWORD NvOptimusEnablement = 1; | 
					
						
							|  |  |  | __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; | 
					
						
							| 
									
										
										
										
											2024-11-18 12:58:38 +02:00
										 |  |  | __declspec(dllexport) void NoHotPatch() {} // Disable Nahimic code injection.
 | 
					
						
							| 
									
										
										
										
											2015-01-17 02:48:35 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 20:46:13 +02:00
										 |  |  | // Workaround mingw-w64 < 4.0 bug
 | 
					
						
							|  |  |  | #ifndef WM_TOUCH
 | 
					
						
							|  |  |  | #define WM_TOUCH 576
 | 
					
						
							| 
									
										
										
										
											2016-02-04 17:16:22 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-13 22:32:11 +02:00
										 |  |  | #ifndef WM_POINTERUPDATE
 | 
					
						
							|  |  |  | #define WM_POINTERUPDATE 0x0245
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-05 18:16:06 +01:00
										 |  |  | // Missing in MinGW headers before 8.0.
 | 
					
						
							|  |  |  | #ifndef DWRITE_FONT_WEIGHT_SEMI_LIGHT
 | 
					
						
							|  |  |  | #define DWRITE_FONT_WEIGHT_SEMI_LIGHT (DWRITE_FONT_WEIGHT)350
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-16 12:07:58 +01:00
										 |  |  | #if defined(__GNUC__)
 | 
					
						
							|  |  |  | // Workaround GCC warning from -Wcast-function-type.
 | 
					
						
							|  |  |  | #define GetProcAddress (void *)GetProcAddress
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | static String fix_path(const String &p_path) { | 
					
						
							|  |  |  | 	String path = p_path; | 
					
						
							|  |  |  | 	if (p_path.is_relative_path()) { | 
					
						
							|  |  |  | 		Char16String current_dir_name; | 
					
						
							|  |  |  | 		size_t str_len = GetCurrentDirectoryW(0, nullptr); | 
					
						
							|  |  |  | 		current_dir_name.resize(str_len + 1); | 
					
						
							|  |  |  | 		GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw()); | 
					
						
							|  |  |  | 		path = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/").path_join(path); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	path = path.simplify_path(); | 
					
						
							|  |  |  | 	path = path.replace("/", "\\"); | 
					
						
							| 
									
										
										
										
											2024-09-10 10:20:28 +03:00
										 |  |  | 	if (path.size() >= MAX_PATH && !path.is_network_share_path() && !path.begins_with(R"(\\?\)")) { | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 		path = R"(\\?\)" + path; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return path; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-01 08:42:57 -03:00
										 |  |  | static String format_error_message(DWORD id) { | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	LPWSTR messageBuffer = nullptr; | 
					
						
							| 
									
										
										
										
											2017-12-01 08:42:57 -03:00
										 |  |  | 	size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 			nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr); | 
					
						
							| 
									
										
										
										
											2017-12-01 08:42:57 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-27 13:43:20 +03:00
										 |  |  | 	String msg = "Error " + itos(id) + ": " + String::utf16((const char16_t *)messageBuffer, size); | 
					
						
							| 
									
										
										
										
											2017-12-01 08:42:57 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	LocalFree(messageBuffer); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | 	return msg.replace("\r", "").replace("\n", ""); | 
					
						
							| 
									
										
										
										
											2017-12-01 08:42:57 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 08:30:01 +02:00
										 |  |  | void RedirectStream(const char *p_file_name, const char *p_mode, FILE *p_cpp_stream, const DWORD p_std_handle) { | 
					
						
							|  |  |  | 	const HANDLE h_existing = GetStdHandle(p_std_handle); | 
					
						
							|  |  |  | 	if (h_existing != INVALID_HANDLE_VALUE) { // Redirect only if attached console have a valid handle.
 | 
					
						
							|  |  |  | 		const HANDLE h_cpp = reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(p_cpp_stream))); | 
					
						
							|  |  |  | 		if (h_cpp == INVALID_HANDLE_VALUE) { // Redirect only if it's not already redirected to the pipe or file.
 | 
					
						
							|  |  |  | 			FILE *fp = p_cpp_stream; | 
					
						
							|  |  |  | 			freopen_s(&fp, p_file_name, p_mode, p_cpp_stream); // Redirect stream.
 | 
					
						
							|  |  |  | 			setvbuf(p_cpp_stream, nullptr, _IONBF, 0); // Disable stream buffering.
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | void RedirectIOToConsole() { | 
					
						
							| 
									
										
										
										
											2024-04-25 12:56:07 +03:00
										 |  |  | 	// Save current handles.
 | 
					
						
							|  |  |  | 	HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE); | 
					
						
							|  |  |  | 	HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); | 
					
						
							|  |  |  | 	HANDLE h_stderr = GetStdHandle(STD_ERROR_HANDLE); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 	if (AttachConsole(ATTACH_PARENT_PROCESS)) { | 
					
						
							| 
									
										
										
										
											2024-04-25 12:56:07 +03:00
										 |  |  | 		// Restore redirection (Note: if not redirected it's NULL handles not INVALID_HANDLE_VALUE).
 | 
					
						
							| 
									
										
										
										
											2024-06-21 11:21:18 -05:00
										 |  |  | 		if (h_stdin != nullptr) { | 
					
						
							| 
									
										
										
										
											2024-04-25 12:56:07 +03:00
										 |  |  | 			SetStdHandle(STD_INPUT_HANDLE, h_stdin); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-21 11:21:18 -05:00
										 |  |  | 		if (h_stdout != nullptr) { | 
					
						
							| 
									
										
										
										
											2024-04-25 12:56:07 +03:00
										 |  |  | 			SetStdHandle(STD_OUTPUT_HANDLE, h_stdout); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-06-21 11:21:18 -05:00
										 |  |  | 		if (h_stderr != nullptr) { | 
					
						
							| 
									
										
										
										
											2024-04-25 12:56:07 +03:00
										 |  |  | 			SetStdHandle(STD_ERROR_HANDLE, h_stderr); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Update file handles.
 | 
					
						
							| 
									
										
										
										
											2022-01-28 08:30:01 +02:00
										 |  |  | 		RedirectStream("CONIN$", "r", stdin, STD_INPUT_HANDLE); | 
					
						
							|  |  |  | 		RedirectStream("CONOUT$", "w", stdout, STD_OUTPUT_HANDLE); | 
					
						
							|  |  |  | 		RedirectStream("CONOUT$", "w", stderr, STD_ERROR_HANDLE); | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-28 13:41:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-26 10:34:35 +03:00
										 |  |  | bool OS_Windows::is_using_con_wrapper() const { | 
					
						
							|  |  |  | 	static String exe_renames[] = { | 
					
						
							|  |  |  | 		".console.exe", | 
					
						
							|  |  |  | 		"_console.exe", | 
					
						
							|  |  |  | 		" console.exe", | 
					
						
							|  |  |  | 		"console.exe", | 
					
						
							|  |  |  | 		String(), | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool found_exe = false; | 
					
						
							|  |  |  | 	bool found_conwrap_exe = false; | 
					
						
							|  |  |  | 	String exe_name = get_executable_path().to_lower(); | 
					
						
							|  |  |  | 	String exe_dir = exe_name.get_base_dir(); | 
					
						
							|  |  |  | 	String exe_fname = exe_name.get_file().get_basename(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	DWORD pids[256]; | 
					
						
							|  |  |  | 	DWORD count = GetConsoleProcessList(&pids[0], 256); | 
					
						
							|  |  |  | 	for (DWORD i = 0; i < count; i++) { | 
					
						
							|  |  |  | 		HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pids[i]); | 
					
						
							|  |  |  | 		if (process != NULL) { | 
					
						
							|  |  |  | 			WCHAR proc_name[MAX_PATH]; | 
					
						
							|  |  |  | 			DWORD len = MAX_PATH; | 
					
						
							|  |  |  | 			if (QueryFullProcessImageNameW(process, 0, &proc_name[0], &len)) { | 
					
						
							|  |  |  | 				String name = String::utf16((const char16_t *)&proc_name[0], len).replace("\\", "/").to_lower(); | 
					
						
							|  |  |  | 				if (name == exe_name) { | 
					
						
							|  |  |  | 					found_exe = true; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				for (int j = 0; !exe_renames[j].is_empty(); j++) { | 
					
						
							|  |  |  | 					if (name == exe_dir.path_join(exe_fname + exe_renames[j])) { | 
					
						
							|  |  |  | 						found_conwrap_exe = true; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			CloseHandle(process); | 
					
						
							|  |  |  | 			if (found_conwrap_exe && found_exe) { | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!found_exe) { | 
					
						
							|  |  |  | 		return true; // Unable to read console info, assume true.
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return found_conwrap_exe; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType) { | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (!EngineDebugger::is_active()) { | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | 		return FALSE; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-12-18 14:17:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | 	switch (dwCtrlType) { | 
					
						
							|  |  |  | 		case CTRL_C_EVENT: | 
					
						
							|  |  |  | 			EngineDebugger::get_script_debugger()->set_depth(-1); | 
					
						
							|  |  |  | 			EngineDebugger::get_script_debugger()->set_lines_left(1); | 
					
						
							|  |  |  | 			return TRUE; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return FALSE; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-12-18 14:17:43 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-22 19:23:48 +03:00
										 |  |  | void OS_Windows::alert(const String &p_alert, const String &p_title) { | 
					
						
							|  |  |  | 	MessageBoxW(nullptr, (LPCWSTR)(p_alert.utf16().get_data()), (LPCWSTR)(p_title.utf16().get_data()), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | void OS_Windows::initialize_debugging() { | 
					
						
							|  |  |  | 	SetConsoleCtrlHandler(HandlerRoutine, TRUE); | 
					
						
							| 
									
										
										
										
											2017-12-10 20:38:26 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-08 19:25:49 -04:00
										 |  |  | #ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
 | 
					
						
							|  |  |  | static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type) { | 
					
						
							|  |  |  | 	String err_str; | 
					
						
							|  |  |  | 	if (p_errorexp && p_errorexp[0]) { | 
					
						
							| 
									
										
										
										
											2024-08-27 15:00:48 +01:00
										 |  |  | 		err_str = String::utf8(p_errorexp) + "\n"; | 
					
						
							| 
									
										
										
										
											2022-05-08 19:25:49 -04:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2024-08-27 15:00:48 +01:00
										 |  |  | 		err_str = String::utf8(p_file) + ":" + itos(p_line) + " - " + String::utf8(p_error) + "\n"; | 
					
						
							| 
									
										
										
										
											2022-05-08 19:25:49 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	OutputDebugStringW((LPCWSTR)err_str.utf16().ptr()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | void OS_Windows::initialize() { | 
					
						
							|  |  |  | 	crash_handler.initialize(); | 
					
						
							| 
									
										
										
										
											2017-12-10 20:38:26 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-08 19:25:49 -04:00
										 |  |  | #ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
 | 
					
						
							|  |  |  | 	error_handlers.errfunc = _error_handler; | 
					
						
							|  |  |  | 	error_handlers.userdata = this; | 
					
						
							|  |  |  | 	add_error_handler(&error_handlers); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | 	FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES); | 
					
						
							|  |  |  | 	FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA); | 
					
						
							|  |  |  | 	FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_FILESYSTEM); | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 	FileAccess::make_default<FileAccessWindowsPipe>(FileAccess::ACCESS_PIPE); | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | 	DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_RESOURCES); | 
					
						
							|  |  |  | 	DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA); | 
					
						
							|  |  |  | 	DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM); | 
					
						
							| 
									
										
										
										
											2017-12-10 20:38:26 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-08 13:34:14 +01:00
										 |  |  | 	NetSocketWinSock::make_default(); | 
					
						
							| 
									
										
										
										
											2017-12-10 20:38:26 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | 	// We need to know how often the clock is updated
 | 
					
						
							| 
									
										
										
										
											2022-01-04 22:38:44 +01:00
										 |  |  | 	QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second); | 
					
						
							|  |  |  | 	QueryPerformanceCounter((LARGE_INTEGER *)&ticks_start); | 
					
						
							| 
									
										
										
										
											2017-12-10 20:38:26 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | 	// set minimum resolution for periodic timers, otherwise Sleep(n) may wait at least as
 | 
					
						
							|  |  |  | 	//  long as the windows scheduler resolution (~16-30ms) even for calls like Sleep(1)
 | 
					
						
							|  |  |  | 	timeBeginPeriod(1); | 
					
						
							| 
									
										
										
										
											2017-12-10 20:38:26 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-13 15:04:37 +02:00
										 |  |  | 	process_map = memnew((HashMap<ProcessID, ProcessInfo>)); | 
					
						
							| 
									
										
										
										
											2017-12-10 20:38:26 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 15:26:10 +01:00
										 |  |  | 	// Add current Godot PID to the list of known PIDs
 | 
					
						
							|  |  |  | 	ProcessInfo current_pi = {}; | 
					
						
							|  |  |  | 	PROCESS_INFORMATION current_pi_pi = {}; | 
					
						
							|  |  |  | 	current_pi.pi = current_pi_pi; | 
					
						
							|  |  |  | 	current_pi.pi.hProcess = GetCurrentProcess(); | 
					
						
							|  |  |  | 	process_map->insert(GetCurrentProcessId(), current_pi); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-10 15:52:55 +01:00
										 |  |  | 	IPWindows::make_default(); | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	main_loop = nullptr; | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown **>(&dwrite_factory)); | 
					
						
							|  |  |  | 	if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  | 		hr = dwrite_factory->GetSystemFontCollection(&font_collection, false); | 
					
						
							|  |  |  | 		if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  | 			dwrite_init = true; | 
					
						
							|  |  |  | 			hr = dwrite_factory->QueryInterface(&dwrite_factory2); | 
					
						
							|  |  |  | 			if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  | 				hr = dwrite_factory2->GetSystemFontFallback(&system_font_fallback); | 
					
						
							|  |  |  | 				if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  | 					dwrite2_init = true; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!dwrite_init) { | 
					
						
							|  |  |  | 		print_verbose("Unable to load IDWriteFactory, system font support is disabled."); | 
					
						
							|  |  |  | 	} else if (!dwrite2_init) { | 
					
						
							|  |  |  | 		print_verbose("Unable to load IDWriteFactory2, automatic system font fallback is disabled."); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-01-11 13:47:40 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	FileAccessWindows::initialize(); | 
					
						
							| 
									
										
										
										
											2017-12-10 20:38:26 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | void OS_Windows::delete_main_loop() { | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (main_loop) { | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | 		memdelete(main_loop); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	main_loop = nullptr; | 
					
						
							| 
									
										
										
										
											2017-12-10 20:38:26 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | void OS_Windows::set_main_loop(MainLoop *p_main_loop) { | 
					
						
							|  |  |  | 	main_loop = p_main_loop; | 
					
						
							| 
									
										
										
										
											2017-12-10 20:38:26 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | void OS_Windows::finalize() { | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 	if (dwrite_factory2) { | 
					
						
							|  |  |  | 		dwrite_factory2->Release(); | 
					
						
							|  |  |  | 		dwrite_factory2 = nullptr; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (font_collection) { | 
					
						
							|  |  |  | 		font_collection->Release(); | 
					
						
							|  |  |  | 		font_collection = nullptr; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (system_font_fallback) { | 
					
						
							|  |  |  | 		system_font_fallback->Release(); | 
					
						
							|  |  |  | 		system_font_fallback = nullptr; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (dwrite_factory) { | 
					
						
							|  |  |  | 		dwrite_factory->Release(); | 
					
						
							|  |  |  | 		dwrite_factory = nullptr; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | #ifdef WINMIDI_ENABLED
 | 
					
						
							|  |  |  | 	driver_midi.close(); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2017-07-09 21:48:22 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (main_loop) { | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | 		memdelete(main_loop); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-03 04:18:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	main_loop = nullptr; | 
					
						
							| 
									
										
										
										
											2016-01-03 04:18:28 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | void OS_Windows::finalize_core() { | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | 	while (!temp_libraries.is_empty()) { | 
					
						
							|  |  |  | 		_remove_temp_library(temp_libraries.last()->key); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-11 13:47:40 +01:00
										 |  |  | 	FileAccessWindows::finalize(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | 	timeEndPeriod(1); | 
					
						
							| 
									
										
										
										
											2017-12-27 20:51:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | 	memdelete(process_map); | 
					
						
							| 
									
										
										
										
											2024-11-08 13:34:14 +01:00
										 |  |  | 	NetSocketWinSock::cleanup(); | 
					
						
							| 
									
										
										
										
											2022-05-08 19:25:49 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
 | 
					
						
							|  |  |  | 	remove_error_handler(&error_handlers); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2017-07-09 21:48:22 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-02-07 17:33:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Error OS_Windows::get_entropy(uint8_t *r_buffer, int p_bytes) { | 
					
						
							|  |  |  | 	NTSTATUS status = BCryptGenRandom(nullptr, r_buffer, p_bytes, BCRYPT_USE_SYSTEM_PREFERRED_RNG); | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(status, FAILED); | 
					
						
							|  |  |  | 	return OK; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-07-09 21:48:22 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | #ifdef DEBUG_ENABLED
 | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | void debug_dynamic_library_check_dependencies(const String &p_path, HashSet<String> &r_checked, HashSet<String> &r_missing) { | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | 	if (r_checked.has(p_path)) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	r_checked.insert(p_path); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	LOADED_IMAGE loaded_image; | 
					
						
							|  |  |  | 	HANDLE file = CreateFileW((LPCWSTR)p_path.utf16().get_data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); | 
					
						
							|  |  |  | 	if (file != INVALID_HANDLE_VALUE) { | 
					
						
							|  |  |  | 		HANDLE file_mapping = CreateFileMappingW(file, nullptr, PAGE_READONLY | SEC_COMMIT, 0, 0, nullptr); | 
					
						
							|  |  |  | 		if (file_mapping != INVALID_HANDLE_VALUE) { | 
					
						
							|  |  |  | 			PVOID mapping = MapViewOfFile(file_mapping, FILE_MAP_READ, 0, 0, 0); | 
					
						
							|  |  |  | 			if (mapping) { | 
					
						
							|  |  |  | 				PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)mapping; | 
					
						
							|  |  |  | 				PIMAGE_NT_HEADERS nt_header = nullptr; | 
					
						
							|  |  |  | 				if (dos_header->e_magic == IMAGE_DOS_SIGNATURE) { | 
					
						
							|  |  |  | 					PCHAR nt_header_ptr; | 
					
						
							|  |  |  | 					nt_header_ptr = ((PCHAR)mapping) + dos_header->e_lfanew; | 
					
						
							|  |  |  | 					nt_header = (PIMAGE_NT_HEADERS)nt_header_ptr; | 
					
						
							|  |  |  | 					if (nt_header->Signature != IMAGE_NT_SIGNATURE) { | 
					
						
							|  |  |  | 						nt_header = nullptr; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (nt_header) { | 
					
						
							|  |  |  | 					loaded_image.ModuleName = nullptr; | 
					
						
							|  |  |  | 					loaded_image.hFile = file; | 
					
						
							|  |  |  | 					loaded_image.MappedAddress = (PUCHAR)mapping; | 
					
						
							|  |  |  | 					loaded_image.FileHeader = nt_header; | 
					
						
							|  |  |  | 					loaded_image.Sections = (PIMAGE_SECTION_HEADER)((LPBYTE)&nt_header->OptionalHeader + nt_header->FileHeader.SizeOfOptionalHeader); | 
					
						
							|  |  |  | 					loaded_image.NumberOfSections = nt_header->FileHeader.NumberOfSections; | 
					
						
							|  |  |  | 					loaded_image.SizeOfImage = GetFileSize(file, nullptr); | 
					
						
							|  |  |  | 					loaded_image.Characteristics = nt_header->FileHeader.Characteristics; | 
					
						
							|  |  |  | 					loaded_image.LastRvaSection = loaded_image.Sections; | 
					
						
							|  |  |  | 					loaded_image.fSystemImage = false; | 
					
						
							|  |  |  | 					loaded_image.fDOSImage = false; | 
					
						
							|  |  |  | 					loaded_image.Links.Flink = &loaded_image.Links; | 
					
						
							|  |  |  | 					loaded_image.Links.Blink = &loaded_image.Links; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					ULONG size = 0; | 
					
						
							|  |  |  | 					const IMAGE_IMPORT_DESCRIPTOR *import_desc = (const IMAGE_IMPORT_DESCRIPTOR *)ImageDirectoryEntryToData((HMODULE)loaded_image.MappedAddress, false, IMAGE_DIRECTORY_ENTRY_IMPORT, &size); | 
					
						
							|  |  |  | 					if (import_desc) { | 
					
						
							|  |  |  | 						for (; import_desc->Name && import_desc->FirstThunk; import_desc++) { | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 							char16_t full_name_wc[32767]; | 
					
						
							| 
									
										
										
										
											2024-03-12 09:40:40 -05:00
										 |  |  | 							const char *name_cs = (const char *)ImageRvaToVa(loaded_image.FileHeader, loaded_image.MappedAddress, import_desc->Name, nullptr); | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | 							String name = String(name_cs); | 
					
						
							|  |  |  | 							if (name.begins_with("api-ms-win-")) { | 
					
						
							|  |  |  | 								r_checked.insert(name); | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 							} else if (SearchPathW(nullptr, (LPCWSTR)name.utf16().get_data(), nullptr, 32767, (LPWSTR)full_name_wc, nullptr)) { | 
					
						
							|  |  |  | 								debug_dynamic_library_check_dependencies(String::utf16(full_name_wc), r_checked, r_missing); | 
					
						
							|  |  |  | 							} else if (SearchPathW((LPCWSTR)(p_path.get_base_dir().utf16().get_data()), (LPCWSTR)name.utf16().get_data(), nullptr, 32767, (LPWSTR)full_name_wc, nullptr)) { | 
					
						
							|  |  |  | 								debug_dynamic_library_check_dependencies(String::utf16(full_name_wc), r_checked, r_missing); | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | 							} else { | 
					
						
							|  |  |  | 								r_missing.insert(name); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				UnmapViewOfFile(mapping); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			CloseHandle(file_mapping); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		CloseHandle(file); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-19 07:14:05 -07:00
										 |  |  | Error OS_Windows::open_dynamic_library(const String &p_path, void *&p_library_handle, GDExtensionData *p_data) { | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 	String path = p_path; | 
					
						
							| 
									
										
										
										
											2018-01-04 15:42:29 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!FileAccess::exists(path)) { | 
					
						
							| 
									
										
										
										
											2022-12-07 12:11:28 +01:00
										 |  |  | 		//this code exists so gdextension can load .dll files from within the executable path
 | 
					
						
							| 
									
										
										
										
											2022-08-29 19:34:01 -05:00
										 |  |  | 		path = get_executable_path().get_base_dir().path_join(p_path.get_file()); | 
					
						
							| 
									
										
										
										
											2018-01-04 15:42:29 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-08-04 11:00:56 -06:00
										 |  |  | 	// Path to load from may be different from original if we make copies.
 | 
					
						
							|  |  |  | 	String load_path = path; | 
					
						
							| 
									
										
										
										
											2018-01-04 15:42:29 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-01 19:48:28 +08:00
										 |  |  | 	ERR_FAIL_COND_V(!FileAccess::exists(path), ERR_FILE_NOT_FOUND); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | 	// Here we want a copy to be loaded.
 | 
					
						
							|  |  |  | 	// This is so the original file isn't locked and can be updated by a compiler.
 | 
					
						
							| 
									
										
										
										
											2024-04-19 07:14:05 -07:00
										 |  |  | 	if (p_data != nullptr && p_data->generate_temp_files) { | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | 		// Copy the file to the same directory as the original with a prefix in the name.
 | 
					
						
							|  |  |  | 		// This is so relative path to dependencies are satisfied.
 | 
					
						
							| 
									
										
										
										
											2024-08-04 11:00:56 -06:00
										 |  |  | 		load_path = path.get_base_dir().path_join("~" + path.get_file()); | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// If there's a left-over copy (possibly from a crash) then delete it first.
 | 
					
						
							| 
									
										
										
										
											2024-08-04 11:00:56 -06:00
										 |  |  | 		if (FileAccess::exists(load_path)) { | 
					
						
							|  |  |  | 			DirAccess::remove_absolute(load_path); | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-04 11:00:56 -06:00
										 |  |  | 		Error copy_err = DirAccess::copy_absolute(path, load_path); | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | 		if (copy_err) { | 
					
						
							|  |  |  | 			ERR_PRINT("Error copying library: " + path); | 
					
						
							|  |  |  | 			return ERR_CANT_CREATE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-04 11:00:56 -06:00
										 |  |  | 		FileAccess::set_hidden_attribute(load_path, true); | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-04 11:00:56 -06:00
										 |  |  | 		Error pdb_err = WindowsUtils::copy_and_rename_pdb(load_path); | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | 		if (pdb_err != OK && pdb_err != ERR_SKIP) { | 
					
						
							|  |  |  | 			WARN_PRINT(vformat("Failed to rename the PDB file. The original PDB file for '%s' will be loaded.", path)); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-06 14:29:01 +02:00
										 |  |  | 	typedef DLL_DIRECTORY_COOKIE(WINAPI * PAddDllDirectory)(PCWSTR); | 
					
						
							|  |  |  | 	typedef BOOL(WINAPI * PRemoveDllDirectory)(DLL_DIRECTORY_COOKIE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	PAddDllDirectory add_dll_directory = (PAddDllDirectory)GetProcAddress(GetModuleHandle("kernel32.dll"), "AddDllDirectory"); | 
					
						
							|  |  |  | 	PRemoveDllDirectory remove_dll_directory = (PRemoveDllDirectory)GetProcAddress(GetModuleHandle("kernel32.dll"), "RemoveDllDirectory"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	bool has_dll_directory_api = ((add_dll_directory != nullptr) && (remove_dll_directory != nullptr)); | 
					
						
							|  |  |  | 	DLL_DIRECTORY_COOKIE cookie = nullptr; | 
					
						
							| 
									
										
										
										
											2017-11-30 10:00:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-28 20:12:09 +03:00
										 |  |  | 	String dll_path = fix_path(load_path); | 
					
						
							|  |  |  | 	String dll_dir = fix_path(ProjectSettings::get_singleton()->globalize_path(load_path.get_base_dir())); | 
					
						
							| 
									
										
										
										
											2024-04-19 07:14:05 -07:00
										 |  |  | 	if (p_data != nullptr && p_data->also_set_library_path && has_dll_directory_api) { | 
					
						
							| 
									
										
										
										
											2024-08-28 20:12:09 +03:00
										 |  |  | 		cookie = add_dll_directory((LPCWSTR)(dll_dir.utf16().get_data())); | 
					
						
							| 
									
										
										
										
											2017-11-30 10:00:10 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-28 20:12:09 +03:00
										 |  |  | 	p_library_handle = (void *)LoadLibraryExW((LPCWSTR)(dll_path.utf16().get_data()), nullptr, (p_data != nullptr && p_data->also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0); | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | 	if (!p_library_handle) { | 
					
						
							| 
									
										
										
										
											2024-04-19 07:14:05 -07:00
										 |  |  | 		if (p_data != nullptr && p_data->generate_temp_files) { | 
					
						
							| 
									
										
										
										
											2024-08-04 11:00:56 -06:00
										 |  |  | 			DirAccess::remove_absolute(load_path); | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef DEBUG_ENABLED
 | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | 		DWORD err_code = GetLastError(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-04 11:00:56 -06:00
										 |  |  | 		HashSet<String> checked_libs; | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | 		HashSet<String> missing_libs; | 
					
						
							| 
									
										
										
										
											2024-08-28 20:12:09 +03:00
										 |  |  | 		debug_dynamic_library_check_dependencies(dll_path, checked_libs, missing_libs); | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | 		if (!missing_libs.is_empty()) { | 
					
						
							|  |  |  | 			String missing; | 
					
						
							|  |  |  | 			for (const String &E : missing_libs) { | 
					
						
							|  |  |  | 				if (!missing.is_empty()) { | 
					
						
							|  |  |  | 					missing += ", "; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				missing += E; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-06-28 17:51:02 +02:00
										 |  |  | 			ERR_FAIL_V_MSG(ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Missing dependencies: %s. Error: %s.", p_path, missing, format_error_message(err_code))); | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2023-06-28 17:51:02 +02:00
										 |  |  | 			ERR_FAIL_V_MSG(ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, format_error_message(err_code))); | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifndef DEBUG_ENABLED
 | 
					
						
							| 
									
										
										
										
											2023-09-09 17:46:44 +02:00
										 |  |  | 	ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, format_error_message(GetLastError()))); | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2017-11-30 10:00:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-26 11:48:20 +01:00
										 |  |  | 	if (cookie) { | 
					
						
							| 
									
										
										
										
											2017-12-06 14:29:01 +02:00
										 |  |  | 		remove_dll_directory(cookie); | 
					
						
							| 
									
										
										
										
											2017-11-30 10:00:10 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-19 07:14:05 -07:00
										 |  |  | 	if (p_data != nullptr && p_data->r_resolved_path != nullptr) { | 
					
						
							|  |  |  | 		*p_data->r_resolved_path = path; | 
					
						
							| 
									
										
										
										
											2022-04-29 00:51:04 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-19 07:14:05 -07:00
										 |  |  | 	if (p_data != nullptr && p_data->generate_temp_files) { | 
					
						
							| 
									
										
										
										
											2024-08-04 11:00:56 -06:00
										 |  |  | 		// Save the copied path so it can be deleted later.
 | 
					
						
							|  |  |  | 		temp_libraries[p_library_handle] = load_path; | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-08 02:50:13 +01:00
										 |  |  | 	return OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-03 16:11:38 +02:00
										 |  |  | Error OS_Windows::close_dynamic_library(void *p_library_handle) { | 
					
						
							|  |  |  | 	if (!FreeLibrary((HMODULE)p_library_handle)) { | 
					
						
							| 
									
										
										
										
											2017-03-08 02:50:13 +01:00
										 |  |  | 		return FAILED; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Delete temporary copy of library if it exists.
 | 
					
						
							|  |  |  | 	_remove_temp_library(p_library_handle); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-08 02:50:13 +01:00
										 |  |  | 	return OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-11 15:33:35 +03:00
										 |  |  | void OS_Windows::_remove_temp_library(void *p_library_handle) { | 
					
						
							|  |  |  | 	if (temp_libraries.has(p_library_handle)) { | 
					
						
							|  |  |  | 		String path = temp_libraries[p_library_handle]; | 
					
						
							|  |  |  | 		DirAccess::remove_absolute(path); | 
					
						
							|  |  |  | 		WindowsUtils::remove_temp_pdbs(path); | 
					
						
							|  |  |  | 		temp_libraries.erase(p_library_handle); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-08 22:36:19 -03:00
										 |  |  | Error OS_Windows::get_dynamic_library_symbol_handle(void *p_library_handle, const String &p_name, void *&p_symbol_handle, bool p_optional) { | 
					
						
							| 
									
										
										
										
											2017-04-03 16:11:38 +02:00
										 |  |  | 	p_symbol_handle = (void *)GetProcAddress((HMODULE)p_library_handle, p_name.utf8().get_data()); | 
					
						
							| 
									
										
										
										
											2017-03-08 02:50:13 +01:00
										 |  |  | 	if (!p_symbol_handle) { | 
					
						
							| 
									
										
										
										
											2017-07-27 09:23:21 +02:00
										 |  |  | 		if (!p_optional) { | 
					
						
							| 
									
										
										
										
											2023-03-27 11:49:05 +03:00
										 |  |  | 			ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, vformat("Can't resolve symbol %s, error: \"%s\".", p_name, format_error_message(GetLastError()))); | 
					
						
							| 
									
										
										
										
											2017-07-27 09:23:21 +02:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			return ERR_CANT_RESOLVE; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-03-08 02:50:13 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-20 13:36:24 -04:00
										 |  |  | String OS_Windows::get_name() const { | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	return "Windows"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-16 11:14:14 +02:00
										 |  |  | String OS_Windows::get_distribution_name() const { | 
					
						
							|  |  |  | 	return get_name(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String OS_Windows::get_version() const { | 
					
						
							|  |  |  | 	RtlGetVersionPtr version_ptr = (RtlGetVersionPtr)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion"); | 
					
						
							|  |  |  | 	if (version_ptr != nullptr) { | 
					
						
							| 
									
										
										
										
											2022-10-06 09:30:25 +03:00
										 |  |  | 		RTL_OSVERSIONINFOW fow; | 
					
						
							|  |  |  | 		ZeroMemory(&fow, sizeof(fow)); | 
					
						
							| 
									
										
										
										
											2022-09-16 11:14:14 +02:00
										 |  |  | 		fow.dwOSVersionInfoSize = sizeof(fow); | 
					
						
							|  |  |  | 		if (version_ptr(&fow) == 0x00000000) { | 
					
						
							|  |  |  | 			return vformat("%d.%d.%d", (int64_t)fow.dwMajorVersion, (int64_t)fow.dwMinorVersion, (int64_t)fow.dwBuildNumber); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ""; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-11 12:39:41 +02:00
										 |  |  | Vector<String> OS_Windows::get_video_adapter_driver_info() const { | 
					
						
							| 
									
										
										
										
											2023-06-06 23:29:36 +02:00
										 |  |  | 	if (RenderingServer::get_singleton() == nullptr) { | 
					
						
							| 
									
										
										
										
											2022-10-27 13:52:38 -07:00
										 |  |  | 		return Vector<String>(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-27 18:21:23 +02:00
										 |  |  | 	static Vector<String> info; | 
					
						
							|  |  |  | 	if (!info.is_empty()) { | 
					
						
							|  |  |  | 		return info; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-11 12:39:41 +02:00
										 |  |  | 	REFCLSID clsid = CLSID_WbemLocator; // Unmarshaler CLSID
 | 
					
						
							|  |  |  | 	REFIID uuid = IID_IWbemLocator; // Interface UUID
 | 
					
						
							| 
									
										
										
										
											2024-03-12 09:40:40 -05:00
										 |  |  | 	IWbemLocator *wbemLocator = nullptr; // to get the services
 | 
					
						
							|  |  |  | 	IWbemServices *wbemServices = nullptr; // to get the class
 | 
					
						
							|  |  |  | 	IEnumWbemClassObject *iter = nullptr; | 
					
						
							| 
									
										
										
										
											2022-10-11 12:39:41 +02:00
										 |  |  | 	IWbemClassObject *pnpSDriverObject[1]; // contains driver name, version, etc.
 | 
					
						
							| 
									
										
										
										
											2023-05-27 18:21:23 +02:00
										 |  |  | 	String driver_name; | 
					
						
							|  |  |  | 	String driver_version; | 
					
						
							| 
									
										
										
										
											2022-10-11 12:39:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-06 23:29:36 +02:00
										 |  |  | 	const String device_name = RenderingServer::get_singleton()->get_video_adapter_name(); | 
					
						
							| 
									
										
										
										
											2022-10-11 12:39:41 +02:00
										 |  |  | 	if (device_name.is_empty()) { | 
					
						
							|  |  |  | 		return Vector<String>(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-12 09:40:40 -05:00
										 |  |  | 	HRESULT hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, uuid, (LPVOID *)&wbemLocator); | 
					
						
							| 
									
										
										
										
											2022-10-11 12:39:41 +02:00
										 |  |  | 	if (hr != S_OK) { | 
					
						
							|  |  |  | 		return Vector<String>(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-10-12 20:17:49 +03:00
										 |  |  | 	BSTR resource_name = SysAllocString(L"root\\CIMV2"); | 
					
						
							| 
									
										
										
										
											2024-03-12 09:40:40 -05:00
										 |  |  | 	hr = wbemLocator->ConnectServer(resource_name, nullptr, nullptr, nullptr, 0, nullptr, nullptr, &wbemServices); | 
					
						
							| 
									
										
										
										
											2022-10-12 20:17:49 +03:00
										 |  |  | 	SysFreeString(resource_name); | 
					
						
							| 
									
										
										
										
											2022-10-11 12:39:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	SAFE_RELEASE(wbemLocator) // from now on, use `wbemServices`
 | 
					
						
							|  |  |  | 	if (hr != S_OK) { | 
					
						
							|  |  |  | 		SAFE_RELEASE(wbemServices) | 
					
						
							|  |  |  | 		return Vector<String>(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const String gpu_device_class_query = vformat("SELECT * FROM Win32_PnPSignedDriver WHERE DeviceName = \"%s\"", device_name); | 
					
						
							|  |  |  | 	BSTR query = SysAllocString((const WCHAR *)gpu_device_class_query.utf16().get_data()); | 
					
						
							|  |  |  | 	BSTR query_lang = SysAllocString(L"WQL"); | 
					
						
							| 
									
										
										
										
											2024-03-12 09:40:40 -05:00
										 |  |  | 	hr = wbemServices->ExecQuery(query_lang, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, nullptr, &iter); | 
					
						
							| 
									
										
										
										
											2022-10-11 12:39:41 +02:00
										 |  |  | 	SysFreeString(query_lang); | 
					
						
							|  |  |  | 	SysFreeString(query); | 
					
						
							|  |  |  | 	if (hr == S_OK) { | 
					
						
							|  |  |  | 		ULONG resultCount; | 
					
						
							|  |  |  | 		hr = iter->Next(5000, 1, pnpSDriverObject, &resultCount); // Get exactly 1. Wait max 5 seconds.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (hr == S_OK && resultCount > 0) { | 
					
						
							|  |  |  | 			VARIANT dn; | 
					
						
							|  |  |  | 			VariantInit(&dn); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			BSTR object_name = SysAllocString(L"DriverName"); | 
					
						
							| 
									
										
										
										
											2024-03-12 09:40:40 -05:00
										 |  |  | 			hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, nullptr, nullptr); | 
					
						
							| 
									
										
										
										
											2022-10-11 12:39:41 +02:00
										 |  |  | 			SysFreeString(object_name); | 
					
						
							|  |  |  | 			if (hr == S_OK) { | 
					
						
							|  |  |  | 				String d_name = String(V_BSTR(&dn)); | 
					
						
							|  |  |  | 				if (d_name.is_empty()) { | 
					
						
							|  |  |  | 					object_name = SysAllocString(L"DriverProviderName"); | 
					
						
							| 
									
										
										
										
											2024-03-12 09:40:40 -05:00
										 |  |  | 					hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, nullptr, nullptr); | 
					
						
							| 
									
										
										
										
											2022-10-11 12:39:41 +02:00
										 |  |  | 					SysFreeString(object_name); | 
					
						
							|  |  |  | 					if (hr == S_OK) { | 
					
						
							|  |  |  | 						driver_name = String(V_BSTR(&dn)); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					driver_name = d_name; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				object_name = SysAllocString(L"DriverProviderName"); | 
					
						
							| 
									
										
										
										
											2024-03-12 09:40:40 -05:00
										 |  |  | 				hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, nullptr, nullptr); | 
					
						
							| 
									
										
										
										
											2022-10-11 12:39:41 +02:00
										 |  |  | 				SysFreeString(object_name); | 
					
						
							|  |  |  | 				if (hr == S_OK) { | 
					
						
							|  |  |  | 					driver_name = String(V_BSTR(&dn)); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			VARIANT dv; | 
					
						
							|  |  |  | 			VariantInit(&dv); | 
					
						
							|  |  |  | 			object_name = SysAllocString(L"DriverVersion"); | 
					
						
							| 
									
										
										
										
											2024-03-12 09:40:40 -05:00
										 |  |  | 			hr = pnpSDriverObject[0]->Get(object_name, 0, &dv, nullptr, nullptr); | 
					
						
							| 
									
										
										
										
											2022-10-11 12:39:41 +02:00
										 |  |  | 			SysFreeString(object_name); | 
					
						
							|  |  |  | 			if (hr == S_OK) { | 
					
						
							|  |  |  | 				driver_version = String(V_BSTR(&dv)); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for (ULONG i = 0; i < resultCount; i++) { | 
					
						
							|  |  |  | 				SAFE_RELEASE(pnpSDriverObject[i]) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	SAFE_RELEASE(wbemServices) | 
					
						
							|  |  |  | 	SAFE_RELEASE(iter) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	info.push_back(driver_name); | 
					
						
							|  |  |  | 	info.push_back(driver_version); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return info; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-06 05:21:43 +08:00
										 |  |  | bool OS_Windows::get_user_prefers_integrated_gpu() const { | 
					
						
							|  |  |  | 	// On Windows 10, the preferred GPU configured in Windows Settings is
 | 
					
						
							|  |  |  | 	// stored in the registry under the key
 | 
					
						
							|  |  |  | 	// `HKEY_CURRENT_USER\SOFTWARE\Microsoft\DirectX\UserGpuPreferences`
 | 
					
						
							| 
									
										
										
										
											2024-07-06 18:15:45 +08:00
										 |  |  | 	// with the name being the app ID or EXE path. The value is in the form of
 | 
					
						
							| 
									
										
										
										
											2024-07-06 05:21:43 +08:00
										 |  |  | 	// `GpuPreference=1;`, with the value being 1 for integrated GPU and 2
 | 
					
						
							|  |  |  | 	// for discrete GPU. On Windows 11, there may be more flags, separated
 | 
					
						
							|  |  |  | 	// by semicolons.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-06 18:15:45 +08:00
										 |  |  | 	// If this is a packaged app, use the "application user model ID".
 | 
					
						
							|  |  |  | 	// Otherwise, use the EXE path.
 | 
					
						
							|  |  |  | 	WCHAR value_name[32768]; | 
					
						
							|  |  |  | 	bool is_packaged = false; | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); | 
					
						
							|  |  |  | 		if (kernel32) { | 
					
						
							|  |  |  | 			using GetCurrentApplicationUserModelIdPtr = LONG(WINAPI *)(UINT32 * length, PWSTR id); | 
					
						
							|  |  |  | 			GetCurrentApplicationUserModelIdPtr GetCurrentApplicationUserModelId = (GetCurrentApplicationUserModelIdPtr)GetProcAddress(kernel32, "GetCurrentApplicationUserModelId"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (GetCurrentApplicationUserModelId) { | 
					
						
							|  |  |  | 				UINT32 length = sizeof(value_name) / sizeof(value_name[0]); | 
					
						
							|  |  |  | 				LONG result = GetCurrentApplicationUserModelId(&length, value_name); | 
					
						
							|  |  |  | 				if (result == ERROR_SUCCESS) { | 
					
						
							|  |  |  | 					is_packaged = true; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!is_packaged && GetModuleFileNameW(nullptr, value_name, sizeof(value_name) / sizeof(value_name[0])) >= sizeof(value_name) / sizeof(value_name[0])) { | 
					
						
							| 
									
										
										
										
											2024-07-06 05:21:43 +08:00
										 |  |  | 		// Paths should never be longer than 32767, but just in case.
 | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	LPCWSTR subkey = L"SOFTWARE\\Microsoft\\DirectX\\UserGpuPreferences"; | 
					
						
							|  |  |  | 	HKEY hkey = nullptr; | 
					
						
							|  |  |  | 	LSTATUS result = RegOpenKeyExW(HKEY_CURRENT_USER, subkey, 0, KEY_READ, &hkey); | 
					
						
							|  |  |  | 	if (result != ERROR_SUCCESS) { | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	DWORD size = 0; | 
					
						
							| 
									
										
										
										
											2024-07-06 18:15:45 +08:00
										 |  |  | 	result = RegGetValueW(hkey, nullptr, value_name, RRF_RT_REG_SZ, nullptr, nullptr, &size); | 
					
						
							| 
									
										
										
										
											2024-07-06 05:21:43 +08:00
										 |  |  | 	if (result != ERROR_SUCCESS || size == 0) { | 
					
						
							|  |  |  | 		RegCloseKey(hkey); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Vector<WCHAR> buffer; | 
					
						
							|  |  |  | 	buffer.resize(size / sizeof(WCHAR)); | 
					
						
							| 
									
										
										
										
											2024-07-06 18:15:45 +08:00
										 |  |  | 	result = RegGetValueW(hkey, nullptr, value_name, RRF_RT_REG_SZ, nullptr, (LPBYTE)buffer.ptrw(), &size); | 
					
						
							| 
									
										
										
										
											2024-07-06 05:21:43 +08:00
										 |  |  | 	if (result != ERROR_SUCCESS) { | 
					
						
							|  |  |  | 		RegCloseKey(hkey); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	RegCloseKey(hkey); | 
					
						
							|  |  |  | 	const String flags = String::utf16((const char16_t *)buffer.ptr(), size / sizeof(WCHAR)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (const String &flag : flags.split(";", false)) { | 
					
						
							|  |  |  | 		if (flag == "GpuPreference=1") { | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 13:36:10 +08:00
										 |  |  | OS::DateTime OS_Windows::get_datetime(bool p_utc) const { | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	SYSTEMTIME systemtime; | 
					
						
							| 
									
										
										
										
											2021-10-28 10:16:47 -05:00
										 |  |  | 	if (p_utc) { | 
					
						
							| 
									
										
										
										
											2015-06-06 03:40:56 +02:00
										 |  |  | 		GetSystemTime(&systemtime); | 
					
						
							| 
									
										
										
										
											2021-10-28 10:16:47 -05:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2015-06-06 03:40:56 +02:00
										 |  |  | 		GetLocalTime(&systemtime); | 
					
						
							| 
									
										
										
										
											2021-10-28 10:16:47 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-07 15:06:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-17 06:28:08 -04:00
										 |  |  | 	//Get DST information from Windows, but only if p_utc is false.
 | 
					
						
							|  |  |  | 	TIME_ZONE_INFORMATION info; | 
					
						
							| 
									
										
										
										
											2023-05-11 12:32:23 +02:00
										 |  |  | 	bool is_daylight = false; | 
					
						
							| 
									
										
										
										
											2022-03-17 06:28:08 -04:00
										 |  |  | 	if (!p_utc && GetTimeZoneInformation(&info) == TIME_ZONE_ID_DAYLIGHT) { | 
					
						
							| 
									
										
										
										
											2023-05-11 12:32:23 +02:00
										 |  |  | 		is_daylight = true; | 
					
						
							| 
									
										
										
										
											2022-03-17 06:28:08 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 13:36:10 +08:00
										 |  |  | 	DateTime dt; | 
					
						
							|  |  |  | 	dt.year = systemtime.wYear; | 
					
						
							|  |  |  | 	dt.month = Month(systemtime.wMonth); | 
					
						
							|  |  |  | 	dt.day = systemtime.wDay; | 
					
						
							|  |  |  | 	dt.weekday = Weekday(systemtime.wDayOfWeek); | 
					
						
							|  |  |  | 	dt.hour = systemtime.wHour; | 
					
						
							|  |  |  | 	dt.minute = systemtime.wMinute; | 
					
						
							|  |  |  | 	dt.second = systemtime.wSecond; | 
					
						
							| 
									
										
										
										
											2023-05-11 12:32:23 +02:00
										 |  |  | 	dt.dst = is_daylight; | 
					
						
							| 
									
										
										
										
											2022-09-08 13:36:10 +08:00
										 |  |  | 	return dt; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-06 05:35:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | OS::TimeZoneInfo OS_Windows::get_time_zone_info() const { | 
					
						
							|  |  |  | 	TIME_ZONE_INFORMATION info; | 
					
						
							| 
									
										
										
										
											2023-05-11 12:32:23 +02:00
										 |  |  | 	bool is_daylight = false; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (GetTimeZoneInformation(&info) == TIME_ZONE_ID_DAYLIGHT) { | 
					
						
							| 
									
										
										
										
											2023-05-11 12:32:23 +02:00
										 |  |  | 		is_daylight = true; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-06 05:35:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-17 06:28:08 -04:00
										 |  |  | 	// Daylight Bias needs to be added to the bias if DST is in effect, or else it will not properly update.
 | 
					
						
							| 
									
										
										
										
											2015-06-07 16:10:33 +02:00
										 |  |  | 	TimeZoneInfo ret; | 
					
						
							| 
									
										
										
										
											2023-05-11 12:32:23 +02:00
										 |  |  | 	if (is_daylight) { | 
					
						
							| 
									
										
										
										
											2015-06-06 05:35:38 +02:00
										 |  |  | 		ret.name = info.DaylightName; | 
					
						
							| 
									
										
										
										
											2022-03-17 06:28:08 -04:00
										 |  |  | 		ret.bias = info.Bias + info.DaylightBias; | 
					
						
							| 
									
										
										
										
											2015-06-06 05:35:38 +02:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		ret.name = info.StandardName; | 
					
						
							| 
									
										
										
										
											2022-03-17 06:28:08 -04:00
										 |  |  | 		ret.bias = info.Bias + info.StandardBias; | 
					
						
							| 
									
										
										
										
											2015-06-06 05:35:38 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-12 21:41:19 -03:00
										 |  |  | 	// Bias value returned by GetTimeZoneInformation is inverted of what we expect
 | 
					
						
							| 
									
										
										
										
											2021-03-12 19:05:16 +05:30
										 |  |  | 	// For example, on GMT-3 GetTimeZoneInformation return a Bias of 180, so invert the value to get -180
 | 
					
						
							| 
									
										
										
										
											2022-03-17 06:28:08 -04:00
										 |  |  | 	ret.bias = -ret.bias; | 
					
						
							| 
									
										
										
										
											2015-06-06 05:35:38 +02:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-31 14:19:31 +02:00
										 |  |  | double OS_Windows::get_unix_time() const { | 
					
						
							|  |  |  | 	// 1 Windows tick is 100ns
 | 
					
						
							|  |  |  | 	const uint64_t WINDOWS_TICKS_PER_SECOND = 10000000; | 
					
						
							|  |  |  | 	const uint64_t TICKS_TO_UNIX_EPOCH = 116444736000000000LL; | 
					
						
							| 
									
										
										
										
											2016-06-11 14:09:21 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-06 10:29:33 -07:00
										 |  |  | 	SYSTEMTIME st; | 
					
						
							|  |  |  | 	GetSystemTime(&st); | 
					
						
							| 
									
										
										
										
											2016-01-10 18:24:55 -03:00
										 |  |  | 	FILETIME ft; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	SystemTimeToFileTime(&st, &ft); | 
					
						
							| 
									
										
										
										
											2020-05-31 14:19:31 +02:00
										 |  |  | 	uint64_t ticks_time; | 
					
						
							|  |  |  | 	ticks_time = ft.dwHighDateTime; | 
					
						
							|  |  |  | 	ticks_time <<= 32; | 
					
						
							|  |  |  | 	ticks_time |= ft.dwLowDateTime; | 
					
						
							| 
									
										
										
										
											2016-06-11 14:09:21 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-31 14:19:31 +02:00
										 |  |  | 	return (double)(ticks_time - TICKS_TO_UNIX_EPOCH) / WINDOWS_TICKS_PER_SECOND; | 
					
						
							| 
									
										
										
										
											2015-08-06 10:29:33 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | void OS_Windows::delay_usec(uint32_t p_usec) const { | 
					
						
							| 
									
										
										
										
											2024-11-13 10:19:21 -06:00
										 |  |  | 	constexpr uint32_t tolerance = 1000 + 20; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	uint64_t t0 = get_ticks_usec(); | 
					
						
							|  |  |  | 	uint64_t target_time = t0 + p_usec; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Calculate sleep duration with a tolerance for fine-tuning.
 | 
					
						
							|  |  |  | 	if (p_usec > tolerance) { | 
					
						
							|  |  |  | 		uint32_t coarse_sleep_usec = p_usec - tolerance; | 
					
						
							|  |  |  | 		if (coarse_sleep_usec >= 1000) { | 
					
						
							|  |  |  | 			Sleep(coarse_sleep_usec / 1000); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Spin-wait until we reach the precise target time.
 | 
					
						
							|  |  |  | 	while (get_ticks_usec() < target_time) { | 
					
						
							|  |  |  | 		YieldProcessor(); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-05-14 14:29:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | uint64_t OS_Windows::get_ticks_usec() const { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	uint64_t ticks; | 
					
						
							| 
									
										
										
										
											2020-05-22 12:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	// This is the number of clock ticks since start
 | 
					
						
							| 
									
										
										
										
											2022-01-04 22:38:44 +01:00
										 |  |  | 	QueryPerformanceCounter((LARGE_INTEGER *)&ticks); | 
					
						
							|  |  |  | 	// Subtract the ticks at game start to get
 | 
					
						
							|  |  |  | 	// the ticks since the game started
 | 
					
						
							|  |  |  | 	ticks -= ticks_start; | 
					
						
							| 
									
										
										
										
											2020-05-22 12:20:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	// Divide by frequency to get the time in seconds
 | 
					
						
							| 
									
										
										
										
											2020-05-22 12:20:19 +01:00
										 |  |  | 	// original calculation shown below is subject to overflow
 | 
					
						
							|  |  |  | 	// with high ticks_per_second and a number of days since the last reboot.
 | 
					
						
							|  |  |  | 	// time = ticks * 1000000L / ticks_per_second;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// we can prevent this by either using 128 bit math
 | 
					
						
							|  |  |  | 	// or separating into a calculation for seconds, and the fraction
 | 
					
						
							|  |  |  | 	uint64_t seconds = ticks / ticks_per_second; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// compiler will optimize these two into one divide
 | 
					
						
							|  |  |  | 	uint64_t leftover = ticks % ticks_per_second; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// remainder
 | 
					
						
							|  |  |  | 	uint64_t time = (leftover * 1000000L) / ticks_per_second; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// seconds
 | 
					
						
							|  |  |  | 	time += seconds * 1000000L; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	return time; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-19 16:34:15 +03:00
										 |  |  | String OS_Windows::_quote_command_line_argument(const String &p_text) const { | 
					
						
							|  |  |  | 	for (int i = 0; i < p_text.size(); i++) { | 
					
						
							| 
									
										
										
										
											2020-07-27 13:43:20 +03:00
										 |  |  | 		char32_t c = p_text[i]; | 
					
						
							| 
									
										
										
										
											2020-05-19 16:34:15 +03:00
										 |  |  | 		if (c == ' ' || c == '&' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' || c == '^' || c == '=' || c == ';' || c == '!' || c == '\'' || c == '+' || c == ',' || c == '`' || c == '~') { | 
					
						
							|  |  |  | 			return "\"" + p_text + "\""; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return p_text; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-10 18:27:45 +08:00
										 |  |  | static void _append_to_pipe(char *p_bytes, int p_size, String *r_pipe, Mutex *p_pipe_mutex) { | 
					
						
							|  |  |  | 	// Try to convert from default ANSI code page to Unicode.
 | 
					
						
							|  |  |  | 	LocalVector<wchar_t> wchars; | 
					
						
							|  |  |  | 	int total_wchars = MultiByteToWideChar(CP_ACP, 0, p_bytes, p_size, nullptr, 0); | 
					
						
							|  |  |  | 	if (total_wchars > 0) { | 
					
						
							|  |  |  | 		wchars.resize(total_wchars); | 
					
						
							|  |  |  | 		if (MultiByteToWideChar(CP_ACP, 0, p_bytes, p_size, wchars.ptr(), total_wchars) == 0) { | 
					
						
							|  |  |  | 			wchars.clear(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (p_pipe_mutex) { | 
					
						
							|  |  |  | 		p_pipe_mutex->lock(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (wchars.is_empty()) { | 
					
						
							|  |  |  | 		// Let's hope it's compatible with UTF-8.
 | 
					
						
							|  |  |  | 		(*r_pipe) += String::utf8(p_bytes, p_size); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		(*r_pipe) += String(wchars.ptr(), total_wchars); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (p_pipe_mutex) { | 
					
						
							|  |  |  | 		p_pipe_mutex->unlock(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 11:46:29 +03:00
										 |  |  | Dictionary OS_Windows::get_memory_info() const { | 
					
						
							|  |  |  | 	Dictionary meminfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	meminfo["physical"] = -1; | 
					
						
							|  |  |  | 	meminfo["free"] = -1; | 
					
						
							|  |  |  | 	meminfo["available"] = -1; | 
					
						
							|  |  |  | 	meminfo["stack"] = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	PERFORMANCE_INFORMATION pref_info; | 
					
						
							|  |  |  | 	pref_info.cb = sizeof(pref_info); | 
					
						
							|  |  |  | 	GetPerformanceInfo(&pref_info, sizeof(pref_info)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	typedef void(WINAPI * PGetCurrentThreadStackLimits)(PULONG_PTR, PULONG_PTR); | 
					
						
							|  |  |  | 	PGetCurrentThreadStackLimits GetCurrentThreadStackLimits = (PGetCurrentThreadStackLimits)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetCurrentThreadStackLimits"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ULONG_PTR LowLimit = 0; | 
					
						
							|  |  |  | 	ULONG_PTR HighLimit = 0; | 
					
						
							|  |  |  | 	if (GetCurrentThreadStackLimits) { | 
					
						
							|  |  |  | 		GetCurrentThreadStackLimits(&LowLimit, &HighLimit); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pref_info.PhysicalTotal * pref_info.PageSize != 0) { | 
					
						
							| 
									
										
										
										
											2023-05-07 11:01:20 -03:00
										 |  |  | 		meminfo["physical"] = static_cast<int64_t>(pref_info.PhysicalTotal * pref_info.PageSize); | 
					
						
							| 
									
										
										
										
											2023-04-03 11:46:29 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (pref_info.PhysicalAvailable * pref_info.PageSize != 0) { | 
					
						
							| 
									
										
										
										
											2023-05-07 11:01:20 -03:00
										 |  |  | 		meminfo["free"] = static_cast<int64_t>(pref_info.PhysicalAvailable * pref_info.PageSize); | 
					
						
							| 
									
										
										
										
											2023-04-03 11:46:29 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (pref_info.CommitLimit * pref_info.PageSize != 0) { | 
					
						
							| 
									
										
										
										
											2023-05-07 11:01:20 -03:00
										 |  |  | 		meminfo["available"] = static_cast<int64_t>(pref_info.CommitLimit * pref_info.PageSize); | 
					
						
							| 
									
										
										
										
											2023-04-03 11:46:29 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (HighLimit - LowLimit != 0) { | 
					
						
							| 
									
										
										
										
											2023-05-07 11:01:20 -03:00
										 |  |  | 		meminfo["stack"] = static_cast<int64_t>(HighLimit - LowLimit); | 
					
						
							| 
									
										
										
										
											2023-04-03 11:46:29 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return meminfo; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-16 14:38:01 +03:00
										 |  |  | Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String> &p_arguments, bool p_blocking) { | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | #define CLEAN_PIPES               \
 | 
					
						
							|  |  |  | 	if (pipe_in[0] != 0) {        \ | 
					
						
							|  |  |  | 		CloseHandle(pipe_in[0]);  \ | 
					
						
							|  |  |  | 	}                             \ | 
					
						
							|  |  |  | 	if (pipe_in[1] != 0) {        \ | 
					
						
							|  |  |  | 		CloseHandle(pipe_in[1]);  \ | 
					
						
							|  |  |  | 	}                             \ | 
					
						
							|  |  |  | 	if (pipe_out[0] != 0) {       \ | 
					
						
							|  |  |  | 		CloseHandle(pipe_out[0]); \ | 
					
						
							|  |  |  | 	}                             \ | 
					
						
							|  |  |  | 	if (pipe_out[1] != 0) {       \ | 
					
						
							|  |  |  | 		CloseHandle(pipe_out[1]); \ | 
					
						
							|  |  |  | 	}                             \ | 
					
						
							|  |  |  | 	if (pipe_err[0] != 0) {       \ | 
					
						
							|  |  |  | 		CloseHandle(pipe_err[0]); \ | 
					
						
							|  |  |  | 	}                             \ | 
					
						
							|  |  |  | 	if (pipe_err[1] != 0) {       \ | 
					
						
							|  |  |  | 		CloseHandle(pipe_err[1]); \ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Dictionary ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 	String path = p_path.is_absolute_path() ? fix_path(p_path) : p_path; | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 	String command = _quote_command_line_argument(path); | 
					
						
							|  |  |  | 	for (const String &E : p_arguments) { | 
					
						
							|  |  |  | 		command += " " + _quote_command_line_argument(E); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create pipes.
 | 
					
						
							| 
									
										
										
										
											2024-06-21 11:21:18 -05:00
										 |  |  | 	HANDLE pipe_in[2] = { nullptr, nullptr }; | 
					
						
							|  |  |  | 	HANDLE pipe_out[2] = { nullptr, nullptr }; | 
					
						
							|  |  |  | 	HANDLE pipe_err[2] = { nullptr, nullptr }; | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	SECURITY_ATTRIBUTES sa; | 
					
						
							|  |  |  | 	sa.nLength = sizeof(SECURITY_ATTRIBUTES); | 
					
						
							|  |  |  | 	sa.bInheritHandle = true; | 
					
						
							|  |  |  | 	sa.lpSecurityDescriptor = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(!CreatePipe(&pipe_in[0], &pipe_in[1], &sa, 0), ret); | 
					
						
							|  |  |  | 	if (!CreatePipe(&pipe_out[0], &pipe_out[1], &sa, 0)) { | 
					
						
							|  |  |  | 		CLEAN_PIPES | 
					
						
							|  |  |  | 		ERR_FAIL_V(ret); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!CreatePipe(&pipe_err[0], &pipe_err[1], &sa, 0)) { | 
					
						
							|  |  |  | 		CLEAN_PIPES | 
					
						
							|  |  |  | 		ERR_FAIL_V(ret); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(!SetHandleInformation(pipe_err[0], HANDLE_FLAG_INHERIT, 0), ret); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create process.
 | 
					
						
							|  |  |  | 	ProcessInfo pi; | 
					
						
							|  |  |  | 	ZeroMemory(&pi.si, sizeof(pi.si)); | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 	pi.si.StartupInfo.cb = sizeof(pi.si); | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 	ZeroMemory(&pi.pi, sizeof(pi.pi)); | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 	LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si.StartupInfo; | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 	pi.si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; | 
					
						
							|  |  |  | 	pi.si.StartupInfo.hStdInput = pipe_in[0]; | 
					
						
							|  |  |  | 	pi.si.StartupInfo.hStdOutput = pipe_out[1]; | 
					
						
							|  |  |  | 	pi.si.StartupInfo.hStdError = pipe_err[1]; | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-15 15:49:08 +02:00
										 |  |  | 	SIZE_T attr_list_size = 0; | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 	InitializeProcThreadAttributeList(nullptr, 1, 0, &attr_list_size); | 
					
						
							|  |  |  | 	pi.si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)alloca(attr_list_size); | 
					
						
							|  |  |  | 	if (!InitializeProcThreadAttributeList(pi.si.lpAttributeList, 1, 0, &attr_list_size)) { | 
					
						
							|  |  |  | 		CLEAN_PIPES | 
					
						
							|  |  |  | 		ERR_FAIL_V(ret); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	HANDLE handles_to_inherit[] = { pipe_in[0], pipe_out[1], pipe_err[1] }; | 
					
						
							|  |  |  | 	if (!UpdateProcThreadAttribute( | 
					
						
							|  |  |  | 				pi.si.lpAttributeList, | 
					
						
							|  |  |  | 				0, | 
					
						
							|  |  |  | 				PROC_THREAD_ATTRIBUTE_HANDLE_LIST, | 
					
						
							|  |  |  | 				handles_to_inherit, | 
					
						
							|  |  |  | 				sizeof(handles_to_inherit), | 
					
						
							|  |  |  | 				nullptr, | 
					
						
							|  |  |  | 				nullptr)) { | 
					
						
							|  |  |  | 		CLEAN_PIPES | 
					
						
							|  |  |  | 		DeleteProcThreadAttributeList(pi.si.lpAttributeList); | 
					
						
							|  |  |  | 		ERR_FAIL_V(ret); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	DWORD creation_flags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT; | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 	Char16String current_dir_name; | 
					
						
							|  |  |  | 	size_t str_len = GetCurrentDirectoryW(0, nullptr); | 
					
						
							|  |  |  | 	current_dir_name.resize(str_len + 1); | 
					
						
							|  |  |  | 	GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw()); | 
					
						
							|  |  |  | 	if (current_dir_name.size() >= MAX_PATH) { | 
					
						
							|  |  |  | 		Char16String current_short_dir_name; | 
					
						
							|  |  |  | 		str_len = GetShortPathNameW((LPCWSTR)current_dir_name.ptr(), nullptr, 0); | 
					
						
							|  |  |  | 		current_short_dir_name.resize(str_len); | 
					
						
							|  |  |  | 		GetShortPathNameW((LPCWSTR)current_dir_name.ptr(), (LPWSTR)current_short_dir_name.ptrw(), current_short_dir_name.size()); | 
					
						
							|  |  |  | 		current_dir_name = current_short_dir_name; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, true, creation_flags, nullptr, (LPWSTR)current_dir_name.ptr(), si_w, &pi.pi)) { | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 		CLEAN_PIPES | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 		DeleteProcThreadAttributeList(pi.si.lpAttributeList); | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 		ERR_FAIL_V_MSG(ret, "Could not create child process: " + command); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	CloseHandle(pipe_in[0]); | 
					
						
							|  |  |  | 	CloseHandle(pipe_out[1]); | 
					
						
							|  |  |  | 	CloseHandle(pipe_err[1]); | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 	DeleteProcThreadAttributeList(pi.si.lpAttributeList); | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ProcessID pid = pi.pi.dwProcessId; | 
					
						
							| 
									
										
										
										
											2024-04-07 20:19:46 +02:00
										 |  |  | 	process_map_mutex.lock(); | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 	process_map->insert(pid, pi); | 
					
						
							| 
									
										
										
										
											2024-04-07 20:19:46 +02:00
										 |  |  | 	process_map_mutex.unlock(); | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Ref<FileAccessWindowsPipe> main_pipe; | 
					
						
							|  |  |  | 	main_pipe.instantiate(); | 
					
						
							| 
									
										
										
										
											2024-07-16 14:38:01 +03:00
										 |  |  | 	main_pipe->open_existing(pipe_out[0], pipe_in[1], p_blocking); | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Ref<FileAccessWindowsPipe> err_pipe; | 
					
						
							|  |  |  | 	err_pipe.instantiate(); | 
					
						
							| 
									
										
										
										
											2024-06-21 11:21:18 -05:00
										 |  |  | 	err_pipe->open_existing(pipe_err[0], nullptr, p_blocking); | 
					
						
							| 
									
										
										
										
											2023-10-19 14:35:10 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ret["stdio"] = main_pipe; | 
					
						
							|  |  |  | 	ret["stderr"] = err_pipe; | 
					
						
							|  |  |  | 	ret["pid"] = pid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #undef CLEAN_PIPES
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) { | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 	String path = p_path.is_absolute_path() ? fix_path(p_path) : p_path; | 
					
						
							| 
									
										
										
										
											2020-12-18 18:49:13 +00:00
										 |  |  | 	String command = _quote_command_line_argument(path); | 
					
						
							| 
									
										
										
										
											2021-07-15 23:45:57 -04:00
										 |  |  | 	for (const String &E : p_arguments) { | 
					
						
							|  |  |  | 		command += " " + _quote_command_line_argument(E); | 
					
						
							| 
									
										
										
										
											2020-12-18 18:49:13 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-10-22 11:17:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 	ProcessInfo pi; | 
					
						
							|  |  |  | 	ZeroMemory(&pi.si, sizeof(pi.si)); | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 	pi.si.StartupInfo.cb = sizeof(pi.si); | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 	ZeroMemory(&pi.pi, sizeof(pi.pi)); | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 	LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si.StartupInfo; | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	bool inherit_handles = false; | 
					
						
							|  |  |  | 	HANDLE pipe[2] = { nullptr, nullptr }; | 
					
						
							| 
									
										
										
										
											2020-12-18 18:49:13 +00:00
										 |  |  | 	if (r_pipe) { | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 		// Create pipe for StdOut and StdErr.
 | 
					
						
							|  |  |  | 		SECURITY_ATTRIBUTES sa; | 
					
						
							|  |  |  | 		sa.nLength = sizeof(SECURITY_ATTRIBUTES); | 
					
						
							|  |  |  | 		sa.bInheritHandle = true; | 
					
						
							|  |  |  | 		sa.lpSecurityDescriptor = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ERR_FAIL_COND_V(!CreatePipe(&pipe[0], &pipe[1], &sa, 0), ERR_CANT_FORK); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 		pi.si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; | 
					
						
							|  |  |  | 		pi.si.StartupInfo.hStdOutput = pipe[1]; | 
					
						
							| 
									
										
										
										
											2019-03-01 16:51:53 -06:00
										 |  |  | 		if (read_stderr) { | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 			pi.si.StartupInfo.hStdError = pipe[1]; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-15 15:49:08 +02:00
										 |  |  | 		SIZE_T attr_list_size = 0; | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 		InitializeProcThreadAttributeList(nullptr, 1, 0, &attr_list_size); | 
					
						
							|  |  |  | 		pi.si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)alloca(attr_list_size); | 
					
						
							|  |  |  | 		if (!InitializeProcThreadAttributeList(pi.si.lpAttributeList, 1, 0, &attr_list_size)) { | 
					
						
							|  |  |  | 			CloseHandle(pipe[0]); // Cleanup pipe handles.
 | 
					
						
							|  |  |  | 			CloseHandle(pipe[1]); | 
					
						
							|  |  |  | 			ERR_FAIL_V(ERR_CANT_FORK); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (!UpdateProcThreadAttribute( | 
					
						
							|  |  |  | 					pi.si.lpAttributeList, | 
					
						
							|  |  |  | 					0, | 
					
						
							|  |  |  | 					PROC_THREAD_ATTRIBUTE_HANDLE_LIST, | 
					
						
							|  |  |  | 					&pipe[1], | 
					
						
							|  |  |  | 					sizeof(HANDLE), | 
					
						
							|  |  |  | 					nullptr, | 
					
						
							|  |  |  | 					nullptr)) { | 
					
						
							|  |  |  | 			CloseHandle(pipe[0]); // Cleanup pipe handles.
 | 
					
						
							|  |  |  | 			CloseHandle(pipe[1]); | 
					
						
							|  |  |  | 			DeleteProcThreadAttributeList(pi.si.lpAttributeList); | 
					
						
							|  |  |  | 			ERR_FAIL_V(ERR_CANT_FORK); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 		inherit_handles = true; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-27 03:11:00 +01:00
										 |  |  | 	DWORD creation_flags = NORMAL_PRIORITY_CLASS; | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 	if (inherit_handles) { | 
					
						
							|  |  |  | 		creation_flags |= EXTENDED_STARTUPINFO_PRESENT; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 	if (p_open_console) { | 
					
						
							| 
									
										
										
										
											2022-01-27 03:11:00 +01:00
										 |  |  | 		creation_flags |= CREATE_NEW_CONSOLE; | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2022-01-27 03:11:00 +01:00
										 |  |  | 		creation_flags |= CREATE_NO_WINDOW; | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 	Char16String current_dir_name; | 
					
						
							|  |  |  | 	size_t str_len = GetCurrentDirectoryW(0, nullptr); | 
					
						
							|  |  |  | 	current_dir_name.resize(str_len + 1); | 
					
						
							|  |  |  | 	GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw()); | 
					
						
							|  |  |  | 	if (current_dir_name.size() >= MAX_PATH) { | 
					
						
							|  |  |  | 		Char16String current_short_dir_name; | 
					
						
							|  |  |  | 		str_len = GetShortPathNameW((LPCWSTR)current_dir_name.ptr(), nullptr, 0); | 
					
						
							|  |  |  | 		current_short_dir_name.resize(str_len); | 
					
						
							|  |  |  | 		GetShortPathNameW((LPCWSTR)current_dir_name.ptr(), (LPWSTR)current_short_dir_name.ptrw(), current_short_dir_name.size()); | 
					
						
							|  |  |  | 		current_dir_name = current_short_dir_name; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, inherit_handles, creation_flags, nullptr, (LPWSTR)current_dir_name.ptr(), si_w, &pi.pi); | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 	if (!ret && r_pipe) { | 
					
						
							|  |  |  | 		CloseHandle(pipe[0]); // Cleanup pipe handles.
 | 
					
						
							|  |  |  | 		CloseHandle(pipe[1]); | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 		DeleteProcThreadAttributeList(pi.si.lpAttributeList); | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (r_pipe) { | 
					
						
							|  |  |  | 		CloseHandle(pipe[1]); // Close pipe write handle (only child process is writing).
 | 
					
						
							| 
									
										
										
										
											2022-05-10 18:27:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		LocalVector<char> bytes; | 
					
						
							|  |  |  | 		int bytes_in_buffer = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		const int CHUNK_SIZE = 4096; | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 		DWORD read = 0; | 
					
						
							|  |  |  | 		for (;;) { // Read StdOut and StdErr from pipe.
 | 
					
						
							| 
									
										
										
										
											2022-05-10 18:27:45 +08:00
										 |  |  | 			bytes.resize(bytes_in_buffer + CHUNK_SIZE); | 
					
						
							| 
									
										
										
										
											2024-03-12 09:40:40 -05:00
										 |  |  | 			const bool success = ReadFile(pipe[0], bytes.ptr() + bytes_in_buffer, CHUNK_SIZE, &read, nullptr); | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 			if (!success || read == 0) { | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-05-10 18:27:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// Assume that all possible encodings are ASCII-compatible.
 | 
					
						
							|  |  |  | 			// Break at newline to allow receiving long output in portions.
 | 
					
						
							|  |  |  | 			int newline_index = -1; | 
					
						
							|  |  |  | 			for (int i = read - 1; i >= 0; i--) { | 
					
						
							|  |  |  | 				if (bytes[bytes_in_buffer + i] == '\n') { | 
					
						
							|  |  |  | 					newline_index = i; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-04-07 15:46:52 -03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-05-10 18:27:45 +08:00
										 |  |  | 			if (newline_index == -1) { | 
					
						
							|  |  |  | 				bytes_in_buffer += read; | 
					
						
							|  |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2019-04-07 15:46:52 -03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-05-10 18:27:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			const int bytes_to_convert = bytes_in_buffer + (newline_index + 1); | 
					
						
							|  |  |  | 			_append_to_pipe(bytes.ptr(), bytes_to_convert, r_pipe, p_pipe_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			bytes_in_buffer = read - (newline_index + 1); | 
					
						
							|  |  |  | 			memmove(bytes.ptr(), bytes.ptr() + bytes_to_convert, bytes_in_buffer); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (bytes_in_buffer > 0) { | 
					
						
							|  |  |  | 			_append_to_pipe(bytes.ptr(), bytes_in_buffer, r_pipe, p_pipe_mutex); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-05-10 18:27:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 		CloseHandle(pipe[0]); // Close pipe read handle.
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-27 09:54:49 +02:00
										 |  |  | 	WaitForSingleObject(pi.pi.hProcess, INFINITE); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-18 18:49:13 +00:00
										 |  |  | 	if (r_exitcode) { | 
					
						
							|  |  |  | 		DWORD ret2; | 
					
						
							|  |  |  | 		GetExitCodeProcess(pi.pi.hProcess, &ret2); | 
					
						
							|  |  |  | 		*r_exitcode = ret2; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-18 18:49:13 +00:00
										 |  |  | 	CloseHandle(pi.pi.hProcess); | 
					
						
							|  |  |  | 	CloseHandle(pi.pi.hThread); | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 	if (r_pipe) { | 
					
						
							|  |  |  | 		DeleteProcThreadAttributeList(pi.si.lpAttributeList); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-12-18 18:49:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return OK; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-12-18 18:49:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | Error OS_Windows::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 	String path = p_path.is_absolute_path() ? fix_path(p_path) : p_path; | 
					
						
							| 
									
										
										
										
											2020-12-18 18:49:13 +00:00
										 |  |  | 	String command = _quote_command_line_argument(path); | 
					
						
							| 
									
										
										
										
											2021-07-15 23:45:57 -04:00
										 |  |  | 	for (const String &E : p_arguments) { | 
					
						
							|  |  |  | 		command += " " + _quote_command_line_argument(E); | 
					
						
							| 
									
										
										
										
											2020-05-19 16:34:15 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ProcessInfo pi; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ZeroMemory(&pi.si, sizeof(pi.si)); | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 	pi.si.StartupInfo.cb = sizeof(pi.si.StartupInfo); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ZeroMemory(&pi.pi, sizeof(pi.pi)); | 
					
						
							| 
									
										
										
										
											2024-11-11 18:37:45 +01:00
										 |  |  | 	LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si.StartupInfo; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-27 03:11:00 +01:00
										 |  |  | 	DWORD creation_flags = NORMAL_PRIORITY_CLASS; | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 	if (p_open_console) { | 
					
						
							| 
									
										
										
										
											2022-01-27 03:11:00 +01:00
										 |  |  | 		creation_flags |= CREATE_NEW_CONSOLE; | 
					
						
							| 
									
										
										
										
											2021-12-16 15:00:55 +02:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2022-01-27 03:11:00 +01:00
										 |  |  | 		creation_flags |= CREATE_NO_WINDOW; | 
					
						
							| 
									
										
										
										
											2021-12-14 14:43:13 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-25 21:54:23 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 	Char16String current_dir_name; | 
					
						
							|  |  |  | 	size_t str_len = GetCurrentDirectoryW(0, nullptr); | 
					
						
							|  |  |  | 	current_dir_name.resize(str_len + 1); | 
					
						
							|  |  |  | 	GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw()); | 
					
						
							|  |  |  | 	if (current_dir_name.size() >= MAX_PATH) { | 
					
						
							|  |  |  | 		Char16String current_short_dir_name; | 
					
						
							|  |  |  | 		str_len = GetShortPathNameW((LPCWSTR)current_dir_name.ptr(), nullptr, 0); | 
					
						
							|  |  |  | 		current_short_dir_name.resize(str_len); | 
					
						
							|  |  |  | 		GetShortPathNameW((LPCWSTR)current_dir_name.ptr(), (LPWSTR)current_short_dir_name.ptrw(), current_short_dir_name.size()); | 
					
						
							|  |  |  | 		current_dir_name = current_short_dir_name; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, creation_flags, nullptr, (LPWSTR)current_dir_name.ptr(), si_w, &pi.pi); | 
					
						
							| 
									
										
										
										
											2020-12-18 18:49:13 +00:00
										 |  |  | 	ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-18 18:49:13 +00:00
										 |  |  | 	ProcessID pid = pi.pi.dwProcessId; | 
					
						
							|  |  |  | 	if (r_child_id) { | 
					
						
							|  |  |  | 		*r_child_id = pid; | 
					
						
							| 
									
										
										
										
											2020-05-19 16:34:15 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-04-07 20:19:46 +02:00
										 |  |  | 	process_map_mutex.lock(); | 
					
						
							| 
									
										
										
										
											2020-12-18 18:49:13 +00:00
										 |  |  | 	process_map->insert(pid, pi); | 
					
						
							| 
									
										
										
										
											2024-04-07 20:19:46 +02:00
										 |  |  | 	process_map_mutex.unlock(); | 
					
						
							| 
									
										
										
										
											2020-12-18 18:49:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	return OK; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-27 17:32:43 +02:00
										 |  |  | Error OS_Windows::kill(const ProcessID &p_pid) { | 
					
						
							| 
									
										
										
										
											2023-01-12 14:41:57 +02:00
										 |  |  | 	int ret = 0; | 
					
						
							| 
									
										
										
										
											2024-04-07 20:19:46 +02:00
										 |  |  | 	MutexLock lock(process_map_mutex); | 
					
						
							| 
									
										
										
										
											2023-01-12 14:41:57 +02:00
										 |  |  | 	if (process_map->has(p_pid)) { | 
					
						
							|  |  |  | 		const PROCESS_INFORMATION pi = (*process_map)[p_pid].pi; | 
					
						
							|  |  |  | 		process_map->erase(p_pid); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-12 14:41:57 +02:00
										 |  |  | 		ret = TerminateProcess(pi.hProcess, 0); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-12 14:41:57 +02:00
										 |  |  | 		CloseHandle(pi.hProcess); | 
					
						
							|  |  |  | 		CloseHandle(pi.hThread); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, false, (DWORD)p_pid); | 
					
						
							| 
									
										
										
										
											2024-03-12 09:40:40 -05:00
										 |  |  | 		if (hProcess != nullptr) { | 
					
						
							| 
									
										
										
										
											2023-01-12 14:41:57 +02:00
										 |  |  | 			ret = TerminateProcess(hProcess, 0); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-12 14:41:57 +02:00
										 |  |  | 			CloseHandle(hProcess); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-27 17:32:43 +02:00
										 |  |  | 	return ret != 0 ? OK : FAILED; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-07 17:17:31 +07:00
										 |  |  | int OS_Windows::get_process_id() const { | 
					
						
							| 
									
										
										
										
											2016-04-29 13:57:57 -03:00
										 |  |  | 	return _getpid(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 20:36:23 -07:00
										 |  |  | bool OS_Windows::is_process_running(const ProcessID &p_pid) const { | 
					
						
							| 
									
										
										
										
											2024-04-07 20:19:46 +02:00
										 |  |  | 	MutexLock lock(process_map_mutex); | 
					
						
							| 
									
										
										
										
											2021-08-12 20:36:23 -07:00
										 |  |  | 	if (!process_map->has(p_pid)) { | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-07 20:19:46 +02:00
										 |  |  | 	const ProcessInfo &info = (*process_map)[p_pid]; | 
					
						
							|  |  |  | 	if (!info.is_running) { | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-08-12 20:36:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-07 20:19:46 +02:00
										 |  |  | 	const PROCESS_INFORMATION &pi = info.pi; | 
					
						
							| 
									
										
										
										
											2021-08-12 20:36:23 -07:00
										 |  |  | 	DWORD dw_exit_code = 0; | 
					
						
							|  |  |  | 	if (!GetExitCodeProcess(pi.hProcess, &dw_exit_code)) { | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dw_exit_code != STILL_ACTIVE) { | 
					
						
							| 
									
										
										
										
											2024-04-07 20:19:46 +02:00
										 |  |  | 		info.is_running = false; | 
					
						
							|  |  |  | 		info.exit_code = dw_exit_code; | 
					
						
							| 
									
										
										
										
											2021-08-12 20:36:23 -07:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-07 20:19:46 +02:00
										 |  |  | int OS_Windows::get_process_exit_code(const ProcessID &p_pid) const { | 
					
						
							|  |  |  | 	MutexLock lock(process_map_mutex); | 
					
						
							|  |  |  | 	if (!process_map->has(p_pid)) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const ProcessInfo &info = (*process_map)[p_pid]; | 
					
						
							|  |  |  | 	if (!info.is_running) { | 
					
						
							|  |  |  | 		return info.exit_code; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const PROCESS_INFORMATION &pi = info.pi; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	DWORD dw_exit_code = 0; | 
					
						
							|  |  |  | 	if (!GetExitCodeProcess(pi.hProcess, &dw_exit_code)) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dw_exit_code == STILL_ACTIVE) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	info.is_running = false; | 
					
						
							|  |  |  | 	info.exit_code = dw_exit_code; | 
					
						
							|  |  |  | 	return dw_exit_code; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | Error OS_Windows::set_cwd(const String &p_cwd) { | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (_wchdir((LPCWSTR)(p_cwd.utf16().get_data())) != 0) { | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 		return ERR_CANT_OPEN; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-08 15:38:30 +03:00
										 |  |  | Vector<String> OS_Windows::get_system_fonts() const { | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 	if (!dwrite_init) { | 
					
						
							|  |  |  | 		return Vector<String>(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-08 15:38:30 +03:00
										 |  |  | 	Vector<String> ret; | 
					
						
							|  |  |  | 	HashSet<String> font_names; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	UINT32 family_count = font_collection->GetFontFamilyCount(); | 
					
						
							|  |  |  | 	for (UINT32 i = 0; i < family_count; i++) { | 
					
						
							|  |  |  | 		ComAutoreleaseRef<IDWriteFontFamily> family; | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 		HRESULT hr = font_collection->GetFontFamily(i, &family.reference); | 
					
						
							| 
									
										
										
										
											2022-07-08 15:38:30 +03:00
										 |  |  | 		ERR_CONTINUE(FAILED(hr) || family.is_null()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ComAutoreleaseRef<IDWriteLocalizedStrings> family_names; | 
					
						
							|  |  |  | 		hr = family->GetFamilyNames(&family_names.reference); | 
					
						
							|  |  |  | 		ERR_CONTINUE(FAILED(hr) || family_names.is_null()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		UINT32 index = 0; | 
					
						
							|  |  |  | 		BOOL exists = false; | 
					
						
							|  |  |  | 		UINT32 length = 0; | 
					
						
							|  |  |  | 		Char16String name; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		hr = family_names->FindLocaleName(L"en-us", &index, &exists); | 
					
						
							|  |  |  | 		ERR_CONTINUE(FAILED(hr)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		hr = family_names->GetStringLength(index, &length); | 
					
						
							|  |  |  | 		ERR_CONTINUE(FAILED(hr)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		name.resize(length + 1); | 
					
						
							|  |  |  | 		hr = family_names->GetString(index, (WCHAR *)name.ptrw(), length + 1); | 
					
						
							|  |  |  | 		ERR_CONTINUE(FAILED(hr)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		font_names.insert(String::utf16(name.ptr(), length)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (const String &E : font_names) { | 
					
						
							|  |  |  | 		ret.push_back(E); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | #if defined(__GNUC__) && !defined(__clang__)
 | 
					
						
							|  |  |  | #pragma GCC diagnostic push
 | 
					
						
							|  |  |  | #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FallbackTextAnalysisSource : public IDWriteTextAnalysisSource { | 
					
						
							|  |  |  | 	LONG _cRef = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool rtl = false; | 
					
						
							|  |  |  | 	Char16String string; | 
					
						
							|  |  |  | 	Char16String locale; | 
					
						
							|  |  |  | 	IDWriteNumberSubstitution *n_sub = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2023-01-30 16:59:38 -08:00
										 |  |  | 	HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) override { | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 		if (IID_IUnknown == riid) { | 
					
						
							|  |  |  | 			AddRef(); | 
					
						
							|  |  |  | 			*ppvInterface = (IUnknown *)this; | 
					
						
							|  |  |  | 		} else if (__uuidof(IMMNotificationClient) == riid) { | 
					
						
							|  |  |  | 			AddRef(); | 
					
						
							|  |  |  | 			*ppvInterface = (IMMNotificationClient *)this; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			*ppvInterface = nullptr; | 
					
						
							|  |  |  | 			return E_NOINTERFACE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return S_OK; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-30 16:59:38 -08:00
										 |  |  | 	ULONG STDMETHODCALLTYPE AddRef() override { | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 		return InterlockedIncrement(&_cRef); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-30 16:59:38 -08:00
										 |  |  | 	ULONG STDMETHODCALLTYPE Release() override { | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 		ULONG ulRef = InterlockedDecrement(&_cRef); | 
					
						
							|  |  |  | 		if (0 == ulRef) { | 
					
						
							|  |  |  | 			delete this; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return ulRef; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HRESULT STDMETHODCALLTYPE GetTextAtPosition(UINT32 p_text_position, WCHAR const **r_text_string, UINT32 *r_text_length) override { | 
					
						
							|  |  |  | 		if (p_text_position >= (UINT32)string.length()) { | 
					
						
							|  |  |  | 			*r_text_string = nullptr; | 
					
						
							|  |  |  | 			*r_text_length = 0; | 
					
						
							|  |  |  | 			return S_OK; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		*r_text_string = reinterpret_cast<const wchar_t *>(string.get_data()) + p_text_position; | 
					
						
							|  |  |  | 		*r_text_length = string.length() - p_text_position; | 
					
						
							|  |  |  | 		return S_OK; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HRESULT STDMETHODCALLTYPE GetTextBeforePosition(UINT32 p_text_position, WCHAR const **r_text_string, UINT32 *r_text_length) override { | 
					
						
							|  |  |  | 		if (p_text_position < 1 || p_text_position >= (UINT32)string.length()) { | 
					
						
							|  |  |  | 			*r_text_string = nullptr; | 
					
						
							|  |  |  | 			*r_text_length = 0; | 
					
						
							|  |  |  | 			return S_OK; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		*r_text_string = reinterpret_cast<const wchar_t *>(string.get_data()); | 
					
						
							|  |  |  | 		*r_text_length = p_text_position; | 
					
						
							|  |  |  | 		return S_OK; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	DWRITE_READING_DIRECTION STDMETHODCALLTYPE GetParagraphReadingDirection() override { | 
					
						
							|  |  |  | 		return (rtl) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT : DWRITE_READING_DIRECTION_LEFT_TO_RIGHT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HRESULT STDMETHODCALLTYPE GetLocaleName(UINT32 p_text_position, UINT32 *r_text_length, WCHAR const **r_locale_name) override { | 
					
						
							|  |  |  | 		*r_locale_name = reinterpret_cast<const wchar_t *>(locale.get_data()); | 
					
						
							|  |  |  | 		return S_OK; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HRESULT STDMETHODCALLTYPE GetNumberSubstitution(UINT32 p_text_position, UINT32 *r_text_length, IDWriteNumberSubstitution **r_number_substitution) override { | 
					
						
							|  |  |  | 		*r_number_substitution = n_sub; | 
					
						
							|  |  |  | 		return S_OK; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	FallbackTextAnalysisSource(const Char16String &p_text, const Char16String &p_locale, bool p_rtl, IDWriteNumberSubstitution *p_nsub) { | 
					
						
							|  |  |  | 		_cRef = 1; | 
					
						
							|  |  |  | 		string = p_text; | 
					
						
							|  |  |  | 		locale = p_locale; | 
					
						
							|  |  |  | 		n_sub = p_nsub; | 
					
						
							|  |  |  | 		rtl = p_rtl; | 
					
						
							| 
									
										
										
										
											2024-10-07 10:57:21 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	virtual ~FallbackTextAnalysisSource() {} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(__GNUC__) && !defined(__clang__)
 | 
					
						
							|  |  |  | #pragma GCC diagnostic pop
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String OS_Windows::_get_default_fontname(const String &p_font_name) const { | 
					
						
							| 
									
										
										
										
											2022-07-08 15:38:30 +03:00
										 |  |  | 	String font_name = p_font_name; | 
					
						
							|  |  |  | 	if (font_name.to_lower() == "sans-serif") { | 
					
						
							|  |  |  | 		font_name = "Arial"; | 
					
						
							|  |  |  | 	} else if (font_name.to_lower() == "serif") { | 
					
						
							|  |  |  | 		font_name = "Times New Roman"; | 
					
						
							|  |  |  | 	} else if (font_name.to_lower() == "monospace") { | 
					
						
							|  |  |  | 		font_name = "Courier New"; | 
					
						
							|  |  |  | 	} else if (font_name.to_lower() == "cursive") { | 
					
						
							|  |  |  | 		font_name = "Comic Sans MS"; | 
					
						
							|  |  |  | 	} else if (font_name.to_lower() == "fantasy") { | 
					
						
							|  |  |  | 		font_name = "Gabriola"; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 	return font_name; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DWRITE_FONT_WEIGHT OS_Windows::_weight_to_dw(int p_weight) const { | 
					
						
							|  |  |  | 	if (p_weight < 150) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_WEIGHT_THIN; | 
					
						
							|  |  |  | 	} else if (p_weight < 250) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_WEIGHT_EXTRA_LIGHT; | 
					
						
							|  |  |  | 	} else if (p_weight < 325) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_WEIGHT_LIGHT; | 
					
						
							|  |  |  | 	} else if (p_weight < 375) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_WEIGHT_SEMI_LIGHT; | 
					
						
							|  |  |  | 	} else if (p_weight < 450) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_WEIGHT_NORMAL; | 
					
						
							|  |  |  | 	} else if (p_weight < 550) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_WEIGHT_MEDIUM; | 
					
						
							|  |  |  | 	} else if (p_weight < 650) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_WEIGHT_DEMI_BOLD; | 
					
						
							|  |  |  | 	} else if (p_weight < 750) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_WEIGHT_BOLD; | 
					
						
							|  |  |  | 	} else if (p_weight < 850) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_WEIGHT_EXTRA_BOLD; | 
					
						
							|  |  |  | 	} else if (p_weight < 925) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_WEIGHT_BLACK; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return DWRITE_FONT_WEIGHT_EXTRA_BLACK; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DWRITE_FONT_STRETCH OS_Windows::_stretch_to_dw(int p_stretch) const { | 
					
						
							|  |  |  | 	if (p_stretch < 56) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_STRETCH_ULTRA_CONDENSED; | 
					
						
							|  |  |  | 	} else if (p_stretch < 69) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_STRETCH_EXTRA_CONDENSED; | 
					
						
							|  |  |  | 	} else if (p_stretch < 81) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_STRETCH_CONDENSED; | 
					
						
							|  |  |  | 	} else if (p_stretch < 93) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_STRETCH_SEMI_CONDENSED; | 
					
						
							|  |  |  | 	} else if (p_stretch < 106) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_STRETCH_NORMAL; | 
					
						
							|  |  |  | 	} else if (p_stretch < 137) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_STRETCH_SEMI_EXPANDED; | 
					
						
							|  |  |  | 	} else if (p_stretch < 144) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_STRETCH_EXPANDED; | 
					
						
							|  |  |  | 	} else if (p_stretch < 162) { | 
					
						
							|  |  |  | 		return DWRITE_FONT_STRETCH_EXTRA_EXPANDED; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return DWRITE_FONT_STRETCH_ULTRA_EXPANDED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Vector<String> OS_Windows::get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale, const String &p_script, int p_weight, int p_stretch, bool p_italic) const { | 
					
						
							|  |  |  | 	if (!dwrite2_init) { | 
					
						
							|  |  |  | 		return Vector<String>(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	String font_name = _get_default_fontname(p_font_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool rtl = TS->is_locale_right_to_left(p_locale); | 
					
						
							|  |  |  | 	Char16String text = p_text.utf16(); | 
					
						
							|  |  |  | 	Char16String locale = p_locale.utf16(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ComAutoreleaseRef<IDWriteNumberSubstitution> number_substitution; | 
					
						
							|  |  |  | 	HRESULT hr = dwrite_factory->CreateNumberSubstitution(DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, reinterpret_cast<const wchar_t *>(locale.get_data()), true, &number_substitution.reference); | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(FAILED(hr) || number_substitution.is_null(), Vector<String>()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	FallbackTextAnalysisSource fs = FallbackTextAnalysisSource(text, locale, rtl, number_substitution.reference); | 
					
						
							|  |  |  | 	UINT32 mapped_length = 0; | 
					
						
							|  |  |  | 	FLOAT scale = 0.0; | 
					
						
							|  |  |  | 	ComAutoreleaseRef<IDWriteFont> dwrite_font; | 
					
						
							|  |  |  | 	hr = system_font_fallback->MapCharacters( | 
					
						
							|  |  |  | 			&fs, | 
					
						
							|  |  |  | 			0, | 
					
						
							|  |  |  | 			(UINT32)text.length(), | 
					
						
							|  |  |  | 			font_collection, | 
					
						
							|  |  |  | 			reinterpret_cast<const wchar_t *>(font_name.utf16().get_data()), | 
					
						
							|  |  |  | 			_weight_to_dw(p_weight), | 
					
						
							|  |  |  | 			p_italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, | 
					
						
							|  |  |  | 			_stretch_to_dw(p_stretch), | 
					
						
							|  |  |  | 			&mapped_length, | 
					
						
							|  |  |  | 			&dwrite_font.reference, | 
					
						
							|  |  |  | 			&scale); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (FAILED(hr) || dwrite_font.is_null()) { | 
					
						
							|  |  |  | 		return Vector<String>(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ComAutoreleaseRef<IDWriteFontFace> dwrite_face; | 
					
						
							|  |  |  | 	hr = dwrite_font->CreateFontFace(&dwrite_face.reference); | 
					
						
							|  |  |  | 	if (FAILED(hr) || dwrite_face.is_null()) { | 
					
						
							|  |  |  | 		return Vector<String>(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	UINT32 number_of_files = 0; | 
					
						
							|  |  |  | 	hr = dwrite_face->GetFiles(&number_of_files, nullptr); | 
					
						
							|  |  |  | 	if (FAILED(hr)) { | 
					
						
							|  |  |  | 		return Vector<String>(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	Vector<ComAutoreleaseRef<IDWriteFontFile>> files; | 
					
						
							|  |  |  | 	files.resize(number_of_files); | 
					
						
							|  |  |  | 	hr = dwrite_face->GetFiles(&number_of_files, (IDWriteFontFile **)files.ptrw()); | 
					
						
							|  |  |  | 	if (FAILED(hr)) { | 
					
						
							|  |  |  | 		return Vector<String>(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Vector<String> ret; | 
					
						
							|  |  |  | 	for (UINT32 i = 0; i < number_of_files; i++) { | 
					
						
							|  |  |  | 		void const *reference_key = nullptr; | 
					
						
							|  |  |  | 		UINT32 reference_key_size = 0; | 
					
						
							|  |  |  | 		ComAutoreleaseRef<IDWriteLocalFontFileLoader> loader; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		hr = files.write[i]->GetLoader((IDWriteFontFileLoader **)&loader.reference); | 
					
						
							|  |  |  | 		if (FAILED(hr) || loader.is_null()) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		hr = files.write[i]->GetReferenceKey(&reference_key, &reference_key_size); | 
					
						
							|  |  |  | 		if (FAILED(hr)) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 		WCHAR file_path[32767]; | 
					
						
							|  |  |  | 		hr = loader->GetFilePathFromKey(reference_key, reference_key_size, &file_path[0], 32767); | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 		if (FAILED(hr)) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-12-27 23:19:43 +07:00
										 |  |  | 		String fpath = String::utf16((const char16_t *)&file_path[0]).replace("\\", "/"); | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		WIN32_FIND_DATAW d; | 
					
						
							|  |  |  | 		HANDLE fnd = FindFirstFileW((LPCWSTR)&file_path[0], &d); | 
					
						
							|  |  |  | 		if (fnd != INVALID_HANDLE_VALUE) { | 
					
						
							|  |  |  | 			String fname = String::utf16((const char16_t *)d.cFileName); | 
					
						
							|  |  |  | 			if (!fname.is_empty()) { | 
					
						
							|  |  |  | 				fpath = fpath.get_base_dir().path_join(fname); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			FindClose(fnd); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ret.push_back(fpath); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-07-08 15:38:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | String OS_Windows::get_system_font_path(const String &p_font_name, int p_weight, int p_stretch, bool p_italic) const { | 
					
						
							|  |  |  | 	if (!dwrite_init) { | 
					
						
							|  |  |  | 		return String(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-07-08 15:38:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 	String font_name = _get_default_fontname(p_font_name); | 
					
						
							| 
									
										
										
										
											2022-07-08 15:38:30 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	UINT32 index = 0; | 
					
						
							|  |  |  | 	BOOL exists = false; | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 	HRESULT hr = font_collection->FindFamilyName((const WCHAR *)font_name.utf16().get_data(), &index, &exists); | 
					
						
							| 
									
										
										
										
											2022-12-12 14:08:55 +01:00
										 |  |  | 	if (FAILED(hr) || !exists) { | 
					
						
							| 
									
										
										
										
											2022-07-08 15:38:30 +03:00
										 |  |  | 		return String(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ComAutoreleaseRef<IDWriteFontFamily> family; | 
					
						
							|  |  |  | 	hr = font_collection->GetFontFamily(index, &family.reference); | 
					
						
							|  |  |  | 	if (FAILED(hr) || family.is_null()) { | 
					
						
							|  |  |  | 		return String(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ComAutoreleaseRef<IDWriteFont> dwrite_font; | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 	hr = family->GetFirstMatchingFont(_weight_to_dw(p_weight), _stretch_to_dw(p_stretch), p_italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, &dwrite_font.reference); | 
					
						
							| 
									
										
										
										
											2022-07-08 15:38:30 +03:00
										 |  |  | 	if (FAILED(hr) || dwrite_font.is_null()) { | 
					
						
							|  |  |  | 		return String(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ComAutoreleaseRef<IDWriteFontFace> dwrite_face; | 
					
						
							|  |  |  | 	hr = dwrite_font->CreateFontFace(&dwrite_face.reference); | 
					
						
							|  |  |  | 	if (FAILED(hr) || dwrite_face.is_null()) { | 
					
						
							|  |  |  | 		return String(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	UINT32 number_of_files = 0; | 
					
						
							|  |  |  | 	hr = dwrite_face->GetFiles(&number_of_files, nullptr); | 
					
						
							|  |  |  | 	if (FAILED(hr)) { | 
					
						
							|  |  |  | 		return String(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	Vector<ComAutoreleaseRef<IDWriteFontFile>> files; | 
					
						
							|  |  |  | 	files.resize(number_of_files); | 
					
						
							|  |  |  | 	hr = dwrite_face->GetFiles(&number_of_files, (IDWriteFontFile **)files.ptrw()); | 
					
						
							|  |  |  | 	if (FAILED(hr)) { | 
					
						
							|  |  |  | 		return String(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (UINT32 i = 0; i < number_of_files; i++) { | 
					
						
							|  |  |  | 		void const *reference_key = nullptr; | 
					
						
							|  |  |  | 		UINT32 reference_key_size = 0; | 
					
						
							|  |  |  | 		ComAutoreleaseRef<IDWriteLocalFontFileLoader> loader; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		hr = files.write[i]->GetLoader((IDWriteFontFileLoader **)&loader.reference); | 
					
						
							|  |  |  | 		if (FAILED(hr) || loader.is_null()) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		hr = files.write[i]->GetReferenceKey(&reference_key, &reference_key_size); | 
					
						
							|  |  |  | 		if (FAILED(hr)) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 		WCHAR file_path[32767]; | 
					
						
							|  |  |  | 		hr = loader->GetFilePathFromKey(reference_key, reference_key_size, &file_path[0], 32767); | 
					
						
							| 
									
										
										
										
											2022-07-08 15:38:30 +03:00
										 |  |  | 		if (FAILED(hr)) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-12-27 23:19:43 +07:00
										 |  |  | 		String fpath = String::utf16((const char16_t *)&file_path[0]).replace("\\", "/"); | 
					
						
							| 
									
										
										
										
											2022-11-17 09:39:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		WIN32_FIND_DATAW d; | 
					
						
							|  |  |  | 		HANDLE fnd = FindFirstFileW((LPCWSTR)&file_path[0], &d); | 
					
						
							|  |  |  | 		if (fnd != INVALID_HANDLE_VALUE) { | 
					
						
							|  |  |  | 			String fname = String::utf16((const char16_t *)d.cFileName); | 
					
						
							|  |  |  | 			if (!fname.is_empty()) { | 
					
						
							|  |  |  | 				fpath = fpath.get_base_dir().path_join(fname); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			FindClose(fnd); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return fpath; | 
					
						
							| 
									
										
										
										
											2022-07-08 15:38:30 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return String(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-15 02:01:39 -03:00
										 |  |  | String OS_Windows::get_executable_path() const { | 
					
						
							| 
									
										
										
										
											2020-07-27 13:43:20 +03:00
										 |  |  | 	WCHAR bufname[4096]; | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	GetModuleFileNameW(nullptr, bufname, 4096); | 
					
						
							| 
									
										
										
										
											2020-10-22 11:17:21 +01:00
										 |  |  | 	String s = String::utf16((const char16_t *)bufname).replace("\\", "/"); | 
					
						
							| 
									
										
										
										
											2014-02-15 02:01:39 -03:00
										 |  |  | 	return s; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | bool OS_Windows::has_environment(const String &p_var) const { | 
					
						
							| 
									
										
										
										
											2024-09-03 16:02:35 +03:00
										 |  |  | 	return GetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), nullptr, 0) > 0; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | String OS_Windows::get_environment(const String &p_var) const { | 
					
						
							| 
									
										
										
										
											2020-07-27 13:43:20 +03:00
										 |  |  | 	WCHAR wval[0x7fff]; // MSDN says 32767 char is the maximum
 | 
					
						
							|  |  |  | 	int wlen = GetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), wval, 0x7fff); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	if (wlen > 0) { | 
					
						
							| 
									
										
										
										
											2020-07-27 13:43:20 +03:00
										 |  |  | 		return String::utf16((const char16_t *)wval); | 
					
						
							| 
									
										
										
										
											2015-05-04 13:12:05 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-13 18:03:28 -03:00
										 |  |  | 	return ""; | 
					
						
							| 
									
										
										
										
											2015-05-04 13:12:05 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-16 14:26:14 +01:00
										 |  |  | void OS_Windows::set_environment(const String &p_var, const String &p_value) const { | 
					
						
							|  |  |  | 	ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var)); | 
					
						
							|  |  |  | 	Char16String var = p_var.utf16(); | 
					
						
							|  |  |  | 	Char16String value = p_value.utf16(); | 
					
						
							|  |  |  | 	ERR_FAIL_COND_MSG(var.length() + value.length() + 2 > 32767, vformat("Invalid definition for environment variable '%s', cannot exceed 32767 characters.", p_var)); | 
					
						
							|  |  |  | 	SetEnvironmentVariableW((LPCWSTR)(var.get_data()), (LPCWSTR)(value.get_data())); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void OS_Windows::unset_environment(const String &p_var) const { | 
					
						
							|  |  |  | 	ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var)); | 
					
						
							|  |  |  | 	SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), nullptr); // Null to delete.
 | 
					
						
							| 
									
										
										
										
											2019-01-29 22:59:38 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-26 10:34:35 +03:00
										 |  |  | String OS_Windows::get_stdin_string(int64_t p_buffer_size) { | 
					
						
							|  |  |  | 	if (get_stdin_type() == STD_HANDLE_INVALID) { | 
					
						
							|  |  |  | 		return String(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Vector<uint8_t> data; | 
					
						
							|  |  |  | 	data.resize(p_buffer_size); | 
					
						
							| 
									
										
										
										
											2022-12-29 21:06:11 +01:00
										 |  |  | 	DWORD count = 0; | 
					
						
							| 
									
										
										
										
											2024-04-26 10:34:35 +03:00
										 |  |  | 	if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), data.ptrw(), data.size(), &count, nullptr)) { | 
					
						
							|  |  |  | 		return String::utf8((const char *)data.ptr(), count); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return String(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-26 10:34:35 +03:00
										 |  |  | PackedByteArray OS_Windows::get_stdin_buffer(int64_t p_buffer_size) { | 
					
						
							|  |  |  | 	Vector<uint8_t> data; | 
					
						
							|  |  |  | 	data.resize(p_buffer_size); | 
					
						
							|  |  |  | 	DWORD count = 0; | 
					
						
							|  |  |  | 	if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), data.ptrw(), data.size(), &count, nullptr)) { | 
					
						
							|  |  |  | 		return data; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return PackedByteArray(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | OS_Windows::StdHandleType OS_Windows::get_stdin_type() const { | 
					
						
							|  |  |  | 	HANDLE h = GetStdHandle(STD_INPUT_HANDLE); | 
					
						
							|  |  |  | 	if (h == 0 || h == INVALID_HANDLE_VALUE) { | 
					
						
							|  |  |  | 		return STD_HANDLE_INVALID; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	DWORD ftype = GetFileType(h); | 
					
						
							|  |  |  | 	if (ftype == FILE_TYPE_UNKNOWN && GetLastError() != ERROR_SUCCESS) { | 
					
						
							|  |  |  | 		return STD_HANDLE_UNKNOWN; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ftype &= ~(FILE_TYPE_REMOTE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ftype == FILE_TYPE_DISK) { | 
					
						
							|  |  |  | 		return STD_HANDLE_FILE; | 
					
						
							|  |  |  | 	} else if (ftype == FILE_TYPE_PIPE) { | 
					
						
							|  |  |  | 		return STD_HANDLE_PIPE; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		DWORD conmode = 0; | 
					
						
							|  |  |  | 		BOOL res = GetConsoleMode(h, &conmode); | 
					
						
							|  |  |  | 		if (!res && (GetLastError() == ERROR_INVALID_HANDLE)) { | 
					
						
							|  |  |  | 			return STD_HANDLE_UNKNOWN; // Unknown character device.
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | #ifndef WINDOWS_SUBSYSTEM_CONSOLE
 | 
					
						
							|  |  |  | 			if (!is_using_con_wrapper()) { | 
					
						
							|  |  |  | 				return STD_HANDLE_INVALID; // Window app can't read stdin input without werapper.
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 			return STD_HANDLE_CONSOLE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | OS_Windows::StdHandleType OS_Windows::get_stdout_type() const { | 
					
						
							|  |  |  | 	HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); | 
					
						
							|  |  |  | 	if (h == 0 || h == INVALID_HANDLE_VALUE) { | 
					
						
							|  |  |  | 		return STD_HANDLE_INVALID; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	DWORD ftype = GetFileType(h); | 
					
						
							|  |  |  | 	if (ftype == FILE_TYPE_UNKNOWN && GetLastError() != ERROR_SUCCESS) { | 
					
						
							|  |  |  | 		return STD_HANDLE_UNKNOWN; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ftype &= ~(FILE_TYPE_REMOTE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ftype == FILE_TYPE_DISK) { | 
					
						
							|  |  |  | 		return STD_HANDLE_FILE; | 
					
						
							|  |  |  | 	} else if (ftype == FILE_TYPE_PIPE) { | 
					
						
							|  |  |  | 		return STD_HANDLE_PIPE; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		DWORD conmode = 0; | 
					
						
							|  |  |  | 		BOOL res = GetConsoleMode(h, &conmode); | 
					
						
							|  |  |  | 		if (!res && (GetLastError() == ERROR_INVALID_HANDLE)) { | 
					
						
							|  |  |  | 			return STD_HANDLE_UNKNOWN; // Unknown character device.
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return STD_HANDLE_CONSOLE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | OS_Windows::StdHandleType OS_Windows::get_stderr_type() const { | 
					
						
							|  |  |  | 	HANDLE h = GetStdHandle(STD_ERROR_HANDLE); | 
					
						
							|  |  |  | 	if (h == 0 || h == INVALID_HANDLE_VALUE) { | 
					
						
							|  |  |  | 		return STD_HANDLE_INVALID; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	DWORD ftype = GetFileType(h); | 
					
						
							|  |  |  | 	if (ftype == FILE_TYPE_UNKNOWN && GetLastError() != ERROR_SUCCESS) { | 
					
						
							|  |  |  | 		return STD_HANDLE_UNKNOWN; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ftype &= ~(FILE_TYPE_REMOTE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ftype == FILE_TYPE_DISK) { | 
					
						
							|  |  |  | 		return STD_HANDLE_FILE; | 
					
						
							|  |  |  | 	} else if (ftype == FILE_TYPE_PIPE) { | 
					
						
							|  |  |  | 		return STD_HANDLE_PIPE; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		DWORD conmode = 0; | 
					
						
							|  |  |  | 		BOOL res = GetConsoleMode(h, &conmode); | 
					
						
							|  |  |  | 		if (!res && (GetLastError() == ERROR_INVALID_HANDLE)) { | 
					
						
							|  |  |  | 			return STD_HANDLE_UNKNOWN; // Unknown character device.
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return STD_HANDLE_CONSOLE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-08 22:36:19 -03:00
										 |  |  | Error OS_Windows::shell_open(const String &p_uri) { | 
					
						
							| 
									
										
										
										
											2021-09-19 11:29:56 +01:00
										 |  |  | 	INT_PTR ret = (INT_PTR)ShellExecuteW(nullptr, nullptr, (LPCWSTR)(p_uri.utf16().get_data()), nullptr, nullptr, SW_SHOWNORMAL); | 
					
						
							|  |  |  | 	if (ret > 32) { | 
					
						
							|  |  |  | 		return OK; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		switch (ret) { | 
					
						
							|  |  |  | 			case ERROR_FILE_NOT_FOUND: | 
					
						
							|  |  |  | 			case SE_ERR_DLLNOTFOUND: | 
					
						
							|  |  |  | 				return ERR_FILE_NOT_FOUND; | 
					
						
							|  |  |  | 			case ERROR_PATH_NOT_FOUND: | 
					
						
							|  |  |  | 				return ERR_FILE_BAD_PATH; | 
					
						
							|  |  |  | 			case ERROR_BAD_FORMAT: | 
					
						
							|  |  |  | 				return ERR_FILE_CORRUPT; | 
					
						
							|  |  |  | 			case SE_ERR_ACCESSDENIED: | 
					
						
							|  |  |  | 				return ERR_UNAUTHORIZED; | 
					
						
							|  |  |  | 			case 0: | 
					
						
							|  |  |  | 			case SE_ERR_OOM: | 
					
						
							|  |  |  | 				return ERR_OUT_OF_MEMORY; | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				return FAILED; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-04-18 11:43:54 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-07 11:33:35 +08:00
										 |  |  | Error OS_Windows::shell_show_in_file_manager(String p_path, bool p_open_folder) { | 
					
						
							|  |  |  | 	bool open_folder = false; | 
					
						
							|  |  |  | 	if (DirAccess::dir_exists_absolute(p_path) && p_open_folder) { | 
					
						
							|  |  |  | 		open_folder = true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-02 22:25:17 +02:00
										 |  |  | 	if (!p_path.is_quoted()) { | 
					
						
							|  |  |  | 		p_path = p_path.quote(); | 
					
						
							| 
									
										
										
										
											2022-12-07 11:33:35 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 	p_path = fix_path(p_path); | 
					
						
							| 
									
										
										
										
											2022-12-07 11:33:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	INT_PTR ret = OK; | 
					
						
							|  |  |  | 	if (open_folder) { | 
					
						
							|  |  |  | 		ret = (INT_PTR)ShellExecuteW(nullptr, nullptr, L"explorer.exe", LPCWSTR(p_path.utf16().get_data()), nullptr, SW_SHOWNORMAL); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ret = (INT_PTR)ShellExecuteW(nullptr, nullptr, L"explorer.exe", LPCWSTR((String("/select,") + p_path).utf16().get_data()), nullptr, SW_SHOWNORMAL); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ret > 32) { | 
					
						
							|  |  |  | 		return OK; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		switch (ret) { | 
					
						
							|  |  |  | 			case ERROR_FILE_NOT_FOUND: | 
					
						
							|  |  |  | 			case SE_ERR_DLLNOTFOUND: | 
					
						
							|  |  |  | 				return ERR_FILE_NOT_FOUND; | 
					
						
							|  |  |  | 			case ERROR_PATH_NOT_FOUND: | 
					
						
							|  |  |  | 				return ERR_FILE_BAD_PATH; | 
					
						
							|  |  |  | 			case ERROR_BAD_FORMAT: | 
					
						
							|  |  |  | 				return ERR_FILE_CORRUPT; | 
					
						
							|  |  |  | 			case SE_ERR_ACCESSDENIED: | 
					
						
							|  |  |  | 				return ERR_UNAUTHORIZED; | 
					
						
							|  |  |  | 			case 0: | 
					
						
							|  |  |  | 			case SE_ERR_OOM: | 
					
						
							|  |  |  | 				return ERR_OUT_OF_MEMORY; | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				return FAILED; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | String OS_Windows::get_locale() const { | 
					
						
							|  |  |  | 	const _WinLocale *wl = &_win_locales[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	LANGID langid = GetUserDefaultUILanguage(); | 
					
						
							|  |  |  | 	String neutral; | 
					
						
							| 
									
										
										
										
											2020-07-25 23:42:11 +03:00
										 |  |  | 	int lang = PRIMARYLANGID(langid); | 
					
						
							|  |  |  | 	int sublang = SUBLANGID(langid); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	while (wl->locale) { | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 		if (wl->main_lang == lang && wl->sublang == SUBLANG_NEUTRAL) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			neutral = wl->locale; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 		if (lang == wl->main_lang && sublang == wl->sublang) { | 
					
						
							| 
									
										
										
										
											2020-07-25 23:42:11 +03:00
										 |  |  | 			return String(wl->locale).replace("-", "_"); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		wl++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (!neutral.is_empty()) { | 
					
						
							| 
									
										
										
										
											2020-07-25 23:42:11 +03:00
										 |  |  | 		return String(neutral).replace("-", "_"); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return "en"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-11 22:08:35 +02:00
										 |  |  | String OS_Windows::get_model_name() const { | 
					
						
							|  |  |  | 	HKEY hkey; | 
					
						
							|  |  |  | 	if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Hardware\\Description\\System\\BIOS", 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) { | 
					
						
							|  |  |  | 		return OS::get_model_name(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	String sys_name; | 
					
						
							|  |  |  | 	String board_name; | 
					
						
							|  |  |  | 	WCHAR buffer[256]; | 
					
						
							|  |  |  | 	DWORD buffer_len = 256; | 
					
						
							|  |  |  | 	DWORD vtype = REG_SZ; | 
					
						
							|  |  |  | 	if (RegQueryValueExW(hkey, L"SystemProductName", nullptr, &vtype, (LPBYTE)buffer, &buffer_len) == ERROR_SUCCESS && buffer_len != 0) { | 
					
						
							|  |  |  | 		sys_name = String::utf16((const char16_t *)buffer, buffer_len).strip_edges(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	buffer_len = 256; | 
					
						
							|  |  |  | 	if (RegQueryValueExW(hkey, L"BaseBoardProduct", nullptr, &vtype, (LPBYTE)buffer, &buffer_len) == ERROR_SUCCESS && buffer_len != 0) { | 
					
						
							|  |  |  | 		board_name = String::utf16((const char16_t *)buffer, buffer_len).strip_edges(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	RegCloseKey(hkey); | 
					
						
							|  |  |  | 	if (!sys_name.is_empty() && sys_name.to_lower() != "system product name") { | 
					
						
							|  |  |  | 		return sys_name; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!board_name.is_empty() && board_name.to_lower() != "base board product") { | 
					
						
							|  |  |  | 		return board_name; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return OS::get_model_name(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-27 01:50:21 +01:00
										 |  |  | String OS_Windows::get_processor_name() const { | 
					
						
							|  |  |  | 	const String id = "Hardware\\Description\\System\\CentralProcessor\\0"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HKEY hkey; | 
					
						
							|  |  |  | 	if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, (LPCWSTR)(id.utf16().get_data()), 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) { | 
					
						
							|  |  |  | 		ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name. Returning an empty string.")); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	WCHAR buffer[256]; | 
					
						
							|  |  |  | 	DWORD buffer_len = 256; | 
					
						
							|  |  |  | 	DWORD vtype = REG_SZ; | 
					
						
							| 
									
										
										
										
											2024-03-12 09:40:40 -05:00
										 |  |  | 	if (RegQueryValueExW(hkey, L"ProcessorNameString", nullptr, &vtype, (LPBYTE)buffer, &buffer_len) == ERROR_SUCCESS) { | 
					
						
							| 
									
										
										
										
											2020-12-27 01:50:21 +01:00
										 |  |  | 		RegCloseKey(hkey); | 
					
						
							|  |  |  | 		return String::utf16((const char16_t *)buffer, buffer_len).strip_edges(); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		RegCloseKey(hkey); | 
					
						
							|  |  |  | 		ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name. Returning an empty string.")); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | void OS_Windows::run() { | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (!main_loop) { | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 09:50:29 +00:00
										 |  |  | 	main_loop->initialize(); | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-16 20:29:55 +02:00
										 |  |  | 	while (true) { | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | 		DisplayServer::get_singleton()->process_events(); // get rid of pending events
 | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 		if (Main::iteration()) { | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 09:50:29 +00:00
										 |  |  | 	main_loop->finalize(); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MainLoop *OS_Windows::get_main_loop() const { | 
					
						
							|  |  |  | 	return main_loop; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-20 11:28:54 +02:00
										 |  |  | uint64_t OS_Windows::get_embedded_pck_offset() const { | 
					
						
							|  |  |  | 	Ref<FileAccess> f = FileAccess::open(get_executable_path(), FileAccess::READ); | 
					
						
							|  |  |  | 	if (f.is_null()) { | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Process header.
 | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		f->seek(0x3c); | 
					
						
							|  |  |  | 		uint32_t pe_pos = f->get_32(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		f->seek(pe_pos); | 
					
						
							|  |  |  | 		uint32_t magic = f->get_32(); | 
					
						
							|  |  |  | 		if (magic != 0x00004550) { | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int num_sections; | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		int64_t header_pos = f->get_position(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		f->seek(header_pos + 2); | 
					
						
							|  |  |  | 		num_sections = f->get_16(); | 
					
						
							|  |  |  | 		f->seek(header_pos + 16); | 
					
						
							|  |  |  | 		uint16_t opt_header_size = f->get_16(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Skip rest of header + optional header to go to the section headers.
 | 
					
						
							|  |  |  | 		f->seek(f->get_position() + 2 + opt_header_size); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	int64_t section_table_pos = f->get_position(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Search for the "pck" section.
 | 
					
						
							|  |  |  | 	int64_t off = 0; | 
					
						
							|  |  |  | 	for (int i = 0; i < num_sections; ++i) { | 
					
						
							|  |  |  | 		int64_t section_header_pos = section_table_pos + i * 40; | 
					
						
							|  |  |  | 		f->seek(section_header_pos); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		uint8_t section_name[9]; | 
					
						
							|  |  |  | 		f->get_buffer(section_name, 8); | 
					
						
							|  |  |  | 		section_name[8] = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (strcmp((char *)section_name, "pck") == 0) { | 
					
						
							|  |  |  | 			f->seek(section_header_pos + 20); | 
					
						
							|  |  |  | 			off = f->get_32(); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return off; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
  ~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
  ~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
  ~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
											
										 
											2017-11-17 17:11:41 +01:00
										 |  |  | String OS_Windows::get_config_path() const { | 
					
						
							| 
									
										
										
										
											2021-05-21 12:48:12 +02:00
										 |  |  | 	if (has_environment("APPDATA")) { | 
					
						
							| 
									
										
										
										
											2021-07-03 23:41:17 +03:00
										 |  |  | 		return get_environment("APPDATA").replace("\\", "/"); | 
					
						
							| 
									
										
											  
											
												Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
  ~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
  ~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
  ~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
											
										 
											2017-11-17 17:11:41 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-05-21 12:48:12 +02:00
										 |  |  | 	return "."; | 
					
						
							| 
									
										
											  
											
												Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
  ~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
  ~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
  ~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
											
										 
											2017-11-17 17:11:41 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String OS_Windows::get_data_path() const { | 
					
						
							| 
									
										
										
										
											2021-05-21 12:48:12 +02:00
										 |  |  | 	return get_config_path(); | 
					
						
							| 
									
										
											  
											
												Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
  ~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
  ~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
  ~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
											
										 
											2017-11-17 17:11:41 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String OS_Windows::get_cache_path() const { | 
					
						
							| 
									
										
										
										
											2021-02-22 22:54:12 +01:00
										 |  |  | 	static String cache_path_cache; | 
					
						
							|  |  |  | 	if (cache_path_cache.is_empty()) { | 
					
						
							| 
									
										
										
										
											2022-10-07 19:00:24 +02:00
										 |  |  | 		if (has_environment("LOCALAPPDATA")) { | 
					
						
							| 
									
										
										
										
											2021-02-22 22:54:12 +01:00
										 |  |  | 			cache_path_cache = get_environment("LOCALAPPDATA").replace("\\", "/"); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (cache_path_cache.is_empty() && has_environment("TEMP")) { | 
					
						
							|  |  |  | 			cache_path_cache = get_environment("TEMP").replace("\\", "/"); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (cache_path_cache.is_empty()) { | 
					
						
							|  |  |  | 			cache_path_cache = get_config_path(); | 
					
						
							| 
									
										
										
										
											2021-05-07 19:02:35 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-05-21 12:48:12 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-02-22 22:54:12 +01:00
										 |  |  | 	return cache_path_cache; | 
					
						
							| 
									
										
											  
											
												Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
  ~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
  ~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
  ~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
											
										 
											2017-11-17 17:11:41 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Get properly capitalized engine name for system paths
 | 
					
						
							|  |  |  | String OS_Windows::get_godot_dir_name() const { | 
					
						
							| 
									
										
										
										
											2017-11-19 21:18:01 +01:00
										 |  |  | 	return String(VERSION_SHORT_NAME).capitalize(); | 
					
						
							| 
									
										
											  
											
												Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
  ~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
  ~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
  ~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
											
										 
											2017-11-17 17:11:41 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 18:39:31 -07:00
										 |  |  | String OS_Windows::get_system_dir(SystemDir p_dir, bool p_shared_storage) const { | 
					
						
							| 
									
										
										
										
											2019-04-18 02:43:33 +00:00
										 |  |  | 	KNOWNFOLDERID id; | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	switch (p_dir) { | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | 		case SYSTEM_DIR_DESKTOP: { | 
					
						
							| 
									
										
										
										
											2019-04-18 02:43:33 +00:00
										 |  |  | 			id = FOLDERID_Desktop; | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case SYSTEM_DIR_DCIM: { | 
					
						
							| 
									
										
										
										
											2019-04-18 02:43:33 +00:00
										 |  |  | 			id = FOLDERID_Pictures; | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case SYSTEM_DIR_DOCUMENTS: { | 
					
						
							| 
									
										
										
										
											2019-04-18 02:43:33 +00:00
										 |  |  | 			id = FOLDERID_Documents; | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case SYSTEM_DIR_DOWNLOADS: { | 
					
						
							| 
									
										
										
										
											2019-04-18 02:43:33 +00:00
										 |  |  | 			id = FOLDERID_Downloads; | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case SYSTEM_DIR_MOVIES: { | 
					
						
							| 
									
										
										
										
											2019-04-18 02:43:33 +00:00
										 |  |  | 			id = FOLDERID_Videos; | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case SYSTEM_DIR_MUSIC: { | 
					
						
							| 
									
										
										
										
											2019-04-18 02:43:33 +00:00
										 |  |  | 			id = FOLDERID_Music; | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case SYSTEM_DIR_PICTURES: { | 
					
						
							| 
									
										
										
										
											2019-04-18 02:43:33 +00:00
										 |  |  | 			id = FOLDERID_Pictures; | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case SYSTEM_DIR_RINGTONES: { | 
					
						
							| 
									
										
										
										
											2019-04-18 02:43:33 +00:00
										 |  |  | 			id = FOLDERID_Music; | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-18 02:43:33 +00:00
										 |  |  | 	PWSTR szPath; | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	HRESULT res = SHGetKnownFolderPath(id, 0, nullptr, &szPath); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ERR_FAIL_COND_V(res != S_OK, String()); | 
					
						
							| 
									
										
										
										
											2021-07-03 23:41:17 +03:00
										 |  |  | 	String path = String::utf16((const char16_t *)szPath).replace("\\", "/"); | 
					
						
							| 
									
										
										
										
											2019-04-18 02:43:33 +00:00
										 |  |  | 	CoTaskMemFree(szPath); | 
					
						
							|  |  |  | 	return path; | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
											  
											
												Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
  ~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
  ~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
  ~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
											
										 
											2017-11-17 17:11:41 +01:00
										 |  |  | String OS_Windows::get_user_data_dir() const { | 
					
						
							| 
									
										
										
										
											2022-10-18 16:43:37 +02:00
										 |  |  | 	String appname = get_safe_dir_name(GLOBAL_GET("application/config/name")); | 
					
						
							| 
									
										
										
										
											2021-12-09 03:42:46 -06:00
										 |  |  | 	if (!appname.is_empty()) { | 
					
						
							| 
									
										
										
										
											2022-10-18 16:43:37 +02:00
										 |  |  | 		bool use_custom_dir = GLOBAL_GET("application/config/use_custom_user_dir"); | 
					
						
							| 
									
										
										
										
											2017-11-26 19:00:53 +01:00
										 |  |  | 		if (use_custom_dir) { | 
					
						
							| 
									
										
										
										
											2022-10-18 16:43:37 +02:00
										 |  |  | 			String custom_dir = get_safe_dir_name(GLOBAL_GET("application/config/custom_user_dir_name"), true); | 
					
						
							| 
									
										
										
										
											2021-12-09 03:42:46 -06:00
										 |  |  | 			if (custom_dir.is_empty()) { | 
					
						
							| 
									
										
										
										
											2017-11-26 19:00:53 +01:00
										 |  |  | 				custom_dir = appname; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-08-29 19:34:01 -05:00
										 |  |  | 			return get_data_path().path_join(custom_dir).replace("\\", "/"); | 
					
						
							| 
									
										
											  
											
												Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
  ~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
  ~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
  ~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
											
										 
											2017-11-17 17:11:41 +01:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2022-08-29 19:34:01 -05:00
										 |  |  | 			return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join(appname).replace("\\", "/"); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-29 19:34:01 -05:00
										 |  |  | 	return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join("[unnamed project]"); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-20 21:40:52 +08:00
										 |  |  | String OS_Windows::get_unique_id() const { | 
					
						
							| 
									
										
										
										
											2022-05-21 18:41:45 +02:00
										 |  |  | 	HW_PROFILE_INFOA HwProfInfo; | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(!GetCurrentHwProfileA(&HwProfInfo), ""); | 
					
						
							|  |  |  | 	return String((HwProfInfo.szHwProfileGuid), HW_PROFILE_GUIDLEN); | 
					
						
							| 
									
										
										
										
											2018-01-20 21:40:52 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-19 17:00:46 -03:00
										 |  |  | bool OS_Windows::_check_internal_feature_support(const String &p_feature) { | 
					
						
							| 
									
										
										
										
											2022-10-31 19:12:18 +02:00
										 |  |  | 	if (p_feature == "system_fonts") { | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 		return dwrite_init; | 
					
						
							| 
									
										
										
										
											2022-10-31 19:12:18 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (p_feature == "pc") { | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return false; | 
					
						
							| 
									
										
										
										
											2017-02-08 18:07:35 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-06-05 19:14:33 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | void OS_Windows::disable_crash_handler() { | 
					
						
							|  |  |  | 	crash_handler.disable(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool OS_Windows::is_disable_crash_handler() const { | 
					
						
							|  |  |  | 	return crash_handler.is_disabled(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 10:15:11 -03:00
										 |  |  | Error OS_Windows::move_to_trash(const String &p_path) { | 
					
						
							| 
									
										
										
										
											2018-08-14 11:49:16 +03:00
										 |  |  | 	SHFILEOPSTRUCTW sf; | 
					
						
							| 
									
										
										
										
											2020-07-27 13:43:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Char16String utf16 = p_path.utf16(); | 
					
						
							|  |  |  | 	WCHAR *from = new WCHAR[utf16.length() + 2]; | 
					
						
							|  |  |  | 	wcscpy_s(from, utf16.length() + 1, (LPCWSTR)(utf16.get_data())); | 
					
						
							|  |  |  | 	from[utf16.length() + 1] = 0; | 
					
						
							| 
									
										
										
										
											2018-08-18 01:30:22 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | 	sf.hwnd = main_window; | 
					
						
							| 
									
										
										
										
											2017-09-25 10:15:11 -03:00
										 |  |  | 	sf.wFunc = FO_DELETE; | 
					
						
							| 
									
										
										
										
											2018-08-18 01:30:22 +03:00
										 |  |  | 	sf.pFrom = from; | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	sf.pTo = nullptr; | 
					
						
							| 
									
										
										
										
											2017-09-25 10:15:11 -03:00
										 |  |  | 	sf.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION; | 
					
						
							|  |  |  | 	sf.fAnyOperationsAborted = FALSE; | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	sf.hNameMappings = nullptr; | 
					
						
							|  |  |  | 	sf.lpszProgressTitle = nullptr; | 
					
						
							| 
									
										
										
										
											2017-09-25 10:15:11 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 11:49:16 +03:00
										 |  |  | 	int ret = SHFileOperationW(&sf); | 
					
						
							| 
									
										
										
										
											2018-08-18 01:30:22 +03:00
										 |  |  | 	delete[] from; | 
					
						
							| 
									
										
										
										
											2017-09-25 10:15:11 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							| 
									
										
										
										
											2019-11-06 17:03:04 +01:00
										 |  |  | 		ERR_PRINT("SHFileOperation error: " + itos(ret)); | 
					
						
							| 
									
										
										
										
											2017-09-25 10:15:11 -03:00
										 |  |  | 		return FAILED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-13 21:17:55 +02:00
										 |  |  | String OS_Windows::get_system_ca_certificates() { | 
					
						
							|  |  |  | 	HCERTSTORE cert_store = CertOpenSystemStoreA(0, "ROOT"); | 
					
						
							| 
									
										
										
										
											2023-09-09 17:46:44 +02:00
										 |  |  | 	ERR_FAIL_NULL_V_MSG(cert_store, "", "Failed to read the root certificate store."); | 
					
						
							| 
									
										
										
										
											2023-04-13 21:17:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-14 14:38:46 +02:00
										 |  |  | 	FILETIME curr_time; | 
					
						
							|  |  |  | 	GetSystemTimeAsFileTime(&curr_time); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-13 21:17:55 +02:00
										 |  |  | 	String certs; | 
					
						
							|  |  |  | 	PCCERT_CONTEXT curr = CertEnumCertificatesInStore(cert_store, nullptr); | 
					
						
							|  |  |  | 	while (curr) { | 
					
						
							| 
									
										
										
										
											2023-05-14 14:38:46 +02:00
										 |  |  | 		FILETIME ft; | 
					
						
							|  |  |  | 		DWORD size = sizeof(ft); | 
					
						
							|  |  |  | 		// Check if the certificate is disallowed.
 | 
					
						
							|  |  |  | 		if (CertGetCertificateContextProperty(curr, CERT_DISALLOWED_FILETIME_PROP_ID, &ft, &size) && CompareFileTime(&curr_time, &ft) != -1) { | 
					
						
							|  |  |  | 			curr = CertEnumCertificatesInStore(cert_store, curr); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Encode and add to certificate list.
 | 
					
						
							| 
									
										
										
										
											2023-04-13 21:17:55 +02:00
										 |  |  | 		bool success = CryptBinaryToStringA(curr->pbCertEncoded, curr->cbCertEncoded, CRYPT_STRING_BASE64HEADER | CRYPT_STRING_NOCR, nullptr, &size); | 
					
						
							|  |  |  | 		ERR_CONTINUE(!success); | 
					
						
							|  |  |  | 		PackedByteArray pba; | 
					
						
							|  |  |  | 		pba.resize(size); | 
					
						
							|  |  |  | 		CryptBinaryToStringA(curr->pbCertEncoded, curr->cbCertEncoded, CRYPT_STRING_BASE64HEADER | CRYPT_STRING_NOCR, (char *)pba.ptrw(), &size); | 
					
						
							|  |  |  | 		certs += String((char *)pba.ptr(), size); | 
					
						
							|  |  |  | 		curr = CertEnumCertificatesInStore(cert_store, curr); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	CertCloseStore(cert_store, 0); | 
					
						
							|  |  |  | 	return certs; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | OS_Windows::OS_Windows(HINSTANCE _hInstance) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	hInstance = _hInstance; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-13 14:14:32 +03:00
										 |  |  | 	// Reset CWD to ensure long path is used.
 | 
					
						
							|  |  |  | 	Char16String current_dir_name; | 
					
						
							|  |  |  | 	size_t str_len = GetCurrentDirectoryW(0, nullptr); | 
					
						
							|  |  |  | 	current_dir_name.resize(str_len + 1); | 
					
						
							|  |  |  | 	GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Char16String new_current_dir_name; | 
					
						
							|  |  |  | 	str_len = GetLongPathNameW((LPCWSTR)current_dir_name.get_data(), nullptr, 0); | 
					
						
							|  |  |  | 	new_current_dir_name.resize(str_len + 1); | 
					
						
							|  |  |  | 	GetLongPathNameW((LPCWSTR)current_dir_name.get_data(), (LPWSTR)new_current_dir_name.ptrw(), new_current_dir_name.size()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	SetCurrentDirectoryW((LPCWSTR)new_current_dir_name.get_data()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-25 12:56:07 +03:00
										 |  |  | #ifndef WINDOWS_SUBSYSTEM_CONSOLE
 | 
					
						
							|  |  |  | 	RedirectIOToConsole(); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	SetConsoleOutputCP(CP_UTF8); | 
					
						
							|  |  |  | 	SetConsoleCP(CP_UTF8); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-20 12:14:16 +03:00
										 |  |  | 	CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); | 
					
						
							| 
									
										
										
										
											2023-04-10 10:38:25 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-27 14:01:34 -03:00
										 |  |  | #ifdef WASAPI_ENABLED
 | 
					
						
							|  |  |  | 	AudioDriverManager::add_driver(&driver_wasapi); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-10-17 13:40:45 -02:00
										 |  |  | #ifdef XAUDIO2_ENABLED
 | 
					
						
							| 
									
										
										
										
											2017-01-16 19:19:45 +01:00
										 |  |  | 	AudioDriverManager::add_driver(&driver_xaudio2); | 
					
						
							| 
									
										
										
										
											2016-10-17 13:40:45 -02:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2017-09-22 12:56:02 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 12:56:48 -03:00
										 |  |  | 	DisplayServerWindows::register_windows_driver(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-05 12:50:20 +01:00
										 |  |  | 	// Enable ANSI escape code support on Windows 10 v1607 (Anniversary Update) and later.
 | 
					
						
							|  |  |  | 	// This lets the engine and projects use ANSI escape codes to color text just like on macOS and Linux.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: The engine does not use ANSI escape codes to color error/warning messages; it uses Windows API calls instead.
 | 
					
						
							|  |  |  | 	// Therefore, error/warning messages are still colored on Windows versions older than 10.
 | 
					
						
							| 
									
										
										
										
											2022-10-11 10:09:36 +02:00
										 |  |  | 	HANDLE stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); | 
					
						
							| 
									
										
										
										
											2024-07-28 00:29:52 +08:00
										 |  |  | 	DWORD outMode = 0; | 
					
						
							|  |  |  | 	GetConsoleMode(stdoutHandle, &outMode); | 
					
						
							|  |  |  | 	outMode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING; | 
					
						
							| 
									
										
										
										
											2020-12-05 12:50:20 +01:00
										 |  |  | 	if (!SetConsoleMode(stdoutHandle, outMode)) { | 
					
						
							|  |  |  | 		// Windows 8.1 or below, or Windows 10 prior to Anniversary Update.
 | 
					
						
							|  |  |  | 		print_verbose("Can't set the ENABLE_VIRTUAL_TERMINAL_PROCESSING Windows console mode. `print_rich()` will not work as expected."); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-21 16:35:01 +07:00
										 |  |  | 	Vector<Logger *> loggers; | 
					
						
							|  |  |  | 	loggers.push_back(memnew(WindowsTerminalLogger)); | 
					
						
							|  |  |  | 	_set_logger(memnew(CompositeLogger(loggers))); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | OS_Windows::~OS_Windows() { | 
					
						
							| 
									
										
										
										
											2023-04-10 10:38:25 +03:00
										 |  |  | 	CoUninitialize(); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } |