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.
*/
#if _MSC_VER < 1900
#include <new.h>
typedef struct
{
int newmode;
} _startupinfo;
#endif // _MSC_VER < 1900
extern "C" {
#if _MSC_VER < 1900
int __getmainargs(int *argc, char ***argv, char ***env, int expandWildcards, _startupinfo *info);
#endif
int main(int, char **);
}
#include <qbytearray.h>
#include <qstring.h>
#include <qlist.h>
#include <qvector.h>
#include <qdir.h>
#include <qstandardpaths.h>
#include <qfunctions_winrt.h>
#include <wrl.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::Activation;
using namespace ABI::Windows::ApplicationModel::Core;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::UI;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
#define qHString(x) Wrappers::HString::MakeReference(x).Get()
#define CoreApplicationClass RuntimeClass_Windows_ApplicationModel_Core_CoreApplication
typedef ITypedEventHandler<Core::CoreApplicationView *, Activation::IActivatedEventArgs *> ActivatedHandler;
static int g_mainExitCode;
typedef ITypedEventHandler<CoreApplicationView *, Activation::IActivatedEventArgs *> ActivatedHandler;
static QtMessageHandler defaultMessageHandler;
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);
}
class AppContainer : public Microsoft::WRL::RuntimeClass<Core::IFrameworkView>
class AppContainer : public RuntimeClass<Xaml::IApplicationOverrides>
{
public:
AppContainer(int argc, char *argv[]) : m_argc(argc), m_deleteArgv0(false)
AppContainer()
{
m_argv.reserve(argc);
for (int i = 0; i < argc; ++i) {
// Workaround for empty argv[0] which occurs when WMAppManifest's ImageParams is used
// The second argument is taken to be the executable
if (i == 0 && argc >= 2 && !qstrlen(argv[0])) {
const QByteArray argv0 = QDir::current()
.absoluteFilePath(QString::fromLatin1(argv[1])).toUtf8();
m_argv.append(qstrdup(argv0.constData()));
m_argc -= 1;
m_deleteArgv0 = true;
++i;
continue;
}
m_argv.append(argv[i]);
}
ComPtr<Xaml::IApplicationFactory> applicationFactory;
HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Application).Get(),
IID_PPV_ARGS(&applicationFactory));
Q_ASSERT_SUCCEEDED(hr);
hr = applicationFactory->CreateInstance(this, &base, &core);
RETURN_VOID_IF_FAILED("Failed to create application container instance");
}
~AppContainer()
{
if (m_deleteArgv0)
delete[] m_argv[0];
for (int i = m_argc; i < m_argv.size(); ++i)
delete[] m_argv[i];
}
// IFrameworkView Methods
HRESULT __stdcall Initialize(Core::ICoreApplicationView *view)
int exec(int argc, char **argv)
{
view->add_Activated(Callback<ActivatedHandler>(this, &AppContainer::onActivated).Get(),
&m_activationToken);
return S_OK;
args.reserve(argc);
for (int i = 0; i < argc; ++i)
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; }
HRESULT __stdcall Run()
private:
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 debugWait = false;
foreach (const QByteArray &arg, m_argv) {
if (arg == "-qdevel")
foreach (const char *arg, args) {
if (strcmp(arg, "-qdevel") == 0)
develMode = true;
if (arg == "-qdebug")
if (strcmp(arg, "-qdebug") == 0)
debugWait = true;
}
if (develMode) {
@ -173,98 +238,70 @@ public:
while (!IsDebuggerPresent())
WaitForSingleObjectEx(GetCurrentThread(), 1, true);
}
g_mainExitCode = main(m_argv.count(), m_argv.data());
return S_OK;
}
HRESULT __stdcall Uninitialize() { return S_OK; }
private:
// 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()));
}
}
}
ResumeThread(mainThread);
return S_OK;
}
int m_argc;
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)
HRESULT __stdcall OnFileActivated(IFileActivatedEventArgs *args) Q_DECL_OVERRIDE
{
return (*frameworkView = Make<AppContainer>(m_argc, m_argv).Detach()) ? S_OK : E_OUTOFMEMORY;
Q_UNUSED(args);
return S_OK;
}
private:
int m_argc;
char **m_argv;
HRESULT __stdcall OnSearchActivated(ISearchActivatedEventArgs *args) Q_DECL_OVERRIDE
{
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
int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
#if _MSC_VER < 1900
int argc = 0;
char **argv, **env;
char **argv = 0, **env = 0;
#if _MSC_VER < 1900
_startupinfo info = { _query_new_mode() };
if (int init = __getmainargs(&argc, &argv, &env, false, &info))
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
for (int i = 0; env && env[i]; ++i) {
QByteArray var(env[i]);
int split = var.indexOf('=');
@ -275,10 +312,6 @@ int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
if (FAILED(RoInitialize(RO_INIT_MULTITHREADED)))
return 1;
Core::ICoreApplication *appFactory;
if (FAILED(RoGetActivationFactory(qHString(CoreApplicationClass), IID_PPV_ARGS(&appFactory))))
return 2;
appFactory->Run(Make<AppViewSource>(argc, argv).Get());
return g_mainExitCode;
ComPtr<AppContainer> app = Make<AppContainer>();
return app->exec(argc, argv);
}