From 9b121e5579538477a1fc7c8250e5d7e875a58de8 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 30 Apr 2014 08:46:16 +0200 Subject: Windows: Use WinAPI CommandLineToArgvW() to create argv from command line. Split the Windows CE/Desktop Windows code paths in winmain. Use CommandLineToArgvW() to obtain argv[] for Desktop Windows. [ChangeLog][QtCore][Windows] Command line parsing on Windows now uses the WinAPI function CommandLineToArgvW() to exactly match the quoting of the command interpreter. Task-number: QTBUG-35432 Task-number: QTBUG-23687 Change-Id: I6743e73649d953497642f7717d3731a83ffda2a2 Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira --- src/corelib/kernel/qcoreapplication_win.cpp | 30 +++++++++++++---- src/corelib/kernel/qcorecmdlineargs_p.h | 38 +++++++++++++++++----- src/winmain/qtmain_win.cpp | 50 ++++++++++++++++++++++------- src/winmain/winmain.pro | 2 ++ 4 files changed, 94 insertions(+), 26 deletions(-) diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp index 65ca6b0dcb..0ce3f00472 100644 --- a/src/corelib/kernel/qcoreapplication_win.cpp +++ b/src/corelib/kernel/qcoreapplication_win.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Samuel Gaist -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -145,14 +145,30 @@ QString QCoreApplicationPrivate::appName() const qWinMain() - Initializes Windows. Called from WinMain() in qtmain_win.cpp *****************************************************************************/ -#if defined(Q_OS_WINCE) -Q_CORE_EXPORT void __cdecl qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam, - int cmdShow, int &argc, QVector &argv) -#else +#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) + +// ### Qt6: FIXME: Remove this function. It is only there since for binary +// compatibility for applications built with Qt 5.3 using qtmain.lib which calls it. +// In Qt 5.4, qtmain.lib was changed to use CommandLineToArgvW() without calling into Qt5Core. Q_CORE_EXPORT void qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam, + int cmdShow, int &argc, QVector &argv) +{ + Q_UNUSED(instance) + Q_UNUSED(prevInstance) + Q_UNUSED(cmdShow) + + const QStringList wArgv = qWinCmdArgs(QString::fromLocal8Bit(cmdParam)); + argv.clear(); + argc = wArgv.size(); + foreach (const QString &wArg, wArgv) + argv.append(_strdup(wArg.toLocal8Bit().constData())); +} + +#elif defined(Q_OS_WINCE) + +Q_CORE_EXPORT void __cdecl qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam, int cmdShow, int &argc, QVector &argv) -#endif { static bool already_called = false; @@ -172,6 +188,8 @@ void qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam, Q_UNUSED(prevInstance); } +#endif // Q_OS_WINCE + #ifndef QT_NO_QOBJECT void QCoreApplicationPrivate::removePostedTimerEvent(QObject *object, int timerId) diff --git a/src/corelib/kernel/qcorecmdlineargs_p.h b/src/corelib/kernel/qcorecmdlineargs_p.h index 93c80205ab..84d9be20e5 100644 --- a/src/corelib/kernel/qcorecmdlineargs_p.h +++ b/src/corelib/kernel/qcorecmdlineargs_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -56,14 +56,34 @@ #include "QtCore/qstring.h" #include "QtCore/qstringlist.h" +#if defined(Q_OS_WIN) +# ifdef Q_OS_WIN32 +# include // first to suppress min, max macros. +# include +# else +# include "QtCore/qvector.h" +# include +# endif + QT_BEGIN_NAMESPACE -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) +#if defined(Q_OS_WIN32) + +static inline QStringList qWinCmdArgs(const QString &cmdLine) +{ + QStringList result; + int size; + if (wchar_t **argv = CommandLineToArgvW((const wchar_t *)cmdLine.utf16(), &size)) { + result.reserve(size); + wchar_t **argvEnd = argv + size; + for (wchar_t **a = argv; a < argvEnd; ++a) + result.append(QString::fromWCharArray(*a)); + LocalFree(argv); + } + return result; +} -QT_BEGIN_INCLUDE_NAMESPACE -# include "QtCore/qvector.h" -# include -QT_END_INCLUDE_NAMESPACE +#elif defined(Q_OS_WINCE) // Q_OS_WIN32 // template implementation of the parsing algorithm // this is used from qcoreapplication_win.cpp and the tools (rcc, uic...) @@ -149,7 +169,7 @@ static inline QStringList qCmdLineArgs(int argc, char *argv[]) return qWinCmdArgs(cmdLine); } -#else // Q_OS_WIN && !Q_OS_WINRT +#elif defined(Q_OS_WINRT) // Q_OS_WINCE static inline QStringList qCmdLineArgs(int argc, char *argv[]) { @@ -159,8 +179,10 @@ static inline QStringList qCmdLineArgs(int argc, char *argv[]) return args; } -#endif // !Q_OS_WIN || Q_OS_WINRT +#endif // Q_OS_WINRT QT_END_NAMESPACE +#endif // Q_OS_WIN + #endif // QCORECMDLINEARGS_WIN_P_H diff --git a/src/winmain/qtmain_win.cpp b/src/winmain/qtmain_win.cpp index dc765ea56a..778ddee64b 100644 --- a/src/winmain/qtmain_win.cpp +++ b/src/winmain/qtmain_win.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Windows main function of the Qt Toolkit. @@ -43,6 +43,10 @@ #include "qstring.h" #include "qvector.h" +#ifndef Q_OS_WINCE +# include +#endif + /* This file contains the code in the qtmain library for Windows. qtmain contains the Windows startup code and is required for @@ -83,26 +87,49 @@ extern "C" int main(int, char **); application. */ -#ifdef Q_OS_WINCE +#ifndef Q_OS_WINCE + +// Convert a wchar_t to char string, equivalent to QString::toLocal8Bit() +// when passed CP_ACP. +static inline char *wideToMulti(int codePage, const wchar_t *aw) +{ + const int required = WideCharToMultiByte(codePage, 0, aw, -1, NULL, 0, NULL, NULL); + char *result = new char[required]; + WideCharToMultiByte(codePage, 0, aw, -1, result, required, NULL, NULL); + return result; +} + +extern "C" int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR /*cmdParamarg*/, int /* cmdShow */) +{ + int argc; + wchar_t **argvW = CommandLineToArgvW(GetCommandLineW(), &argc); + if (!argvW) + return -1; + char **argv = new char *[argc]; + for (int i = 0; i < argc; ++i) + argv[i] = wideToMulti(CP_ACP, argvW[i]); + LocalFree(argvW); + const int exitCode = main(argc, argv); + for (int i = 0; i < argc; ++i) + delete [] argv[i]; + delete [] argv; + return exitCode; +} + +#else // !Q_OS_WINCE + int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR /*wCmdParam*/, int cmdShow) -#else -extern "C" -int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR /*cmdParamarg*/, int cmdShow) -#endif { QByteArray cmdParam = QString::fromWCharArray(GetCommandLine()).toLocal8Bit(); -#if defined(Q_OS_WINCE) wchar_t appName[MAX_PATH]; GetModuleFileName(0, appName, MAX_PATH); cmdParam.prepend(QString(QLatin1String("\"%1\" ")).arg(QString::fromWCharArray(appName)).toLocal8Bit()); -#endif int argc = 0; QVector argv(8); qWinMain(instance, prevInstance, cmdParam.data(), cmdShow, argc, argv); -#if defined(Q_OS_WINCE) wchar_t uniqueAppID[MAX_PATH]; GetModuleFileName(0, uniqueAppID, MAX_PATH); QString uid = QString::fromWCharArray(uniqueAppID).toLower().replace(QLatin1String("\\"), QLatin1String("_")); @@ -126,11 +153,10 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR /*cmdPara SetForegroundWindow((HWND)(((ULONG)aHwnd) | 0x01)); return 0; } -#endif // Q_OS_WINCE int result = main(argc, argv.data()); -#if defined(Q_OS_WINCE) CloseHandle(mutex); -#endif return result; } + +#endif // Q_OS_WINCE diff --git a/src/winmain/winmain.pro b/src/winmain/winmain.pro index 998200cb1e..284f2a2201 100644 --- a/src/winmain/winmain.pro +++ b/src/winmain/winmain.pro @@ -20,6 +20,8 @@ winrt { SOURCES = qtmain_winrt.cpp } else { SOURCES = qtmain_win.cpp + + !wince: LIBS += -lshell32 } load(qt_installs) -- cgit v1.2.3