ohmu
·
2026-10-15
1#include "winrt.hpp"
2
3#if FF_HAVE_WINRT
4
5 #include <wchar.h>
6
7#if defined(__GNUC__) || defined(__clang__)
8extern "C" [[noreturn]] void __cxa_pure_virtual(void) {
9 __builtin_trap();
10}
11#endif
12
13// C++/WinRT supplies the ABI vtable shape, including IUnknown and IInspectable. These concrete
14// classes only provide the implementation-specific state and methods; placement new keeps their
15// storage under the C allocator used by the rest of fastfetch.
16namespace {
17
18using WinrtIterableAbi = abi_t<winrt::Windows::Foundation::Collections::IIterable<winrt::hstring>>;
19using WinrtIteratorAbi = abi_t<winrt::Windows::Foundation::Collections::IIterator<winrt::hstring>>;
20using WinrtHstringAbiOut = winrt::impl::arg_out<winrt::hstring>;
21
22struct FFWinrtHstringIterable;
23struct FFWinrtHstringIterator;
24
25struct FFWinrtHstringIterable final : WinrtIterableAbi {
26 std::uint32_t refCount;
27 FFlist strings; // HSTRING
28
29 std::int32_t STDMETHODCALLTYPE QueryInterface(winrt::guid const& riid, void** result) noexcept override;
30 std::uint32_t STDMETHODCALLTYPE AddRef() noexcept override;
31 std::uint32_t STDMETHODCALLTYPE Release() noexcept override;
32 std::int32_t STDMETHODCALLTYPE GetIids(std::uint32_t* count, winrt::guid** iids) noexcept override;
33 std::int32_t STDMETHODCALLTYPE GetRuntimeClassName(void** name) noexcept override;
34 std::int32_t STDMETHODCALLTYPE GetTrustLevel(winrt::Windows::Foundation::TrustLevel* level) noexcept override;
35 std::int32_t STDMETHODCALLTYPE First(void** result) noexcept override;
36};
37
38struct FFWinrtHstringIterator final : WinrtIteratorAbi {
39 std::uint32_t refCount;
40 FFWinrtHstringIterable* owner;
41 std::uint32_t index;
42
43 std::int32_t STDMETHODCALLTYPE QueryInterface(winrt::guid const& riid, void** result) noexcept override;
44 std::uint32_t STDMETHODCALLTYPE AddRef() noexcept override;
45 std::uint32_t STDMETHODCALLTYPE Release() noexcept override;
46 std::int32_t STDMETHODCALLTYPE GetIids(std::uint32_t* count, winrt::guid** iids) noexcept override;
47 std::int32_t STDMETHODCALLTYPE GetRuntimeClassName(void** name) noexcept override;
48 std::int32_t STDMETHODCALLTYPE GetTrustLevel(winrt::Windows::Foundation::TrustLevel* level) noexcept override;
49 std::int32_t STDMETHODCALLTYPE get_Current(WinrtHstringAbiOut value) noexcept override;
50 std::int32_t STDMETHODCALLTYPE get_HasCurrent(bool* value) noexcept override;
51 std::int32_t STDMETHODCALLTYPE MoveNext(bool* value) noexcept override;
52 std::int32_t STDMETHODCALLTYPE GetMany(std::uint32_t capacity, WinrtHstringAbiOut values, std::uint32_t* actual) noexcept override;
53};
54
55// ---------------------------------------------------------------------------------------------
56// IIterable<HSTRING>
57// ---------------------------------------------------------------------------------------------
58
59std::int32_t STDMETHODCALLTYPE FFWinrtHstringIterable::QueryInterface(winrt::guid const& riid, void** result) noexcept {
60 if (!result) {
61 return E_POINTER;
62 }
63 *result = nullptr;
64
65 if (riid == winrt::guid_of<winrt::Windows::Foundation::IUnknown>() ||
66 riid == winrt::guid_of<winrt::Windows::Foundation::IInspectable>() ||
67 riid == winrt::guid_of<winrt::Windows::Foundation::Collections::IIterable<winrt::hstring>>()) {
68 *result = this;
69 AddRef();
70 return S_OK;
71 }
72
73 return E_NOINTERFACE;
74}
75
76std::uint32_t STDMETHODCALLTYPE FFWinrtHstringIterable::AddRef() noexcept {
77 return ++refCount;
78}
79
80std::uint32_t STDMETHODCALLTYPE FFWinrtHstringIterable::Release() noexcept {
81 std::uint32_t remaining = --refCount;
82 if (remaining == 0) {
83 FF_LIST_FOR_EACH(HSTRING, string, strings) {
84 WindowsDeleteString(*string);
85 }
86 ffListDestroy(&strings);
87 this->~FFWinrtHstringIterable();
88 free(this);
89 }
90 return remaining;
91}
92
93std::int32_t STDMETHODCALLTYPE FFWinrtHstringIterable::GetIids(std::uint32_t* count, winrt::guid** iids) noexcept {
94 *count = 0;
95 *iids = nullptr;
96 return S_OK;
97}
98
99std::int32_t STDMETHODCALLTYPE FFWinrtHstringIterable::GetRuntimeClassName(void** name) noexcept {
100 *name = nullptr;
101 return S_OK;
102}
103
104// `level` is the ABI's 32-bit TrustLevel enum; BaseTrust is 0.
105std::int32_t STDMETHODCALLTYPE FFWinrtHstringIterable::GetTrustLevel(winrt::Windows::Foundation::TrustLevel* level) noexcept {
106 *level = winrt::Windows::Foundation::TrustLevel::BaseTrust;
107 return S_OK;
108}
109
110std::int32_t STDMETHODCALLTYPE FFWinrtHstringIterable::First(void** result) noexcept {
111 if (!result) {
112 return E_POINTER;
113 }
114 *result = nullptr;
115
116 auto* iterator = (FFWinrtHstringIterator*) malloc(sizeof(FFWinrtHstringIterator));
117 if (!iterator) {
118 return E_OUTOFMEMORY;
119 }
120
121 ::new (iterator) FFWinrtHstringIterator();
122 iterator->refCount = 1;
123 iterator->owner = this;
124 iterator->index = 0;
125
126 // The iterator outlives the call that created it, so it holds a reference of its own.
127 AddRef();
128
129 *result = iterator;
130 return S_OK;
131}
132
133// ---------------------------------------------------------------------------------------------
134// IIterator<HSTRING>
135// ---------------------------------------------------------------------------------------------
136
137std::int32_t STDMETHODCALLTYPE FFWinrtHstringIterator::QueryInterface(winrt::guid const& riid, void** result) noexcept {
138 if (!result) {
139 return E_POINTER;
140 }
141 *result = nullptr;
142
143 if (riid == winrt::guid_of<winrt::Windows::Foundation::IUnknown>() ||
144 riid == winrt::guid_of<winrt::Windows::Foundation::IInspectable>() ||
145 riid == winrt::guid_of<winrt::Windows::Foundation::Collections::IIterator<winrt::hstring>>()) {
146 *result = this;
147 AddRef();
148 return S_OK;
149 }
150
151 return E_NOINTERFACE;
152}
153
154std::uint32_t STDMETHODCALLTYPE FFWinrtHstringIterator::AddRef() noexcept {
155 return ++refCount;
156}
157
158std::uint32_t STDMETHODCALLTYPE FFWinrtHstringIterator::Release() noexcept {
159 std::uint32_t remaining = --refCount;
160 if (remaining == 0) {
161 owner->Release();
162 this->~FFWinrtHstringIterator();
163 free(this);
164 }
165 return remaining;
166}
167
168std::int32_t STDMETHODCALLTYPE FFWinrtHstringIterator::GetIids(std::uint32_t* count, winrt::guid** iids) noexcept {
169 *count = 0;
170 *iids = nullptr;
171 return S_OK;
172}
173
174std::int32_t STDMETHODCALLTYPE FFWinrtHstringIterator::GetRuntimeClassName(void** name) noexcept {
175 *name = nullptr;
176 return S_OK;
177}
178
179std::int32_t STDMETHODCALLTYPE FFWinrtHstringIterator::GetTrustLevel(winrt::Windows::Foundation::TrustLevel* level) noexcept {
180 *level = winrt::Windows::Foundation::TrustLevel::BaseTrust;
181 return S_OK;
182}
183
184std::int32_t STDMETHODCALLTYPE FFWinrtHstringIterator::get_Current(WinrtHstringAbiOut value) noexcept {
185 if (!value) {
186 return E_POINTER;
187 }
188 *value = nullptr;
189
190 if (index >= owner->strings.length) {
191 return E_BOUNDS;
192 }
193
194 // The caller owns what it gets, so hand out a duplicate rather than the stored string.
195 return WindowsDuplicateString(*(HSTRING*) ffListGet(&owner->strings, sizeof(HSTRING), index), reinterpret_cast<HSTRING*>(value));
196}
197
198std::int32_t STDMETHODCALLTYPE FFWinrtHstringIterator::get_HasCurrent(bool* value) noexcept {
199 if (!value) {
200 return E_POINTER;
201 }
202 *value = index < owner->strings.length;
203 return S_OK;
204}
205
206std::int32_t STDMETHODCALLTYPE FFWinrtHstringIterator::MoveNext(bool* value) noexcept {
207 if (!value) {
208 return E_POINTER;
209 }
210
211 if (index < owner->strings.length) {
212 ++index;
213 }
214 *value = index < owner->strings.length;
215 return S_OK;
216}
217
218std::int32_t STDMETHODCALLTYPE FFWinrtHstringIterator::GetMany(std::uint32_t capacity, WinrtHstringAbiOut values, std::uint32_t* actual) noexcept {
219 if (!actual) {
220 return E_POINTER;
221 }
222 *actual = 0;
223
224 if (capacity && !values) {
225 return E_POINTER;
226 }
227
228 std::uint32_t available = owner->strings.length - index;
229 std::uint32_t taken = capacity < available ? capacity : available;
230 HSTRING* hstrings = reinterpret_cast<HSTRING*>(values);
231
232 for (std::uint32_t i = 0; i < taken; ++i) {
233 HRESULT hr = WindowsDuplicateString(*(HSTRING*) ffListGet(&owner->strings, sizeof(HSTRING), index + i), &hstrings[i]);
234 if (FAILED(hr)) {
235 // Whatever was handed out already belongs to the caller, so a half filled array has to
236 // be taken back before the error goes out: the caller has no way to free a partial one.
237 for (std::uint32_t j = 0; j < i; ++j) {
238 WindowsDeleteString(hstrings[j]);
239 }
240 return hr;
241 }
242 }
243
244 index += taken;
245 *actual = taken;
246
247 return taken == capacity ? S_OK : S_FALSE;
248}
249
250} // namespace
251
252HRESULT ffWinrtCreateHstringIterable(const wchar_t* const* items, uint32_t count, abi_t<winrt::Windows::Foundation::Collections::IIterable<winrt::hstring>>** result) {
253 *result = nullptr;
254
255 if (count > 0 && !items) {
256 return E_INVALIDARG;
257 }
258
259 auto* iterable = (FFWinrtHstringIterable*) malloc(sizeof(FFWinrtHstringIterable));
260 if (!iterable) {
261 return E_OUTOFMEMORY;
262 }
263
264 ::new (iterable) FFWinrtHstringIterable();
265 iterable->refCount = 1;
266 ffListInitA(&iterable->strings, sizeof(HSTRING), count > 0 ? count : FF_LIST_DEFAULT_ALLOC);
267
268 for (uint32_t i = 0; i < count; ++i) {
269 HSTRING* slot = (HSTRING*) ffListAdd(&iterable->strings, sizeof(HSTRING));
270 // ffListAdd does not zero the slot it hands out, and Release() walks every one of them, so
271 // the slot has to hold a usable HSTRING before WindowsCreateString gets a chance to fail.
272 *slot = nullptr;
273 HRESULT hr = WindowsCreateString(items[i], (UINT32) ::wcslen(items[i]), slot);
274 if (FAILED(hr)) {
275 iterable->Release();
276 return hr;
277 }
278 }
279
280 *result = static_cast<WinrtIterableAbi*>(iterable);
281 return S_OK;
282}
283
284#endif // FF_HAVE_WINRT