winrtmain: Start in XAML mode

This allows the platform plugin to start using XAML interfaces in the
windowing system.

Change-Id: Ifcd29b8b8d83b138af69786dfc6a1adec21be37e
Reviewed-by: Maurice Kalinowski <maurice.kalinowski@theqtcompany.com>
This commit is contained in:
Andrew Knight 2015-08-05 08:15:06 +03:00
parent 130083a7fc
commit ebc2b963aa

View File

@ -49,38 +49,44 @@
entry point within the newly created GUI thread. entry point within the newly created GUI thread.
*/ */
#if _MSC_VER < 1900
#include <new.h> #include <new.h>
typedef struct typedef struct
{ {
int newmode; int newmode;
} _startupinfo; } _startupinfo;
#endif // _MSC_VER < 1900
extern "C" { extern "C" {
#if _MSC_VER < 1900
int __getmainargs(int *argc, char ***argv, char ***env, int expandWildcards, _startupinfo *info); int __getmainargs(int *argc, char ***argv, char ***env, int expandWildcards, _startupinfo *info);
#endif
int main(int, char **); int main(int, char **);
} }
#include <qbytearray.h> #include <qbytearray.h>
#include <qstring.h> #include <qstring.h>
#include <qlist.h>
#include <qvector.h>
#include <qdir.h> #include <qdir.h>
#include <qstandardpaths.h> #include <qstandardpaths.h>
#include <qfunctions_winrt.h>
#include <wrl.h> #include <wrl.h>
#include <Windows.ApplicationModel.core.h> #include <Windows.ApplicationModel.core.h>
#include <windows.ui.xaml.h>
#include <windows.ui.xaml.controls.h>
using namespace ABI::Windows::ApplicationModel; using namespace ABI::Windows::ApplicationModel;
using namespace ABI::Windows::ApplicationModel::Activation;
using namespace ABI::Windows::ApplicationModel::Core;
using namespace ABI::Windows::Foundation; using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::UI;
using namespace Microsoft::WRL; using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers; using namespace Microsoft::WRL::Wrappers;
#define qHString(x) Wrappers::HString::MakeReference(x).Get() #define qHString(x) Wrappers::HString::MakeReference(x).Get()
#define CoreApplicationClass RuntimeClass_Windows_ApplicationModel_Core_CoreApplication #define CoreApplicationClass RuntimeClass_Windows_ApplicationModel_Core_CoreApplication
typedef ITypedEventHandler<Core::CoreApplicationView *, Activation::IActivatedEventArgs *> ActivatedHandler; typedef ITypedEventHandler<CoreApplicationView *, Activation::IActivatedEventArgs *> ActivatedHandler;
static int g_mainExitCode;
static QtMessageHandler defaultMessageHandler; static QtMessageHandler defaultMessageHandler;
static void devMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message) static void devMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
@ -103,53 +109,112 @@ static void devMessageHandler(QtMsgType type, const QMessageLogContext &context,
defaultMessageHandler(type, context, message); defaultMessageHandler(type, context, message);
} }
class AppContainer : public Microsoft::WRL::RuntimeClass<Core::IFrameworkView> class AppContainer : public RuntimeClass<Xaml::IApplicationOverrides>
{ {
public: public:
AppContainer(int argc, char *argv[]) : m_argc(argc), m_deleteArgv0(false) AppContainer()
{ {
m_argv.reserve(argc); ComPtr<Xaml::IApplicationFactory> applicationFactory;
for (int i = 0; i < argc; ++i) { HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Application).Get(),
// Workaround for empty argv[0] which occurs when WMAppManifest's ImageParams is used IID_PPV_ARGS(&applicationFactory));
// The second argument is taken to be the executable Q_ASSERT_SUCCEEDED(hr);
if (i == 0 && argc >= 2 && !qstrlen(argv[0])) {
const QByteArray argv0 = QDir::current() hr = applicationFactory->CreateInstance(this, &base, &core);
.absoluteFilePath(QString::fromLatin1(argv[1])).toUtf8(); RETURN_VOID_IF_FAILED("Failed to create application container instance");
m_argv.append(qstrdup(argv0.constData()));
m_argc -= 1;
m_deleteArgv0 = true;
++i;
continue;
}
m_argv.append(argv[i]);
}
} }
~AppContainer() ~AppContainer()
{ {
if (m_deleteArgv0)
delete[] m_argv[0];
for (int i = m_argc; i < m_argv.size(); ++i)
delete[] m_argv[i];
} }
// IFrameworkView Methods int exec(int argc, char **argv)
HRESULT __stdcall Initialize(Core::ICoreApplicationView *view)
{ {
view->add_Activated(Callback<ActivatedHandler>(this, &AppContainer::onActivated).Get(), args.reserve(argc);
&m_activationToken); for (int i = 0; i < argc; ++i)
return S_OK; args.append(argv[i]);
mainThread = CreateThread(NULL, 0, [](void *param) -> DWORD {
AppContainer *app = reinterpret_cast<AppContainer *>(param);
int argc = app->args.count();
char **argv = app->args.data();
return main(argc, argv);
}, this, CREATE_SUSPENDED, nullptr);
HRESULT hr;
ComPtr<Xaml::IApplicationStatics> appStatics;
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Application).Get(),
IID_PPV_ARGS(&appStatics));
Q_ASSERT_SUCCEEDED(hr);
hr = appStatics->Start(Callback<Xaml::IApplicationInitializationCallback>([](Xaml::IApplicationInitializationCallbackParams *) {
return S_OK;
}).Get());
Q_ASSERT_SUCCEEDED(hr);
DWORD exitCode;
GetExitCodeThread(mainThread, &exitCode);
return exitCode;
} }
HRESULT __stdcall SetWindow(ABI::Windows::UI::Core::ICoreWindow *) { return S_OK; }
HRESULT __stdcall Load(HSTRING) { return S_OK; } private:
HRESULT __stdcall Run() HRESULT __stdcall OnActivated(IActivatedEventArgs *args) Q_DECL_OVERRIDE
{ {
return base->OnActivated(args);
}
HRESULT __stdcall OnLaunched(ILaunchActivatedEventArgs *launchArgs) Q_DECL_OVERRIDE
{
#if _MSC_VER >= 1900
commandLine = QString::fromWCharArray(GetCommandLine()).toUtf8();
#endif
HString launchCommandLine;
launchArgs->get_Arguments(launchCommandLine.GetAddressOf());
if (launchCommandLine.IsValid()) {
quint32 launchCommandLineLength;
const wchar_t *launchCommandLineBuffer = launchCommandLine.GetRawBuffer(&launchCommandLineLength);
if (!commandLine.isEmpty() && launchCommandLineLength)
commandLine += ' ';
if (launchCommandLineLength)
commandLine += QString::fromWCharArray(launchCommandLineBuffer, launchCommandLineLength).toUtf8();
}
if (!commandLine.isEmpty())
args.append(commandLine.data());
bool quote = false;
bool escape = false;
for (int i = 0; i < commandLine.size(); ++i) {
switch (commandLine.at(i)) {
case '\\':
escape = true;
break;
case '"':
if (escape) {
escape = false;
break;
}
quote = !quote;
commandLine[i] = '\0';
break;
case ' ':
if (quote)
break;
commandLine[i] = '\0';
if (args.last()[0] != '\0')
args.append(commandLine.data() + i + 1);
// fall through
default:
if (args.last()[0] == '\0')
args.last() = commandLine.data() + i;
escape = false; // only quotes are escaped
break;
}
}
bool develMode = false; bool develMode = false;
bool debugWait = false; bool debugWait = false;
foreach (const QByteArray &arg, m_argv) { foreach (const char *arg, args) {
if (arg == "-qdevel") if (strcmp(arg, "-qdevel") == 0)
develMode = true; develMode = true;
if (arg == "-qdebug") if (strcmp(arg, "-qdebug") == 0)
debugWait = true; debugWait = true;
} }
if (develMode) { if (develMode) {
@ -173,98 +238,70 @@ public:
while (!IsDebuggerPresent()) while (!IsDebuggerPresent())
WaitForSingleObjectEx(GetCurrentThread(), 1, true); WaitForSingleObjectEx(GetCurrentThread(), 1, true);
} }
g_mainExitCode = main(m_argv.count(), m_argv.data());
return S_OK;
}
HRESULT __stdcall Uninitialize() { return S_OK; }
private: ResumeThread(mainThread);
// Activation handler
HRESULT onActivated(Core::ICoreApplicationView *, Activation::IActivatedEventArgs *args)
{
Activation::ILaunchActivatedEventArgs *launchArgs;
if (SUCCEEDED(args->QueryInterface(&launchArgs))) {
for (int i = m_argc; i < m_argv.size(); ++i)
delete[] m_argv[i];
m_argv.resize(m_argc);
HString arguments;
launchArgs->get_Arguments(arguments.GetAddressOf());
if (arguments.IsValid()) {
foreach (const QByteArray &arg, QString::fromWCharArray(
arguments.GetRawBuffer(nullptr)).toLocal8Bit().split(' ')) {
m_argv.append(qstrdup(arg.constData()));
}
}
}
return S_OK; return S_OK;
} }
int m_argc; HRESULT __stdcall OnFileActivated(IFileActivatedEventArgs *args) Q_DECL_OVERRIDE
QVector<char *> m_argv;
bool m_deleteArgv0;
EventRegistrationToken m_activationToken;
};
class AppViewSource : public Microsoft::WRL::RuntimeClass<Core::IFrameworkViewSource>
{
public:
AppViewSource(int argc, char **argv) : m_argc(argc), m_argv(argv) { }
HRESULT __stdcall CreateView(Core::IFrameworkView **frameworkView)
{ {
return (*frameworkView = Make<AppContainer>(m_argc, m_argv).Detach()) ? S_OK : E_OUTOFMEMORY; Q_UNUSED(args);
return S_OK;
} }
private:
int m_argc; HRESULT __stdcall OnSearchActivated(ISearchActivatedEventArgs *args) Q_DECL_OVERRIDE
char **m_argv; {
Q_UNUSED(args);
return S_OK;
}
HRESULT __stdcall OnShareTargetActivated(IShareTargetActivatedEventArgs *args) Q_DECL_OVERRIDE
{
Q_UNUSED(args);
return S_OK;
}
HRESULT __stdcall OnFileOpenPickerActivated(IFileOpenPickerActivatedEventArgs *args) Q_DECL_OVERRIDE
{
Q_UNUSED(args);
return S_OK;
}
HRESULT __stdcall OnFileSavePickerActivated(IFileSavePickerActivatedEventArgs *args) Q_DECL_OVERRIDE
{
Q_UNUSED(args);
return S_OK;
}
HRESULT __stdcall OnCachedFileUpdaterActivated(ICachedFileUpdaterActivatedEventArgs *args) Q_DECL_OVERRIDE
{
Q_UNUSED(args);
return S_OK;
}
HRESULT __stdcall OnWindowCreated(Xaml::IWindowCreatedEventArgs *args) Q_DECL_OVERRIDE
{
Q_UNUSED(args);
return S_OK;
}
ComPtr<Xaml::IApplicationOverrides> base;
ComPtr<Xaml::IApplication> core;
QByteArray commandLine;
QVarLengthArray<char *> args;
HANDLE mainThread;
}; };
// Main entry point for Appx containers // Main entry point for Appx containers
int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int) int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{ {
#if _MSC_VER < 1900
int argc = 0; int argc = 0;
char **argv, **env; char **argv = 0, **env = 0;
#if _MSC_VER < 1900
_startupinfo info = { _query_new_mode() }; _startupinfo info = { _query_new_mode() };
if (int init = __getmainargs(&argc, &argv, &env, false, &info)) if (int init = __getmainargs(&argc, &argv, &env, false, &info))
return init; return init;
#else
QByteArray commandLine = QString::fromWCharArray(GetCommandLine()).toUtf8();
QVarLengthArray<char *> args;
args.append(commandLine.data());
bool quote = false;
bool escape = false;
for (int i = 0; i < commandLine.size(); ++i) {
switch (commandLine.at(i)) {
case '\\':
escape = true;
break;
case '"':
if (escape) {
escape = false;
break;
}
quote = !quote;
commandLine[i] = '\0';
break;
case ' ':
if (quote)
break;
commandLine[i] = '\0';
if (args.last()[0] != '\0')
args.append(commandLine.data() + i + 1);
// fall through
default:
if (args.last()[0] == '\0')
args.last() = commandLine.data() + i;
escape = false; // only quotes are escaped
break;
}
}
int argc = args.size();
char **argv = args.data();
char **env = Q_NULLPTR;
#endif // _MSC_VER >= 1900 #endif // _MSC_VER >= 1900
for (int i = 0; env && env[i]; ++i) { for (int i = 0; env && env[i]; ++i) {
QByteArray var(env[i]); QByteArray var(env[i]);
int split = var.indexOf('='); int split = var.indexOf('=');
@ -275,10 +312,6 @@ int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
if (FAILED(RoInitialize(RO_INIT_MULTITHREADED))) if (FAILED(RoInitialize(RO_INIT_MULTITHREADED)))
return 1; return 1;
Core::ICoreApplication *appFactory; ComPtr<AppContainer> app = Make<AppContainer>();
if (FAILED(RoGetActivationFactory(qHString(CoreApplicationClass), IID_PPV_ARGS(&appFactory)))) return app->exec(argc, argv);
return 2;
appFactory->Run(Make<AppViewSource>(argc, argv).Get());
return g_mainExitCode;
} }