winrtmain: Start in XAML mode
authorAndrew Knight <andrew.knight@intopalo.com>
Wed, 5 Aug 2015 05:15:06 +0000 (08:15 +0300)
committerAndrew Knight <andrew.knight@intopalo.com>
Thu, 13 Aug 2015 16:12:18 +0000 (16:12 +0000)
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>
src/winmain/qtmain_winrt.cpp

index 141e3ed135921cb92480aa646db38f948963986c..d9f8c8f991977955444cb2cc553ee6039c8bf743 100644 (file)
   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;
+    }
+
+private:
+    HRESULT __stdcall OnActivated(IActivatedEventArgs *args) Q_DECL_OVERRIDE
+    {
+        return base->OnActivated(args);
     }
-    HRESULT __stdcall SetWindow(ABI::Windows::UI::Core::ICoreWindow *) { return S_OK; }
-    HRESULT __stdcall Load(HSTRING) { return S_OK; }
-    HRESULT __stdcall Run()
+
+    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());
+
+        ResumeThread(mainThread);
         return S_OK;
     }
-    HRESULT __stdcall Uninitialize() { return S_OK; }
 
-private:
-    // Activation handler
-    HRESULT onActivated(Core::ICoreApplicationView *, Activation::IActivatedEventArgs *args)
+    HRESULT __stdcall OnFileActivated(IFileActivatedEventArgs *args) Q_DECL_OVERRIDE
     {
-        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()));
-                }
-            }
-        }
+        Q_UNUSED(args);
         return S_OK;
     }
 
-    int m_argc;
-    QVector<char *> m_argv;
-    bool m_deleteArgv0;
-    EventRegistrationToken m_activationToken;
-};
+    HRESULT __stdcall OnSearchActivated(ISearchActivatedEventArgs *args) Q_DECL_OVERRIDE
+    {
+        Q_UNUSED(args);
+        return S_OK;
+    }
 
-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 OnShareTargetActivated(IShareTargetActivatedEventArgs *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 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);
 }