diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -22,6 +22,7 @@ #include #include +#include const std::function G_TRANSLATION_FUN = nullptr; @@ -605,6 +606,10 @@ } int main(int argc, char *argv[]) { +#ifdef WIN32 + util::WinCmdLineArgs winArgs; + std::tie(argc, argv) = winArgs.get(); +#endif SetupEnvironment(); if (!SetupNetworking()) { fprintf(stderr, "Error: Initializing networking failed\n"); diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -216,6 +216,10 @@ } int main(int argc, char *argv[]) { +#ifdef WIN32 + util::WinCmdLineArgs winArgs; + std::tie(argc, argv) = winArgs.get(); +#endif SetupEnvironment(); // Connect bitcoind signal handlers diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -627,6 +627,10 @@ } int main(int argc, char *argv[]) { +#ifdef WIN32 + util::WinCmdLineArgs winArgs; + std::tie(argc, argv) = winArgs.get(); +#endif SetupEnvironment(); std::unique_ptr node = interfaces::MakeNode(); diff --git a/src/util/system.h b/src/util/system.h --- a/src/util/system.h +++ b/src/util/system.h @@ -31,6 +31,7 @@ #include #include #include +#include #include // Application startup time (used for uptime calculation) @@ -354,6 +355,20 @@ dst.insert(src.begin(), src.end()); } +#ifdef WIN32 +class WinCmdLineArgs { +public: + WinCmdLineArgs(); + ~WinCmdLineArgs(); + std::pair get(); + +private: + int argc; + char **argv; + std::vector args; +}; +#endif + } // namespace util /** diff --git a/src/util/system.cpp b/src/util/system.cpp --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -74,6 +74,7 @@ #include #include /* for _commit */ +#include #include #endif @@ -1293,6 +1294,10 @@ } catch (const std::runtime_error &) { setenv("LC_ALL", "C", 1); } +#elif defined(WIN32) + // Set the default input/output charset is utf-8 + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); #endif // The path locale is lazy initialized and to avoid deinitialization errors // in multithreading environments, it is set explicitly by the main thread. @@ -1349,3 +1354,27 @@ return 1; #endif } + +namespace util { +#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 util diff --git a/test/functional/feature_uacomment.py b/test/functional/feature_uacomment.py --- a/test/functional/feature_uacomment.py +++ b/test/functional/feature_uacomment.py @@ -32,7 +32,7 @@ ["-uacomment=" + 'a' * 256], expected, match=ErrorMatch.FULL_REGEX) self.log.info("test -uacomment unsafe characters") - for unsafe_char in ['/', ':', '(', ')']: + for unsafe_char in ['/', ':', '(', ')', '₿', '🏃']: expected = r"Error: User Agent comment \(" + re.escape( unsafe_char) + r"\) contains unsafe characters." self.nodes[0].assert_start_raises_init_error(