ohmu
·
2026-10-15
1#include <oaidl.h>
2#include <propidl.h>
3#include <type_traits>
4#include <utility>
5#include <string_view>
6#include <cassert>
7#include <cstdint>
8
9template <typename TVariant>
10struct FFBaseVariant : TVariant {
11 bool hasValue() {
12 return this->vt != VT_EMPTY;
13 }
14
15 explicit operator bool() {
16 return this->hasValue();
17 }
18
19 template <typename T>
20 T get() {
21 // boolean
22 if constexpr (std::is_same_v<T, bool>) {
23 assert(this->vt == VT_BOOL);
24 return this->boolVal != VARIANT_FALSE;
25 }
26
27 // signed
28 else if constexpr (std::is_same_v<T, int8_t>) {
29 assert(this->vt == VT_I1);
30 return this->cVal;
31 } else if constexpr (std::is_same_v<T, int16_t>) {
32 assert(this->vt == VT_I2);
33 return this->iVal;
34 } else if constexpr (std::is_same_v<T, int32_t>) {
35 assert(this->vt == VT_I4 || this->vt == VT_INT);
36 return this->intVal;
37 } else if constexpr (std::is_same_v<T, int64_t>) {
38 assert(this->vt == VT_I8);
39 return this->llVal;
40 }
41
42 // unsigned
43 else if constexpr (std::is_same_v<T, uint8_t>) {
44 assert(this->vt == VT_UI1);
45 return this->bVal;
46 } else if constexpr (std::is_same_v<T, uint16_t>) {
47 assert(this->vt == VT_UI2);
48 return this->uiVal;
49 } else if constexpr (std::is_same_v<T, uint32_t>) {
50 assert(this->vt == VT_UI4 || this->vt == VT_UINT);
51 return this->uintVal;
52 } else if constexpr (std::is_same_v<T, uint64_t>) {
53 assert(this->vt == VT_UI8);
54 return this->ullVal;
55 }
56
57 // decimal
58 else if constexpr (std::is_same_v<T, float>) {
59 assert(this->vt == VT_R4);
60 return this->fltVal;
61 } else if constexpr (std::is_same_v<T, double>) {
62 assert(this->vt == VT_R8);
63 return this->dblVal;
64 }
65
66 // string
67 else if constexpr (std::is_same_v<T, std::string_view>) {
68 assert(this->vt == VT_LPSTR);
69 return this->pcVal;
70 } else if constexpr (std::is_same_v<T, std::wstring_view>) {
71 assert(this->vt == VT_BSTR || this->vt == VT_LPWSTR);
72 if (this->vt == VT_LPWSTR) {
73 return this->bstrVal;
74 } else {
75 return { this->bstrVal, SysStringLen(this->bstrVal) };
76 }
77 }
78
79 // array signed
80 else if constexpr (std::is_same_v<T, std::pair<const int8_t*, uint32_t>>) {
81 assert(this->vt & VT_ARRAY);
82 assert((this->vt & ~VT_ARRAY) == VT_I1);
83 return std::make_pair((int8_t*) this->parray->pvData, this->parray->cDims);
84 } else if constexpr (std::is_same_v<T, std::pair<const int16_t*, uint32_t>>) {
85 assert(this->vt & VT_ARRAY);
86 assert((this->vt & ~VT_ARRAY) == VT_I2);
87 return std::make_pair((int16_t*) this->parray->pvData, this->parray->cDims);
88 } else if constexpr (std::is_same_v<T, std::pair<const int32_t*, uint32_t>>) {
89 assert(this->vt & VT_ARRAY);
90 assert((this->vt & ~VT_ARRAY) == VT_I4);
91 return std::make_pair((int32_t*) this->parray->pvData, this->parray->cDims);
92 } else if constexpr (std::is_same_v<T, std::pair<const int64_t*, uint32_t>>) {
93 assert(this->vt & VT_ARRAY);
94 assert((this->vt & ~VT_ARRAY) == VT_I8);
95 return std::make_pair((int64_t*) this->parray->pvData, this->parray->cDims);
96 }
97
98 // array unsigned
99 else if constexpr (std::is_same_v<T, std::pair<const uint8_t*, uint32_t>>) {
100 assert(this->vt & VT_ARRAY);
101 assert((this->vt & ~VT_ARRAY) == VT_UI1);
102 return std::make_pair((uint8_t*) this->parray->pvData, this->parray->cDims);
103 } else if constexpr (std::is_same_v<T, std::pair<const uint16_t*, uint32_t>>) {
104 assert(this->vt & VT_ARRAY);
105 assert((this->vt & ~VT_ARRAY) == VT_UI2);
106 return std::make_pair((uint16_t*) this->parray->pvData, this->parray->cDims);
107 } else if constexpr (std::is_same_v<T, std::pair<const uint32_t*, uint32_t>>) {
108 assert(this->vt & VT_ARRAY);
109 assert((this->vt & ~VT_ARRAY) == VT_UI4);
110 return std::make_pair((uint32_t*) this->parray->pvData, this->parray->cDims);
111 } else if constexpr (std::is_same_v<T, std::pair<const uint64_t*, uint32_t>>) {
112 assert(this->vt & VT_ARRAY);
113 assert((this->vt & ~VT_ARRAY) == VT_UI8);
114 return std::make_pair((uint64_t*) this->parray->pvData, this->parray->cDims);
115 } else {
116 assert(false && "unsupported type");
117 __builtin_unreachable();
118 }
119 }
120};
121
122struct FFWmiVariant : FFBaseVariant<VARIANT> {
123 FFWmiVariant(const FFWmiVariant&) = delete;
124 FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization
125 explicit FFWmiVariant() {
126 VariantInit(this);
127 }
128 explicit FFWmiVariant(std::initializer_list<PCWSTR> strings);
129 ~FFWmiVariant() {
130 VariantClear(this);
131 }
132};
133static_assert(sizeof(FFWmiVariant) == sizeof(VARIANT), "");
134
135struct FFPropVariant : FFBaseVariant<PROPVARIANT> {
136 FFPropVariant(const FFPropVariant&) = delete;
137 FFPropVariant(FFPropVariant&&); // don't define it to enforce NRVO optimization
138 explicit FFPropVariant() {
139 PropVariantInit(this);
140 }
141 ~FFPropVariant() {
142 PropVariantClear(this);
143 }
144};
145static_assert(sizeof(FFPropVariant) == sizeof(PROPVARIANT), "");
146
147namespace {
148// Provide our bstr_t to avoid libstdc++ dependency
149struct bstr_t {
150 explicit bstr_t(const wchar_t* str) noexcept : _bstr(SysAllocString(str)) {}
151 ~bstr_t(void) noexcept {
152 SysFreeString(_bstr);
153 }
154 explicit operator const wchar_t*(void) const noexcept {
155 return _bstr;
156 }
157 operator BSTR(void) const noexcept {
158 return _bstr;
159 }
160
161 private:
162 BSTR _bstr;
163};
164} // namespace