SynchronizationContext.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #include "il2cpp-config.h"
  2. #if IL2CPP_TARGET_WINDOWS && IL2CPP_HAS_OS_SYNCHRONIZATION_CONTEXT
  3. #include "os/SynchronizationContext.h"
  4. #include "os/WindowsRuntime.h"
  5. #include "vm/Class.h"
  6. #include "vm/Exception.h"
  7. #include "vm/RCW.h"
  8. #include "WindowsHelpers.h"
  9. #ifndef WINDOWS_SDK_BUILD_VERSION
  10. #error "We need to know which Windows SDK version we are compiling against!"
  11. #endif
  12. // There is a bug in Windows SDK 16299 where if the c++ compiler is too new, it forgets to define DEPRECATEDENUMERATOR.
  13. // To see if this workaround can be removed, compile this cfile against 10.0.16299 and verify that it compiles.
  14. // If it compiles correctly, we can remove this workaround.
  15. #if WINDOWS_SDK_BUILD_VERSION == 16299
  16. #define DEPRECATEDENUMERATOR(x)
  17. #endif
  18. #include <windows.ui.core.h>
  19. #include <wrl.h>
  20. using il2cpp::os::SynchronizationContext;
  21. using Microsoft::WRL::Callback;
  22. using Microsoft::WRL::ComPtr;
  23. using Microsoft::WRL::Wrappers::HStringReference;
  24. template<typename T>
  25. using AgileCallback = Microsoft::WRL::Implements<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, T, Microsoft::WRL::FtmBase>;
  26. #if !IL2CPP_TARGET_XBOXONE
  27. namespace winrt_interfaces
  28. {
  29. // NOTE: DispatcherQueue interface was added in Windows SDK 16299
  30. // That means that when we build libil2cpp against an older SDK, these interfaces
  31. // will not be part of the headers. In order to solve that, I defined them here locally.
  32. enum DispatcherQueuePriority : int
  33. {
  34. DispatcherQueuePriority_Low = -10,
  35. DispatcherQueuePriority_Normal = 0,
  36. DispatcherQueuePriority_High = 10,
  37. };
  38. MIDL_INTERFACE("DFA2DC9C-1A2D-4917-98F2-939AF1D6E0C8")
  39. IDispatcherQueueHandler : public IUnknown
  40. {
  41. public:
  42. virtual HRESULT STDMETHODCALLTYPE Invoke(void) = 0;
  43. };
  44. MIDL_INTERFACE("603E88E4-A338-4FFE-A457-A5CFB9CEB899")
  45. IDispatcherQueue : public IInspectable
  46. {
  47. public:
  48. virtual HRESULT STDMETHODCALLTYPE CreateTimer(struct IDispatcherQueueTimer** result) = 0;
  49. virtual HRESULT STDMETHODCALLTYPE TryEnqueue(IDispatcherQueueHandler* callback, boolean* result) = 0;
  50. virtual HRESULT STDMETHODCALLTYPE TryEnqueueWithPriority(DispatcherQueuePriority priority, IDispatcherQueueHandler* callback, boolean* result) = 0;
  51. virtual HRESULT STDMETHODCALLTYPE add_ShutdownStarting(ABI::Windows::Foundation::ITypedEventHandler<struct DispatcherQueue*, struct DispatcherQueueShutdownStartingEventArgs*>* handler, EventRegistrationToken* token) = 0;
  52. virtual HRESULT STDMETHODCALLTYPE remove_ShutdownStarting(EventRegistrationToken token) = 0;
  53. virtual HRESULT STDMETHODCALLTYPE add_ShutdownCompleted(ABI::Windows::Foundation::ITypedEventHandler<struct DispatcherQueue*, IInspectable*>* handler, EventRegistrationToken* token) = 0;
  54. virtual HRESULT STDMETHODCALLTYPE remove_ShutdownCompleted(EventRegistrationToken token) = 0;
  55. };
  56. MIDL_INTERFACE("A96D83D7-9371-4517-9245-D0824AC12C74")
  57. IDispatcherQueueStatics : public IInspectable
  58. {
  59. public:
  60. virtual HRESULT STDMETHODCALLTYPE GetForCurrentThread(IDispatcherQueue** result) = 0;
  61. };
  62. }
  63. static ComPtr<winrt_interfaces::IDispatcherQueueStatics> GetDispatcherQueueStatics()
  64. {
  65. Il2CppHString className;
  66. Il2CppHStringHeader classNameHeader;
  67. auto hr = il2cpp::os::WindowsRuntime::CreateHStringReference(L"Windows.System.DispatcherQueue", &classNameHeader, &className);
  68. if (FAILED(hr))
  69. return nullptr;
  70. ComPtr<IActivationFactory> activationFactory;
  71. hr = il2cpp::os::WindowsRuntime::GetActivationFactory(className, reinterpret_cast<Il2CppIActivationFactory**>(activationFactory.ReleaseAndGetAddressOf()));
  72. if (FAILED(hr))
  73. return nullptr;
  74. ComPtr<winrt_interfaces::IDispatcherQueueStatics> result;
  75. hr = activationFactory.As(&result);
  76. if (FAILED(hr))
  77. return nullptr;
  78. return result;
  79. }
  80. #endif
  81. #if !IL2CPP_TARGET_WINDOWS_DESKTOP
  82. ComPtr<ABI::Windows::UI::Core::ICoreWindowStatic> s_CoreWindowStatics;
  83. #endif
  84. #if !IL2CPP_TARGET_XBOXONE
  85. ComPtr<winrt_interfaces::IDispatcherQueueStatics> s_DispatcherQueueStatics;
  86. #endif
  87. Il2CppObject* SynchronizationContext::GetForCurrentThread()
  88. {
  89. HRESULT hr;
  90. #if !IL2CPP_TARGET_WINDOWS_DESKTOP
  91. if (s_CoreWindowStatics != nullptr)
  92. {
  93. ComPtr<ABI::Windows::UI::Core::ICoreWindow> currentThreadWindow;
  94. hr = s_CoreWindowStatics->GetForCurrentThread(&currentThreadWindow);
  95. if (SUCCEEDED(hr) && currentThreadWindow != nullptr)
  96. {
  97. ComPtr<ABI::Windows::UI::Core::ICoreDispatcher> dispatcher;
  98. hr = currentThreadWindow->get_Dispatcher(&dispatcher);
  99. if (SUCCEEDED(hr))
  100. return vm::RCW::GetOrCreateFromIInspectable(reinterpret_cast<Il2CppIInspectable*>(dispatcher.Get()), il2cpp_defaults.il2cpp_com_object_class);
  101. }
  102. }
  103. #endif
  104. #if !IL2CPP_TARGET_XBOXONE
  105. if (s_DispatcherQueueStatics != nullptr)
  106. {
  107. ComPtr<winrt_interfaces::IDispatcherQueue> dispatcherQueue;
  108. hr = s_DispatcherQueueStatics->GetForCurrentThread(&dispatcherQueue);
  109. if (SUCCEEDED(hr) && dispatcherQueue != nullptr)
  110. return vm::RCW::GetOrCreateFromIInspectable(reinterpret_cast<Il2CppIInspectable*>(dispatcherQueue.Get()), il2cpp_defaults.il2cpp_com_object_class);
  111. }
  112. #endif
  113. return nullptr;
  114. }
  115. void SynchronizationContext::Post(Il2CppObject* context, SynchronizationContextCallback callback, intptr_t arg)
  116. {
  117. IL2CPP_ASSERT(vm::Class::HasParent(context->klass, il2cpp_defaults.il2cpp_com_object_class));
  118. HRESULT hr;
  119. auto dispatcherUnknown = reinterpret_cast<IUnknown*>(static_cast<Il2CppComObject*>(context)->identity);
  120. #if !IL2CPP_TARGET_WINDOWS_DESKTOP
  121. ComPtr<ABI::Windows::UI::Core::ICoreDispatcher> dispatcher;
  122. hr = dispatcherUnknown->QueryInterface(__uuidof(dispatcher), &dispatcher);
  123. if (SUCCEEDED(hr))
  124. {
  125. ComPtr<ABI::Windows::Foundation::IAsyncAction> ignoredAction;
  126. hr = dispatcher->RunAsync(ABI::Windows::UI::Core::CoreDispatcherPriority_Normal, Callback<AgileCallback<ABI::Windows::UI::Core::IDispatchedHandler> >([callback, arg]() -> HRESULT
  127. {
  128. callback(arg);
  129. return S_OK;
  130. }).Get(), &ignoredAction);
  131. vm::Exception::RaiseIfFailed(hr, false);
  132. }
  133. #endif
  134. #if !IL2CPP_TARGET_XBOXONE
  135. ComPtr<winrt_interfaces::IDispatcherQueue> dispatcherQueue;
  136. hr = dispatcherUnknown->QueryInterface(__uuidof(dispatcherQueue), &dispatcherQueue);
  137. if (SUCCEEDED(hr))
  138. {
  139. boolean ignoredResult;
  140. hr = dispatcherQueue->TryEnqueueWithPriority(winrt_interfaces::DispatcherQueuePriority_Normal, Callback<AgileCallback<winrt_interfaces::IDispatcherQueueHandler> >([callback, arg]() -> HRESULT
  141. {
  142. callback(arg);
  143. return S_OK;
  144. }).Get(), &ignoredResult);
  145. vm::Exception::RaiseIfFailed(hr, false);
  146. }
  147. #endif
  148. }
  149. void SynchronizationContext::Initialize()
  150. {
  151. #if !IL2CPP_TARGET_WINDOWS_DESKTOP
  152. static_assert(LINK_TO_WINDOWSRUNTIME_LIBS, "RoGetActivationFactory and HStringReference can only be used directly if we link to WindowsRuntime libraries");
  153. RoGetActivationFactory(HStringReference(L"Windows.UI.Core.CoreWindow").Get(), __uuidof(s_CoreWindowStatics), &s_CoreWindowStatics);
  154. #endif
  155. #if !IL2CPP_TARGET_XBOXONE
  156. s_DispatcherQueueStatics = GetDispatcherQueueStatics();
  157. #endif
  158. }
  159. void SynchronizationContext::Shutdown()
  160. {
  161. #if !IL2CPP_TARGET_WINDOWS_DESKTOP
  162. s_CoreWindowStatics = nullptr;
  163. #endif
  164. #if !IL2CPP_TARGET_XBOXONE
  165. s_DispatcherQueueStatics = nullptr;
  166. #endif
  167. }
  168. #endif // IL2CPP_TARGET_WINDOWS && IL2CPP_HAS_OS_SYNCHRONIZATION_CONTEXT