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>bb10
parent
bec2fc19fd
commit
753aed83c6
|
|
@ -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);
|
||||
if (dispatcher)
|
||||
break;
|
||||
hr = view->get_CoreWindow(&window);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue