#include "il2cpp-config.h" #if IL2CPP_TARGET_WINDOWS && IL2CPP_HAS_OS_SYNCHRONIZATION_CONTEXT #include "os/SynchronizationContext.h" #include "os/WindowsRuntime.h" #include "vm/Class.h" #include "vm/Exception.h" #include "vm/RCW.h" #include "WindowsHelpers.h" #ifndef WINDOWS_SDK_BUILD_VERSION #error "We need to know which Windows SDK version we are compiling against!" #endif // There is a bug in Windows SDK 16299 where if the c++ compiler is too new, it forgets to define DEPRECATEDENUMERATOR. // To see if this workaround can be removed, compile this cfile against 10.0.16299 and verify that it compiles. // If it compiles correctly, we can remove this workaround. #if WINDOWS_SDK_BUILD_VERSION == 16299 #define DEPRECATEDENUMERATOR(x) #endif #include #include using il2cpp::os::SynchronizationContext; using Microsoft::WRL::Callback; using Microsoft::WRL::ComPtr; using Microsoft::WRL::Wrappers::HStringReference; template using AgileCallback = Microsoft::WRL::Implements, T, Microsoft::WRL::FtmBase>; #if !IL2CPP_TARGET_XBOXONE namespace winrt_interfaces { // NOTE: DispatcherQueue interface was added in Windows SDK 16299 // That means that when we build libil2cpp against an older SDK, these interfaces // will not be part of the headers. In order to solve that, I defined them here locally. enum DispatcherQueuePriority : int { DispatcherQueuePriority_Low = -10, DispatcherQueuePriority_Normal = 0, DispatcherQueuePriority_High = 10, }; MIDL_INTERFACE("DFA2DC9C-1A2D-4917-98F2-939AF1D6E0C8") IDispatcherQueueHandler : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE Invoke(void) = 0; }; MIDL_INTERFACE("603E88E4-A338-4FFE-A457-A5CFB9CEB899") IDispatcherQueue : public IInspectable { public: virtual HRESULT STDMETHODCALLTYPE CreateTimer(struct IDispatcherQueueTimer** result) = 0; virtual HRESULT STDMETHODCALLTYPE TryEnqueue(IDispatcherQueueHandler* callback, boolean* result) = 0; virtual HRESULT STDMETHODCALLTYPE TryEnqueueWithPriority(DispatcherQueuePriority priority, IDispatcherQueueHandler* callback, boolean* result) = 0; virtual HRESULT STDMETHODCALLTYPE add_ShutdownStarting(ABI::Windows::Foundation::ITypedEventHandler* handler, EventRegistrationToken* token) = 0; virtual HRESULT STDMETHODCALLTYPE remove_ShutdownStarting(EventRegistrationToken token) = 0; virtual HRESULT STDMETHODCALLTYPE add_ShutdownCompleted(ABI::Windows::Foundation::ITypedEventHandler* handler, EventRegistrationToken* token) = 0; virtual HRESULT STDMETHODCALLTYPE remove_ShutdownCompleted(EventRegistrationToken token) = 0; }; MIDL_INTERFACE("A96D83D7-9371-4517-9245-D0824AC12C74") IDispatcherQueueStatics : public IInspectable { public: virtual HRESULT STDMETHODCALLTYPE GetForCurrentThread(IDispatcherQueue** result) = 0; }; } static ComPtr GetDispatcherQueueStatics() { Il2CppHString className; Il2CppHStringHeader classNameHeader; auto hr = il2cpp::os::WindowsRuntime::CreateHStringReference(L"Windows.System.DispatcherQueue", &classNameHeader, &className); if (FAILED(hr)) return nullptr; ComPtr activationFactory; hr = il2cpp::os::WindowsRuntime::GetActivationFactory(className, reinterpret_cast(activationFactory.ReleaseAndGetAddressOf())); if (FAILED(hr)) return nullptr; ComPtr result; hr = activationFactory.As(&result); if (FAILED(hr)) return nullptr; return result; } #endif #if !IL2CPP_TARGET_WINDOWS_DESKTOP ComPtr s_CoreWindowStatics; #endif #if !IL2CPP_TARGET_XBOXONE ComPtr s_DispatcherQueueStatics; #endif Il2CppObject* SynchronizationContext::GetForCurrentThread() { HRESULT hr; #if !IL2CPP_TARGET_WINDOWS_DESKTOP if (s_CoreWindowStatics != nullptr) { ComPtr currentThreadWindow; hr = s_CoreWindowStatics->GetForCurrentThread(¤tThreadWindow); if (SUCCEEDED(hr) && currentThreadWindow != nullptr) { ComPtr dispatcher; hr = currentThreadWindow->get_Dispatcher(&dispatcher); if (SUCCEEDED(hr)) return vm::RCW::GetOrCreateFromIInspectable(reinterpret_cast(dispatcher.Get()), il2cpp_defaults.il2cpp_com_object_class); } } #endif #if !IL2CPP_TARGET_XBOXONE if (s_DispatcherQueueStatics != nullptr) { ComPtr dispatcherQueue; hr = s_DispatcherQueueStatics->GetForCurrentThread(&dispatcherQueue); if (SUCCEEDED(hr) && dispatcherQueue != nullptr) return vm::RCW::GetOrCreateFromIInspectable(reinterpret_cast(dispatcherQueue.Get()), il2cpp_defaults.il2cpp_com_object_class); } #endif return nullptr; } void SynchronizationContext::Post(Il2CppObject* context, SynchronizationContextCallback callback, intptr_t arg) { IL2CPP_ASSERT(vm::Class::HasParent(context->klass, il2cpp_defaults.il2cpp_com_object_class)); HRESULT hr; auto dispatcherUnknown = reinterpret_cast(static_cast(context)->identity); #if !IL2CPP_TARGET_WINDOWS_DESKTOP ComPtr dispatcher; hr = dispatcherUnknown->QueryInterface(__uuidof(dispatcher), &dispatcher); if (SUCCEEDED(hr)) { ComPtr ignoredAction; hr = dispatcher->RunAsync(ABI::Windows::UI::Core::CoreDispatcherPriority_Normal, Callback >([callback, arg]() -> HRESULT { callback(arg); return S_OK; }).Get(), &ignoredAction); vm::Exception::RaiseIfFailed(hr, false); } #endif #if !IL2CPP_TARGET_XBOXONE ComPtr dispatcherQueue; hr = dispatcherUnknown->QueryInterface(__uuidof(dispatcherQueue), &dispatcherQueue); if (SUCCEEDED(hr)) { boolean ignoredResult; hr = dispatcherQueue->TryEnqueueWithPriority(winrt_interfaces::DispatcherQueuePriority_Normal, Callback >([callback, arg]() -> HRESULT { callback(arg); return S_OK; }).Get(), &ignoredResult); vm::Exception::RaiseIfFailed(hr, false); } #endif } void SynchronizationContext::Initialize() { #if !IL2CPP_TARGET_WINDOWS_DESKTOP static_assert(LINK_TO_WINDOWSRUNTIME_LIBS, "RoGetActivationFactory and HStringReference can only be used directly if we link to WindowsRuntime libraries"); RoGetActivationFactory(HStringReference(L"Windows.UI.Core.CoreWindow").Get(), __uuidof(s_CoreWindowStatics), &s_CoreWindowStatics); #endif #if !IL2CPP_TARGET_XBOXONE s_DispatcherQueueStatics = GetDispatcherQueueStatics(); #endif } void SynchronizationContext::Shutdown() { #if !IL2CPP_TARGET_WINDOWS_DESKTOP s_CoreWindowStatics = nullptr; #endif #if !IL2CPP_TARGET_XBOXONE s_DispatcherQueueStatics = nullptr; #endif } #endif // IL2CPP_TARGET_WINDOWS && IL2CPP_HAS_OS_SYNCHRONIZATION_CONTEXT