From dccbb178065f05810a0fad57a86bca2f10995ecf Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 19 May 2025 16:11:21 +0100 Subject: [PATCH 1/5] Set minimum supported Windows version to 1903 (May 2019 Update) This version is the minimum required to support the UTF-8 code page (CP_UTF8). --- doc/release-notes-empty-template.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/release-notes-empty-template.md b/doc/release-notes-empty-template.md index 7f419cbf420..86dafb36ef9 100644 --- a/doc/release-notes-empty-template.md +++ b/doc/release-notes-empty-template.md @@ -35,8 +35,8 @@ wallet versions of Bitcoin Core are generally supported. Compatibility ============== -Bitcoin Core is supported and tested on operating systems using the -Linux Kernel 3.17+, macOS 14+, and Windows 10+. Bitcoin +Bitcoin Core is supported and tested on the following operating systems or newer: +Linux Kernel 3.17, macOS 14, and Windows 10 (version 1903). Bitcoin Core should also work on most other Unix-like systems but is not as frequently tested on them. It is not recommended to use Bitcoin Core on unsupported systems. From f366408492f6205ee20fe23e5104813de45dd4b1 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 22 Sep 2025 12:13:48 +0100 Subject: [PATCH 2/5] cmake: Set process code page to UTF-8 on Windows Additionally, this change adds app manifests to targets that were previously missing them. --- cmake/windows-app.manifest.in | 7 ++++++- src/CMakeLists.txt | 1 + src/bench/CMakeLists.txt | 2 ++ src/bitcoin.cpp | 3 +++ src/common/system.cpp | 2 ++ src/qt/test/CMakeLists.txt | 2 ++ src/test/fuzz/CMakeLists.txt | 3 +++ 7 files changed, 19 insertions(+), 1 deletion(-) diff --git a/cmake/windows-app.manifest.in b/cmake/windows-app.manifest.in index c3bd333a227..e0dc2eb8271 100644 --- a/cmake/windows-app.manifest.in +++ b/cmake/windows-app.manifest.in @@ -1,10 +1,15 @@ - + + + + UTF-8 + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f9934bb5906..fdf8799df8c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -410,6 +410,7 @@ if(BUILD_UTIL_CHAINSTATE) add_executable(bitcoin-chainstate bitcoin-chainstate.cpp ) + add_windows_application_manifest(bitcoin-chainstate) # TODO: The `SKIP_BUILD_RPATH` property setting can be deleted # in the future after reordering Guix script commands to # perform binary checks after the installation step. diff --git a/src/bench/CMakeLists.txt b/src/bench/CMakeLists.txt index 0bf469c79cd..e0e03b1df7c 100644 --- a/src/bench/CMakeLists.txt +++ b/src/bench/CMakeLists.txt @@ -56,6 +56,8 @@ add_executable(bench_bitcoin verify_script.cpp ) +add_windows_application_manifest(bench_bitcoin) + include(TargetDataSources) target_raw_data_sources(bench_bitcoin NAMESPACE benchmark::data data/block413567.raw diff --git a/src/bitcoin.cpp b/src/bitcoin.cpp index c1a5fce33af..5d2b145bb2e 100644 --- a/src/bitcoin.cpp +++ b/src/bitcoin.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -61,6 +62,8 @@ static void ExecCommand(const std::vector& args, std::string_view a int main(int argc, char* argv[]) { + SetupEnvironment(); + try { CommandLine cmd{ParseCommandLine(argc, argv)}; if (cmd.show_version) { diff --git a/src/common/system.cpp b/src/common/system.cpp index 35a6f4415bc..3833763341a 100644 --- a/src/common/system.cpp +++ b/src/common/system.cpp @@ -12,6 +12,7 @@ #include #ifdef WIN32 +#include #include #include #include @@ -83,6 +84,7 @@ void SetupEnvironment() setenv("LC_ALL", "C.UTF-8", 1); } #elif defined(WIN32) + assert(GetACP() == CP_UTF8); // Set the default input/output charset is utf-8 SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); diff --git a/src/qt/test/CMakeLists.txt b/src/qt/test/CMakeLists.txt index 8fe4ea68e26..af28271356b 100644 --- a/src/qt/test/CMakeLists.txt +++ b/src/qt/test/CMakeLists.txt @@ -14,6 +14,8 @@ add_executable(test_bitcoin-qt ../../init/bitcoin-qt.cpp ) +add_windows_application_manifest(test_bitcoin-qt) + target_link_libraries(test_bitcoin-qt core_interface bitcoinqt diff --git a/src/test/fuzz/CMakeLists.txt b/src/test/fuzz/CMakeLists.txt index 4d649a737f3..d32d72d8640 100644 --- a/src/test/fuzz/CMakeLists.txt +++ b/src/test/fuzz/CMakeLists.txt @@ -134,6 +134,9 @@ add_executable(fuzz vecdeque.cpp versionbits.cpp ) + +add_windows_application_manifest(fuzz) + target_link_libraries(fuzz core_interface fuzzer_interface From 06d0be4e22cef08fd7517f42ee82a44475c6363b Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 16 May 2025 12:24:16 +0100 Subject: [PATCH 3/5] Remove no longer necessary `WinCmdLineArgs` class This change removes one use case of `std::wstring_convert`, which is deprecated in C++17 and removed in C++26. Other uses remain for now. --- src/bitcoin-cli.cpp | 4 ---- src/bitcoin-wallet.cpp | 4 ---- src/bitcoind.cpp | 5 ----- src/common/args.cpp | 29 ----------------------------- src/common/args.h | 17 ----------------- src/qt/bitcoin.cpp | 5 ----- 6 files changed, 64 deletions(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 56f2a906b5f..279aa89e88e 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -1328,10 +1328,6 @@ static int CommandLineRPC(int argc, char *argv[]) MAIN_FUNCTION { -#ifdef WIN32 - common::WinCmdLineArgs winArgs; - std::tie(argc, argv) = winArgs.get(); -#endif SetupEnvironment(); if (!SetupNetworking()) { tfm::format(std::cerr, "Error: Initializing networking failed\n"); diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index c8715231ea2..6811f8c5ea1 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -94,10 +94,6 @@ static std::optional WalletAppInit(ArgsManager& args, int argc, char* argv[ MAIN_FUNCTION { ArgsManager& args = gArgs; -#ifdef WIN32 - common::WinCmdLineArgs winArgs; - std::tie(argc, argv) = winArgs.get(); -#endif int exit_status; std::unique_ptr init = interfaces::MakeWalletInit(argc, argv, exit_status); diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index a4373dafdf2..37cacb2a7e5 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -259,11 +259,6 @@ static bool AppInit(NodeContext& node) MAIN_FUNCTION { -#ifdef WIN32 - common::WinCmdLineArgs winArgs; - std::tie(argc, argv) = winArgs.get(); -#endif - NodeContext node; int exit_status; std::unique_ptr init = interfaces::MakeNodeInit(node, argc, argv, exit_status); diff --git a/src/common/args.cpp b/src/common/args.cpp index d44cd4319b6..50b990291ff 100644 --- a/src/common/args.cpp +++ b/src/common/args.cpp @@ -19,8 +19,6 @@ #include #ifdef WIN32 -#include -#include #include #endif @@ -879,30 +877,3 @@ void ArgsManager::LogArgs() const } logArgsPrefix("Command-line arg:", "", m_settings.command_line_options); } - -namespace common { -#ifdef WIN32 -WinCmdLineArgs::WinCmdLineArgs() -{ - wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); - std::wstring_convert, wchar_t> utf8_cvt; - argv = new char*[argc]; - args.resize(argc); - for (int i = 0; i < argc; i++) { - args[i] = utf8_cvt.to_bytes(wargv[i]); - argv[i] = &*args[i].begin(); - } - LocalFree(wargv); -} - -WinCmdLineArgs::~WinCmdLineArgs() -{ - delete[] argv; -} - -std::pair WinCmdLineArgs::get() -{ - return std::make_pair(argc, argv); -} -#endif -} // namespace common diff --git a/src/common/args.h b/src/common/args.h index d907ad7663d..1b9233ec75c 100644 --- a/src/common/args.h +++ b/src/common/args.h @@ -480,21 +480,4 @@ std::string HelpMessageGroup(const std::string& message); */ std::string HelpMessageOpt(const std::string& option, const std::string& message); -namespace common { -#ifdef WIN32 -class WinCmdLineArgs -{ -public: - WinCmdLineArgs(); - ~WinCmdLineArgs(); - std::pair get(); - -private: - int argc; - char** argv; - std::vector args; -}; -#endif -} // namespace common - #endif // BITCOIN_COMMON_ARGS_H diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index fe552a574a2..59e74f92636 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -478,11 +478,6 @@ static void SetupUIArgs(ArgsManager& argsman) int GuiMain(int argc, char* argv[]) { -#ifdef WIN32 - common::WinCmdLineArgs winArgs; - std::tie(argc, argv) = winArgs.get(); -#endif - std::unique_ptr init = interfaces::MakeGuiInit(argc, argv); SetupEnvironment(); From dbe770d9210666a366f055d52b9f34fa8a3d7305 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 18 May 2025 14:39:10 +0100 Subject: [PATCH 4/5] Switch to ANSI Windows API in `Win32ErrorString()` function --- src/util/syserror.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/util/syserror.cpp b/src/util/syserror.cpp index a902826f8ec..4b456db8d07 100644 --- a/src/util/syserror.cpp +++ b/src/util/syserror.cpp @@ -12,8 +12,6 @@ #if defined(WIN32) #include -#include -#include #endif std::string SysErrorString(int err) @@ -41,16 +39,13 @@ std::string SysErrorString(int err) #if defined(WIN32) std::string Win32ErrorString(int err) { - wchar_t buf[256]; + char buf[256]; buf[0] = 0; - if(FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, + if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - buf, ARRAYSIZE(buf), nullptr)) - { - return strprintf("%s (%d)", std::wstring_convert,wchar_t>().to_bytes(buf), err); - } - else - { + buf, ARRAYSIZE(buf), nullptr)) { + return strprintf("%s (%d)", buf, err); + } else { return strprintf("Unknown error (%d)", err); } } From 53e4951a5b5b9d166d278db4240513d09b447f58 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 16 May 2025 12:25:40 +0100 Subject: [PATCH 5/5] Switch to ANSI Windows API in `fsbridge::fopen()` function --- src/util/fs.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/util/fs.cpp b/src/util/fs.cpp index ec4d551e788..692f6718425 100644 --- a/src/util/fs.cpp +++ b/src/util/fs.cpp @@ -12,7 +12,6 @@ #include #include #else -#include #include #include #endif @@ -28,8 +27,7 @@ FILE *fopen(const fs::path& p, const char *mode) #ifndef WIN32 return ::fopen(p.c_str(), mode); #else - std::wstring_convert,wchar_t> utf8_cvt; - return ::_wfopen(p.wstring().c_str(), utf8_cvt.from_bytes(mode).c_str()); + return ::fopen(p.utf8string().c_str(), mode); #endif }