Change entry point for WinRT apps to WinMain

Using wmain causes the problem that the linker seems to create some code
around it, which calls ExitProcess. That function however is forbidden by
the Windows Store Certification process and hence you cannot publish an
application currently. This does not apply to Windows Phone, which links
in such a way that this problem does not occur there.

With WinMain as the entry point this does not happen and also is the
default entry point. Testing locally shows that certification goes fine.
Since it does not pass the full command line string, the C-runtime method
__getmainargs is used instead. This also gives access to any environment
strings which may be passed.

Note that MSDN states that this function should only be used for desktop
applications. For XAML/C++ scenarios there is no entry function at all,
but rather the App object gets instantiated in the default template. But
this only works for XAML itself and not for plain C++ applications,
probably some other entry wrapper is created on the fly here.

Done-with: Andrew Knight <andrew.knight@digia.com>
Change-Id: I8a118eddf6cfeddeca7d676267e979af17123e02
Reviewed-by: Maurice Kalinowski <maurice.kalinowski@digia.com>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
This commit is contained in:
Maurice Kalinowski 2013-12-31 00:21:08 +02:00 committed by The Qt Project
parent bdd3ead827
commit 3227929d21
3 changed files with 38 additions and 17 deletions

View File

@ -79,7 +79,7 @@ QMAKE_LIBS_NETWORK =
QMAKE_LIBS_OPENGL_ES2 = libEGL.lib libGLESv2.lib QMAKE_LIBS_OPENGL_ES2 = libEGL.lib libGLESv2.lib
QMAKE_LIBS_OPENGL_ES2_DEBUG = libEGLd.lib libGLESv2d.lib QMAKE_LIBS_OPENGL_ES2_DEBUG = libEGLd.lib libGLESv2d.lib
QMAKE_LIBS_QT_ENTRY = -lqtmain /ENTRY:wmainCRTStartup QMAKE_LIBS_QT_ENTRY = -lqtmain
QMAKE_IDL = midl QMAKE_IDL = midl
QMAKE_LIB = lib /NOLOGO QMAKE_LIB = lib /NOLOGO

View File

@ -44,11 +44,22 @@
linking to the Qt DLL. linking to the Qt DLL.
When a Windows application starts, the WinMain function is When a Windows application starts, the WinMain function is
invoked. WinMain creates the WinRT application which in turn invoked. This WinMain creates the WinRT application
calls the main entry point. container, which in turn calls the application's main()
entry point within the newly created GUI thread.
*/ */
extern "C" int main(int, char **); #include <new.h>
typedef struct
{
int newmode;
} _startupinfo;
extern "C" {
int __getmainargs(int *argc, char ***argv, char ***env, int expandWildcards, _startupinfo *info);
int main(int, char **);
}
#include <qbytearray.h> #include <qbytearray.h>
#include <qstring.h> #include <qstring.h>
@ -69,19 +80,17 @@ typedef ITypedEventHandler<Core::CoreApplicationView *, Activation::IActivatedEv
class AppContainer : public Microsoft::WRL::RuntimeClass<Core::IFrameworkView> class AppContainer : public Microsoft::WRL::RuntimeClass<Core::IFrameworkView>
{ {
public: public:
AppContainer(int argc, wchar_t **argv) : m_argc(argc), m_debugWait(false) AppContainer(int argc, char *argv[]) : m_argc(argc), m_debugWait(false)
{ {
m_argv.reserve(argc); m_argv.reserve(argc);
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i)
QByteArray arg = QString::fromWCharArray(argv[i]).toLocal8Bit(); m_argv.append(argv[i]);
m_argv.append(qstrdup(arg.constData()));
}
} }
~AppContainer() ~AppContainer()
{ {
foreach (const char *arg, m_argv) for (int i = m_argc; i < m_argv.size(); ++i)
delete[] arg; delete[] m_argv[i];
} }
// IFrameworkView Methods // IFrameworkView Methods
@ -136,19 +145,32 @@ private:
class AppViewSource : public Microsoft::WRL::RuntimeClass<Core::IFrameworkViewSource> class AppViewSource : public Microsoft::WRL::RuntimeClass<Core::IFrameworkViewSource>
{ {
public: public:
AppViewSource(int argc, wchar_t *argv[]) : argc(argc), argv(argv) { } AppViewSource(int argc, char **argv) : m_argc(argc), m_argv(argv) { }
HRESULT __stdcall CreateView(Core::IFrameworkView **frameworkView) HRESULT __stdcall CreateView(Core::IFrameworkView **frameworkView)
{ {
return (*frameworkView = Make<AppContainer>(argc, argv).Detach()) ? S_OK : E_OUTOFMEMORY; return (*frameworkView = Make<AppContainer>(m_argc, m_argv).Detach()) ? S_OK : E_OUTOFMEMORY;
} }
private: private:
int argc; int m_argc;
wchar_t **argv; char **m_argv;
}; };
// Main entry point for Appx containers // Main entry point for Appx containers
int wmain(int argc, wchar_t *argv[]) int WinMain()
{ {
int argc = 0;
char **argv, **env;
_startupinfo info = { _query_new_mode() };
if (int init = __getmainargs(&argc, &argv, &env, false, &info))
return init;
for (int i = 0; env && env[i]; ++i) {
QByteArray var(env[i]);
int split = var.indexOf('=');
if (split > 0)
qputenv(var.mid(0, split), var.mid(split + 1));
}
if (FAILED(RoInitialize(RO_INIT_MULTITHREADED))) if (FAILED(RoInitialize(RO_INIT_MULTITHREADED)))
return 1; return 1;

View File

@ -17,7 +17,6 @@ win32-msvc*:QMAKE_CXXFLAGS_DEBUG *= -Z7
win32-g++*: DEFINES += QT_NEEDS_QMAIN win32-g++*: DEFINES += QT_NEEDS_QMAIN
winrt { winrt {
QMAKE_LFLAGS += /ENTRY:wmainCRTStartup
SOURCES = qtmain_winrt.cpp SOURCES = qtmain_winrt.cpp
} else { } else {
SOURCES = qtmain_win.cpp SOURCES = qtmain_win.cpp