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 <oswald.buddenhagen@digia.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Friedemann Kleint 2014-04-30 08:46:16 +02:00 committed by The Qt Project
parent 9dc254ad50
commit 9b121e5579
4 changed files with 94 additions and 26 deletions

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch> ** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
** 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 ** Contact: http://www.qt-project.org/legal
** **
** This file is part of the QtCore module of the Qt Toolkit. ** 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 qWinMain() - Initializes Windows. Called from WinMain() in qtmain_win.cpp
*****************************************************************************/ *****************************************************************************/
#if defined(Q_OS_WINCE) #if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
Q_CORE_EXPORT void __cdecl qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam,
int cmdShow, int &argc, QVector<char *> &argv) // ### Qt6: FIXME: Remove this function. It is only there since for binary
#else // 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 Q_CORE_EXPORT
void qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam, void qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam,
int cmdShow, int &argc, QVector<char *> &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<char *> &argv) int cmdShow, int &argc, QVector<char *> &argv)
#endif
{ {
static bool already_called = false; static bool already_called = false;
@ -172,6 +188,8 @@ void qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam,
Q_UNUSED(prevInstance); Q_UNUSED(prevInstance);
} }
#endif // Q_OS_WINCE
#ifndef QT_NO_QOBJECT #ifndef QT_NO_QOBJECT
void QCoreApplicationPrivate::removePostedTimerEvent(QObject *object, int timerId) void QCoreApplicationPrivate::removePostedTimerEvent(QObject *object, int timerId)

View File

@ -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 ** Contact: http://www.qt-project.org/legal
** **
** This file is part of the QtCore module of the Qt Toolkit. ** This file is part of the QtCore module of the Qt Toolkit.
@ -56,14 +56,34 @@
#include "QtCore/qstring.h" #include "QtCore/qstring.h"
#include "QtCore/qstringlist.h" #include "QtCore/qstringlist.h"
#if defined(Q_OS_WIN)
# ifdef Q_OS_WIN32
# include <qt_windows.h> // first to suppress min, max macros.
# include <shlobj.h>
# else
# include "QtCore/qvector.h"
# include <qt_windows.h>
# endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) #if defined(Q_OS_WIN32)
QT_BEGIN_INCLUDE_NAMESPACE static inline QStringList qWinCmdArgs(const QString &cmdLine)
# include "QtCore/qvector.h" {
# include <qt_windows.h> QStringList result;
QT_END_INCLUDE_NAMESPACE 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;
}
#elif defined(Q_OS_WINCE) // Q_OS_WIN32
// template implementation of the parsing algorithm // template implementation of the parsing algorithm
// this is used from qcoreapplication_win.cpp and the tools (rcc, uic...) // 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); 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[]) static inline QStringList qCmdLineArgs(int argc, char *argv[])
{ {
@ -159,8 +179,10 @@ static inline QStringList qCmdLineArgs(int argc, char *argv[])
return args; return args;
} }
#endif // !Q_OS_WIN || Q_OS_WINRT #endif // Q_OS_WINRT
QT_END_NAMESPACE QT_END_NAMESPACE
#endif // Q_OS_WIN
#endif // QCORECMDLINEARGS_WIN_P_H #endif // QCORECMDLINEARGS_WIN_P_H

View File

@ -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 ** Contact: http://www.qt-project.org/legal
** **
** This file is part of the Windows main function of the Qt Toolkit. ** This file is part of the Windows main function of the Qt Toolkit.
@ -43,6 +43,10 @@
#include "qstring.h" #include "qstring.h"
#include "qvector.h" #include "qvector.h"
#ifndef Q_OS_WINCE
# include <shlobj.h>
#endif
/* /*
This file contains the code in the qtmain library for Windows. This file contains the code in the qtmain library for Windows.
qtmain contains the Windows startup code and is required for qtmain contains the Windows startup code and is required for
@ -83,26 +87,49 @@ extern "C" int main(int, char **);
application. 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) 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(); QByteArray cmdParam = QString::fromWCharArray(GetCommandLine()).toLocal8Bit();
#if defined(Q_OS_WINCE)
wchar_t appName[MAX_PATH]; wchar_t appName[MAX_PATH];
GetModuleFileName(0, appName, MAX_PATH); GetModuleFileName(0, appName, MAX_PATH);
cmdParam.prepend(QString(QLatin1String("\"%1\" ")).arg(QString::fromWCharArray(appName)).toLocal8Bit()); cmdParam.prepend(QString(QLatin1String("\"%1\" ")).arg(QString::fromWCharArray(appName)).toLocal8Bit());
#endif
int argc = 0; int argc = 0;
QVector<char *> argv(8); QVector<char *> argv(8);
qWinMain(instance, prevInstance, cmdParam.data(), cmdShow, argc, argv); qWinMain(instance, prevInstance, cmdParam.data(), cmdShow, argc, argv);
#if defined(Q_OS_WINCE)
wchar_t uniqueAppID[MAX_PATH]; wchar_t uniqueAppID[MAX_PATH];
GetModuleFileName(0, uniqueAppID, MAX_PATH); GetModuleFileName(0, uniqueAppID, MAX_PATH);
QString uid = QString::fromWCharArray(uniqueAppID).toLower().replace(QLatin1String("\\"), QLatin1String("_")); 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)); SetForegroundWindow((HWND)(((ULONG)aHwnd) | 0x01));
return 0; return 0;
} }
#endif // Q_OS_WINCE
int result = main(argc, argv.data()); int result = main(argc, argv.data());
#if defined(Q_OS_WINCE)
CloseHandle(mutex); CloseHandle(mutex);
#endif
return result; return result;
} }
#endif // Q_OS_WINCE

View File

@ -20,6 +20,8 @@ winrt {
SOURCES = qtmain_winrt.cpp SOURCES = qtmain_winrt.cpp
} else { } else {
SOURCES = qtmain_win.cpp SOURCES = qtmain_win.cpp
!wince: LIBS += -lshell32
} }
load(qt_installs) load(qt_installs)