#pragma once #ifdef __cplusplus extern "C" { #include "common/FFlist.h" #include "common/FFstrbuf.h" #include "common/time.h" #include "common/windows/com.h" #include "common/windows/unicode.h" } #if FF_HAVE_WINRT #include #include #include #include #include #include using winrt::impl::abi_t; // Frees an HSTRING and clears the pointer, so it can be used with [[gnu::cleanup]]. void ffDeleteHstring(HSTRING* value); // Copies an HSTRING into an FFstrbuf, transcoding from UTF-16 to UTF-8. void ffStrbufSetHstring(FFstrbuf* destination, HSTRING value); // Wraps `items` in an IVector and hands out its IIterable view, which is the // parameter shape the FindAllAsync overloads taking additional properties expect. The caller owns // the result. HRESULT ffWinrtCreateHstringIterable(const wchar_t* const* items, uint32_t count, abi_t>** result); // RoGetActivationFactory() for a WinRT runtime class. // // `Projection` must be the *projection* type -- e.g. // winrt::Windows::Devices.Bluetooth::IBluetoothLEDeviceStatics -- and never abi_t<...>: // winrt::impl::guid_v is only specialized for projection types, and abi_t expands to // impl::abi::type, which is a non-deduced context. template static inline HRESULT ffGetActivationFactory(const wchar_t* className, abi_t** factory) { HSTRING_HEADER header; HSTRING runtimeClass; HRESULT hr = WindowsCreateStringReference(className, (UINT32) ::wcslen(className), &header, &runtimeClass); if (FAILED(hr)) { return hr; } return RoGetActivationFactory(runtimeClass, winrt::guid_of(), reinterpret_cast(factory)); } template static inline HRESULT ffQueryInterface(SourceAbi* source, abi_t** target) { return source->QueryInterface(winrt::guid_of(), reinterpret_cast(target)); } // Spins until `operation` leaves AsyncStatus::Started, then hands its results to `result`. template static HRESULT ffWaitForAsyncOperation(TOperationAbi* operation, TResultAbi** result) { FF_AUTO_RELEASE_COM_OBJECT IAsyncInfo* asyncInfo = nullptr; HRESULT hr = ffQueryInterface(operation, &asyncInfo); if (FAILED(hr)) { return hr; } AsyncStatus status = AsyncStatus::Started; for (;;) { hr = asyncInfo->get_Status(&status); if (FAILED(hr)) { return hr; } if (status == AsyncStatus::Started) { ffTimeSleep(0); } else { break; } } if (status != AsyncStatus::Completed) { HRESULT errorCode = E_FAIL; asyncInfo->get_ErrorCode(&errorCode); return FAILED(errorCode) ? errorCode : E_FAIL; } return operation->GetResults((void**) result); } template static HRESULT ffRunAndWait(TOperation&& operation, abi_t** result) { FF_AUTO_RELEASE_COM_OBJECT abi_t>* opResult = nullptr; HRESULT hr = operation(reinterpret_cast(&opResult)); if (FAILED(hr) || !opResult) { return hr; } return ffWaitForAsyncOperation(opResult, result); } template static HRESULT ffRunAndWait2(TOperation&& operation, abi_t** result) { *result = nullptr; FF_AUTO_RELEASE_COM_OBJECT abi_t>* opResult = nullptr; HRESULT hr = operation(reinterpret_cast(&opResult)); if (FAILED(hr) || !opResult) { return hr; } return ffWaitForAsyncOperation(opResult, result); } #endif // FF_HAVE_WINRT #else #error Must be included in C++ source file #endif