From 16d2ef1ea9bc35e0a30806e1406a9aa6be9d409f Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 21 Sep 2020 11:23:06 +0200 Subject: [PATCH 1/2] DolphinQt: Handle non-ASCII characters in Windows cmd arguments CommandLineParse expects UTF-8 strings. (QApplication, on the other hand, seems to be designed so that you can pass in the char** argv untouched on Windows and get proper Unicode handling.) --- Source/Core/Common/StringUtil.cpp | 20 ++++++++++++++++++++ Source/Core/Common/StringUtil.h | 4 ++++ Source/Core/DolphinQt/Main.cpp | 16 +++++++++++++++- Source/Core/WinUpdater/Main.cpp | 20 -------------------- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/Source/Core/Common/StringUtil.cpp b/Source/Core/Common/StringUtil.cpp index bbc281460c..5ef8b01d24 100644 --- a/Source/Core/Common/StringUtil.cpp +++ b/Source/Core/Common/StringUtil.cpp @@ -31,6 +31,7 @@ #ifdef _WIN32 #include +#include constexpr u32 CODEPAGE_SHIFT_JIS = 932; constexpr u32 CODEPAGE_WINDOWS_1252 = 1252; #else @@ -630,3 +631,22 @@ std::string PathToString(const std::filesystem::path& path) #endif } #endif + +#ifdef _WIN32 +std::vector CommandLineToUtf8Argv(const wchar_t* command_line) +{ + int nargs; + LPWSTR* tokenized = CommandLineToArgvW(command_line, &nargs); + if (!tokenized) + return {}; + + std::vector argv(nargs); + for (size_t i = 0; i < nargs; ++i) + { + argv[i] = WStringToUTF8(tokenized[i]); + } + + LocalFree(tokenized); + return argv; +} +#endif diff --git a/Source/Core/Common/StringUtil.h b/Source/Core/Common/StringUtil.h index 0539667383..615127d191 100644 --- a/Source/Core/Common/StringUtil.h +++ b/Source/Core/Common/StringUtil.h @@ -236,3 +236,7 @@ inline bool IsPrintableCharacter(char c) { return std::isprint(c, std::locale::classic()); } + +#ifdef _WIN32 +std::vector CommandLineToUtf8Argv(const wchar_t* command_line); +#endif diff --git a/Source/Core/DolphinQt/Main.cpp b/Source/Core/DolphinQt/Main.cpp index 8d22beb845..3420a0a886 100644 --- a/Source/Core/DolphinQt/Main.cpp +++ b/Source/Core/DolphinQt/Main.cpp @@ -3,6 +3,9 @@ // Refer to the license.txt file included. #ifdef _WIN32 +#include +#include + #include #include #endif @@ -101,6 +104,12 @@ static bool QtMsgAlertHandler(const char* caption, const char* text, bool yes_no int main(int argc, char* argv[]) { #ifdef _WIN32 + std::vector utf8_args = CommandLineToUtf8Argv(GetCommandLineW()); + const int utf8_argc = static_cast(utf8_args.size()); + std::vector utf8_argv(utf8_args.size()); + for (size_t i = 0; i < utf8_args.size(); ++i) + utf8_argv[i] = utf8_args[i].data(); + const bool console_attached = AttachConsole(ATTACH_PARENT_PROCESS) != FALSE; HANDLE stdout_handle = ::GetStdHandle(STD_OUTPUT_HANDLE); if (console_attached && stdout_handle) @@ -123,7 +132,12 @@ int main(int argc, char* argv[]) #endif auto parser = CommandLineParse::CreateParser(CommandLineParse::ParserOptions::IncludeGUIOptions); - const optparse::Values& options = CommandLineParse::ParseArguments(parser.get(), argc, argv); + const optparse::Values& options = +#ifdef _WIN32 + CommandLineParse::ParseArguments(parser.get(), utf8_argc, utf8_argv.data()); +#else + CommandLineParse::ParseArguments(parser.get(), argc, argv); +#endif const std::vector args = parser->args(); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); diff --git a/Source/Core/WinUpdater/Main.cpp b/Source/Core/WinUpdater/Main.cpp index 6afb807941..567486f00a 100644 --- a/Source/Core/WinUpdater/Main.cpp +++ b/Source/Core/WinUpdater/Main.cpp @@ -16,26 +16,6 @@ #include "UpdaterCommon/UI.h" #include "UpdaterCommon/UpdaterCommon.h" -namespace -{ -std::vector CommandLineToUtf8Argv(PCWSTR command_line) -{ - int nargs; - LPWSTR* tokenized = CommandLineToArgvW(command_line, &nargs); - if (!tokenized) - return {}; - - std::vector argv(nargs); - for (int i = 0; i < nargs; ++i) - { - argv[i] = WStringToUTF8(tokenized[i]); - } - - LocalFree(tokenized); - return argv; -} -}; // namespace - int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { if (lstrlenW(pCmdLine) == 0) From 17e02838b0c885992c7148c2cd017c326b5b6d99 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 21 Sep 2020 17:25:47 +0200 Subject: [PATCH 2/2] DolphinQt: Stop using qtmain --- Source/Core/DolphinQt/Main.cpp | 11 ++++++++--- Source/VSProps/QtCompile.props | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Source/Core/DolphinQt/Main.cpp b/Source/Core/DolphinQt/Main.cpp index 3420a0a886..945912dea7 100644 --- a/Source/Core/DolphinQt/Main.cpp +++ b/Source/Core/DolphinQt/Main.cpp @@ -99,11 +99,12 @@ static bool QtMsgAlertHandler(const char* caption, const char* text, bool yes_no return false; } -// N.B. On Windows, this should be called from WinMain. Link against qtmain and specify -// /SubSystem:Windows +#ifndef _WIN32 int main(int argc, char* argv[]) { -#ifdef _WIN32 +#else +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) +{ std::vector utf8_args = CommandLineToUtf8Argv(GetCommandLineW()); const int utf8_argc = static_cast(utf8_args.size()); std::vector utf8_argv(utf8_args.size()); @@ -146,7 +147,11 @@ int main(int argc, char* argv[]) QCoreApplication::setOrganizationDomain(QStringLiteral("dolphin-emu.org")); QCoreApplication::setApplicationName(QStringLiteral("dolphin-emu")); +#ifdef _WIN32 + QApplication app(__argc, __argv); +#else QApplication app(argc, argv); +#endif #ifdef _WIN32 // On Windows, Qt 5's default system font (MS Shell Dlg 2) is outdated. diff --git a/Source/VSProps/QtCompile.props b/Source/VSProps/QtCompile.props index 107f176795..0ad24e61ad 100644 --- a/Source/VSProps/QtCompile.props +++ b/Source/VSProps/QtCompile.props @@ -35,7 +35,7 @@ $(QtLibDir);%(AdditionalLibraryDirectories) - qtmain$(QtLibSuffix).lib;Qt5Core$(QtLibSuffix).lib;Qt5Gui$(QtLibSuffix).lib;Qt5Widgets$(QtLibSuffix).lib;%(AdditionalDependencies) + Qt5Core$(QtLibSuffix).lib;Qt5Gui$(QtLibSuffix).lib;Qt5Widgets$(QtLibSuffix).lib;%(AdditionalDependencies) Windows