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 static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; static const int DEFAULT_HTTP_CLIENT_TIMEOUT = 900; @@ -603,6 +604,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 @@ -214,6 +214,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 @@ -626,6 +626,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 @@ -32,6 +32,7 @@ #include #include #include +#include #include // Application startup time (used for uptime calculation) @@ -363,6 +364,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 @@ -1295,6 +1296,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. @@ -1351,3 +1356,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,11 +32,11 @@ ["-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( - ["-uacomment=" + unsafe_char], expected, match=ErrorMatch.FULL_REGEX) + ["-uacomment={}".format(unsafe_char)], expected, match=ErrorMatch.FULL_REGEX) if __name__ == '__main__':