ohmu
·
2026-10-15
1#pragma once
2
3#ifdef __cplusplus
4
5extern "C" {
6 #include "common/FFlist.h"
7 #include "common/FFstrbuf.h"
8 #include "common/time.h"
9 #include "common/windows/com.h"
10 #include "common/windows/unicode.h"
11}
12
13 #if FF_HAVE_WINRT
14
15 #include <roapi.h>
16 #include <winstring.h>
17 #include <asyncinfo.h>
18
19 #include <winrt/base.h>
20 #include <winrt/Windows.Foundation.h>
21 #include <winrt/Windows.Foundation.Collections.h>
22
23using winrt::impl::abi_t;
24
25// Frees an HSTRING and clears the pointer, so it can be used with [[gnu::cleanup]].
26static inline void ffDeleteHstring(HSTRING* value) {
27 if (*value) {
28 WindowsDeleteString(*value);
29 *value = nullptr;
30 }
31}
32
33// Copies an HSTRING into an FFstrbuf, transcoding from UTF-16 to UTF-8.
34static inline void ffStrbufSetHstring(FFstrbuf* destination, HSTRING value) {
35 uint32_t length = 0;
36 const wchar_t* raw = WindowsGetStringRawBuffer(value, &length);
37 ffStrbufSetNWS(destination, length, raw);
38}
39
40// Wraps `items` in an IVector<hstring> and hands out its IIterable<hstring> view, which is the
41// parameter shape the FindAllAsync overloads taking additional properties expect. The caller owns
42// the result.
43HRESULT ffWinrtCreateHstringIterable(const wchar_t* const* items, uint32_t count, abi_t<winrt::Windows::Foundation::Collections::IIterable<winrt::hstring>>** result);
44
45// RoGetActivationFactory() for a WinRT runtime class.
46//
47// `Projection` must be the *projection* type -- e.g.
48// winrt::Windows::Devices.Bluetooth::IBluetoothLEDeviceStatics -- and never abi_t<...>:
49// winrt::impl::guid_v is only specialized for projection types, and abi_t<T> expands to
50// impl::abi<T>::type, which is a non-deduced context.
51template <typename Projection>
52static inline HRESULT ffGetActivationFactory(const wchar_t* className, abi_t<Projection>** factory) {
53 HSTRING_HEADER header;
54 HSTRING runtimeClass;
55 HRESULT hr = WindowsCreateStringReference(className, (UINT32) ::wcslen(className), &header, &runtimeClass);
56 if (FAILED(hr)) {
57 return hr;
58 }
59
60 return RoGetActivationFactory(runtimeClass, winrt::guid_of<Projection>(), reinterpret_cast<void**>(factory));
61}
62
63template <typename TargetProjection, typename SourceAbi>
64static inline HRESULT ffQueryInterface(SourceAbi* source, abi_t<TargetProjection>** target) {
65 return source->QueryInterface(winrt::guid_of<TargetProjection>(), reinterpret_cast<void**>(target));
66}
67
68// Spins until `operation` leaves AsyncStatus::Started, then hands its results to `result`.
69template <typename TOperationAbi, typename TResultAbi>
70static HRESULT ffWaitForAsyncOperation(TOperationAbi* operation, TResultAbi** result) {
71 FF_AUTO_RELEASE_COM_OBJECT IAsyncInfo* asyncInfo = nullptr;
72 HRESULT hr = ffQueryInterface<IAsyncInfo>(operation, &asyncInfo);
73 if (FAILED(hr)) {
74 return hr;
75 }
76
77 AsyncStatus status = AsyncStatus::Started;
78
79 for (;;) {
80 hr = asyncInfo->get_Status(&status);
81 if (FAILED(hr)) {
82 return hr;
83 }
84 if (status == AsyncStatus::Started) {
85 ffTimeSleep(0);
86 } else {
87 break;
88 }
89 }
90
91 if (status != AsyncStatus::Completed) {
92 HRESULT errorCode = E_FAIL;
93 asyncInfo->get_ErrorCode(&errorCode);
94 return FAILED(errorCode) ? errorCode : E_FAIL;
95 }
96
97 return operation->GetResults((void**) result);
98}
99
100template <typename TResultProjection, typename TOperation>
101static HRESULT ffRunAndWait(TOperation&& operation, abi_t<TResultProjection>** result) {
102 *result = nullptr;
103
104 FF_AUTO_RELEASE_COM_OBJECT abi_t<winrt::Windows::Foundation::IAsyncOperation<TResultProjection>>* opResult = nullptr;
105 HRESULT hr = operation(reinterpret_cast<void**>(&opResult));
106 if (FAILED(hr) || !opResult) {
107 return hr;
108 }
109
110 return ffWaitForAsyncOperation(opResult, result);
111}
112
113template <typename TResultProjection, typename TOperation>
114static HRESULT ffRunAndWait2(TOperation&& operation, abi_t<TResultProjection>** result) {
115 *result = nullptr;
116
117 FF_AUTO_RELEASE_COM_OBJECT abi_t<winrt::Windows::Foundation::IAsyncOperationWithProgress<TResultProjection, int32_t>>* opResult = nullptr;
118 HRESULT hr = operation(reinterpret_cast<void**>(&opResult));
119 if (FAILED(hr) || !opResult) {
120 return hr;
121 }
122
123 return ffWaitForAsyncOperation(opResult, result);
124}
125
126 #endif // FF_HAVE_WINRT
127
128#else
129
130 #error Must be included in C++ source file
131
132#endif