diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 09507fd2492d6..f46650511426e 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -511,6 +512,10 @@ static int CommandLineRPC(int argc, char *argv[]) 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 index bf04d95b50016..18fcd9bc2a970 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -185,6 +185,10 @@ static bool AppInit(int argc, char* argv[]) 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 index 1e950e2686a5f..61a9f390e92bd 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -552,6 +552,10 @@ static void SetupUIArgs() #ifndef BITCOIN_QT_TEST 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.cpp b/src/util.cpp index fa624aee908e8..1002302904764 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -61,6 +61,7 @@ #include #include /* for _commit */ +#include #include #endif @@ -1200,6 +1201,10 @@ void SetupEnvironment() } 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. @@ -1265,3 +1270,30 @@ int ScheduleBatchPriority() 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/src/util.h b/src/util.h index f119385e48d4d..fa6d2cd4891c0 100644 --- a/src/util.h +++ b/src/util.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include // for boost::thread_interrupted @@ -361,6 +362,21 @@ inline void insert(std::set& dst, const Tsrc& src) { 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 #endif // BITCOIN_UTIL_H diff --git a/test/functional/feature_uacomment.py b/test/functional/feature_uacomment.py index 691a39b82584e..fb4ad213596cd 100755 --- a/test/functional/feature_uacomment.py +++ b/test/functional/feature_uacomment.py @@ -31,7 +31,7 @@ def run_test(self): self.nodes[0].assert_start_raises_init_error(["-uacomment=" + 'a' * 256], expected, match=ErrorMatch.FULL_REGEX) self.log.info("test -uacomment unsafe characters") - for unsafe_char in ['/', ':', '(', ')']: + for unsafe_char in ['/', ':', '(', ')', '₿', '🏃']: expected = "Error: User Agent comment \(" + re.escape(unsafe_char) + "\) contains unsafe characters." self.nodes[0].assert_start_raises_init_error(["-uacomment=" + unsafe_char], expected, match=ErrorMatch.FULL_REGEX)