#pragma once #include "ReferenceCounter.h" #include "os/Win32/WindowsHeaders.h" #include #include #include #include namespace il2cpp { namespace winrt { template struct ResultTypeTraits { typedef typename ABI::Windows::Foundation::Internal::GetLogicalType::type LogicalType; typedef typename ABI::Windows::Foundation::Internal::GetAbiType::type ResultType; }; template<> struct ResultTypeTraits { typedef void LogicalType; typedef void ResultType; }; template class SynchronousOperationBase : public Microsoft::WRL::RuntimeClass, Microsoft::WRL::FtmBase, HandlerType> { protected: HANDLE m_Event; HRESULT m_HR; typedef OperationType OperationType; inline SynchronousOperationBase(OperationType* op) { m_Event = CreateEventExW(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); Assert(m_Event && "CreateEventExW failed."); } inline ~SynchronousOperationBase() { CloseHandle(m_Event); // This will be not 0 if it's allocated on the stack // This class must be allocated on the heap for correct COM ref counting! IL2CPP_ASSERT(GetRefCount() == 0); } public: inline HRESULT Wait() { auto waitResult = WaitForSingleObjectEx(m_Event, INFINITE, FALSE); if (waitResult != WAIT_OBJECT_0) return E_FAIL; return m_HR; } }; template class SynchronousOperation : public SynchronousOperationBase, ABI::Windows::Foundation::IAsyncOperationCompletedHandler > { private: typedef typename ResultTypeTraits::ResultType ResultType; ResultType m_Result; public: inline SynchronousOperation(OperationType* op) : SynchronousOperationBase(op), m_Result(ResultType()) { // NOTE: this is in the derived class because it might immediately complete. // If this was called from the base class, you'd get a callback on a partially // constructed vtable and crash. auto hr = op->put_Completed(this); Assert(SUCCEEDED(hr) && "IAsyncOperation::put_Completed failed."); } ~SynchronousOperation() { ReferenceCounter::Release(m_Result); } HRESULT GetResults(ResultType* result) { auto hr = Wait(); if (FAILED(hr)) return hr; *result = m_Result; ReferenceCounter::AddRef(*result); return S_OK; } virtual HRESULT STDMETHODCALLTYPE Invoke(ABI::Windows::Foundation::IAsyncOperation* asyncInfo, ABI::Windows::Foundation::AsyncStatus status) override { m_HR = asyncInfo->GetResults(&m_Result); SetEvent(m_Event); return S_OK; } static Microsoft::WRL::ComPtr > Make(OperationType* op) { return Microsoft::WRL::Make >(op); } }; template<> class SynchronousOperation : public SynchronousOperationBase { public: inline SynchronousOperation(OperationType* op) : SynchronousOperationBase(op) { // NOTE: this is in the derived class because it might immediately complete. // If this was called from the base class, you'd get a callback on a partially // constructed vtable and crash. auto hr = op->put_Completed(this); Assert(SUCCEEDED(hr) && "IAsyncAction::put_Completed failed."); } virtual HRESULT STDMETHODCALLTYPE Invoke(ABI::Windows::Foundation::IAsyncAction* asyncInfo, ABI::Windows::Foundation::AsyncStatus status) override { m_HR = asyncInfo->GetResults(); SetEvent(m_Event); return S_OK; } }; template Microsoft::WRL::ComPtr::LogicalType> > MakeSynchronousOperation(T* op) { return Microsoft::WRL::Make::LogicalType> >(op); } } }