summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorMaurice Kalinowski <maurice.kalinowski@qt.io>2016-06-29 16:38:58 +0200
committerMaurice Kalinowski <maurice.kalinowski@qt.io>2016-07-06 07:20:16 +0000
commit753aed83c6568d3a6e3b7c653ed5782bf93cd214 (patch)
treed6a1f4570ee5b5a5c417e79f2378c423889b5de6 /src/corelib
parentbec2fc19fd18768b16925597871c77a61e716abd (diff)
winrt: Fix launch as background task
In case a background task wants to use Qt, winmain is not invoked. Neither can we create the same objects like winmain do (as in creating a application view). Instead runOnXamlThread uses the thread pool enabling the event loop to run successfully. Task-number: QTBUG-54396 Change-Id: Ia3ba23ed0fd6cd7d2ed8d43675e88073b9aec8b5 Reviewed-by: Andy Shaw <andy.shaw@qt.io> Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/kernel/qeventdispatcher_winrt.cpp113
1 files changed, 86 insertions, 27 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_winrt.cpp b/src/corelib/kernel/qeventdispatcher_winrt.cpp
index 2ffcf03eb2..3b2321aa49 100644
--- a/src/corelib/kernel/qeventdispatcher_winrt.cpp
+++ b/src/corelib/kernel/qeventdispatcher_winrt.cpp
@@ -95,6 +95,51 @@ private:
std::function<HRESULT()> delegate;
};
+class QWorkHandler : public IWorkItemHandler
+{
+public:
+ QWorkHandler(const std::function<HRESULT()> &delegate)
+ : m_delegate(delegate)
+ {
+ }
+
+ STDMETHODIMP Invoke(ABI::Windows::Foundation::IAsyncAction *operation)
+ {
+ HRESULT res = m_delegate();
+ Q_UNUSED(operation);
+ return res;
+ }
+
+ STDMETHODIMP QueryInterface(REFIID riid, void FAR* FAR* ppvObj)
+ {
+ if (riid == IID_IUnknown || riid == IID_IWorkItemHandler) {
+ *ppvObj = this;
+ AddRef();
+ return NOERROR;
+ }
+ *ppvObj = NULL;
+ return ResultFromScode(E_NOINTERFACE);
+ }
+
+ STDMETHODIMP_(ULONG) AddRef(void)
+ {
+ return ++m_refs;
+ }
+
+ STDMETHODIMP_(ULONG) Release(void)
+ {
+ if (--m_refs == 0) {
+ delete this;
+ return 0;
+ }
+ return m_refs;
+ }
+
+private:
+ std::function<HRESULT()> m_delegate;
+ ULONG m_refs{0};
+};
+
class QEventDispatcherWinRTPrivate : public QAbstractEventDispatcherPrivate
{
Q_DECLARE_PUBLIC(QEventDispatcherWinRT)
@@ -175,48 +220,62 @@ QEventDispatcherWinRT::~QEventDispatcherWinRT()
HRESULT QEventDispatcherWinRT::runOnXamlThread(const std::function<HRESULT ()> &delegate, bool waitForRun)
{
static __declspec(thread) ICoreDispatcher *dispatcher = nullptr;
+ HRESULT hr;
if (!dispatcher) {
- HRESULT hr;
ComPtr<ICoreImmersiveApplication> application;
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(),
IID_PPV_ARGS(&application));
ComPtr<ICoreApplicationView> view;
hr = application->get_MainView(&view);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<ICoreWindow> window;
- hr = view->get_CoreWindow(&window);
- Q_ASSERT_SUCCEEDED(hr);
- if (!window) {
- // In case the application is launched via activation
- // there might not be a main view (eg ShareTarget).
- // Hence iterate through the available views and try to find
- // a dispatcher in there
- ComPtr<IVectorView<CoreApplicationView*>> appViews;
- hr = application->get_Views(&appViews);
+ if (SUCCEEDED(hr) && view) {
+ ComPtr<ICoreWindow> window;
+ hr = view->get_CoreWindow(&window);
Q_ASSERT_SUCCEEDED(hr);
- quint32 count;
- hr = appViews->get_Size(&count);
- Q_ASSERT_SUCCEEDED(hr);
- for (quint32 i = 0; i < count; ++i) {
- hr = appViews->GetAt(i, &view);
+ if (!window) {
+ // In case the application is launched via activation
+ // there might not be a main view (eg ShareTarget).
+ // Hence iterate through the available views and try to find
+ // a dispatcher in there
+ ComPtr<IVectorView<CoreApplicationView*>> appViews;
+ hr = application->get_Views(&appViews);
Q_ASSERT_SUCCEEDED(hr);
- hr = view->get_CoreWindow(&window);
+ quint32 count;
+ hr = appViews->get_Size(&count);
Q_ASSERT_SUCCEEDED(hr);
- if (window) {
- hr = window->get_Dispatcher(&dispatcher);
+ for (quint32 i = 0; i < count; ++i) {
+ hr = appViews->GetAt(i, &view);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = view->get_CoreWindow(&window);
Q_ASSERT_SUCCEEDED(hr);
- if (dispatcher)
- break;
+ if (window) {
+ hr = window->get_Dispatcher(&dispatcher);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (dispatcher)
+ break;
+ }
}
+ } else {
+ hr = window->get_Dispatcher(&dispatcher);
+ Q_ASSERT_SUCCEEDED(hr);
}
- Q_ASSERT(dispatcher);
- } else {
- hr = window->get_Dispatcher(&dispatcher);
- Q_ASSERT_SUCCEEDED(hr);
}
}
- HRESULT hr;
+ if (Q_UNLIKELY(!dispatcher)) {
+ // In case the application is launched in a way that has no UI and
+ // also does not allow to create one, e.g. as a background task.
+ // Features like network operations do still work, others might cause
+ // errors in that case.
+ ComPtr<IThreadPoolStatics> tpStatics;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Threading_ThreadPool).Get(),
+ IID_PPV_ARGS(&tpStatics));
+ ComPtr<IAsyncAction> op;
+ hr = tpStatics.Get()->RunAsync(new QWorkHandler(delegate), &op);
+ if (FAILED(hr) || !waitForRun)
+ return hr;
+ return QWinRTFunctions::await(op);
+ }
+
boolean onXamlThread;
hr = dispatcher->get_HasThreadAccess(&onXamlThread);
Q_ASSERT_SUCCEEDED(hr);