summaryrefslogtreecommitdiffstats
path: root/src/common/windows/variant.hpp
diff options
context:
space:
mode:
authorsumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
committersumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
commit76424950e373d3b04ac3dd13019151bfba3e8423 (patch)
tree4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/common/windows/variant.hpp
Add the files
Diffstat (limited to 'src/common/windows/variant.hpp')
-rw-r--r--src/common/windows/variant.hpp164
1 files changed, 164 insertions, 0 deletions
diff --git a/src/common/windows/variant.hpp b/src/common/windows/variant.hpp
new file mode 100644
index 0000000..58e46b7
--- /dev/null
+++ b/src/common/windows/variant.hpp
@@ -0,0 +1,164 @@
+#include <oaidl.h>
+#include <propidl.h>
+#include <type_traits>
+#include <utility>
+#include <string_view>
+#include <cassert>
+#include <cstdint>
+
+template <typename TVariant>
+struct FFBaseVariant : TVariant {
+ bool hasValue() {
+ return this->vt != VT_EMPTY;
+ }
+
+ explicit operator bool() {
+ return this->hasValue();
+ }
+
+ template <typename T>
+ T get() {
+ // boolean
+ if constexpr (std::is_same_v<T, bool>) {
+ assert(this->vt == VT_BOOL);
+ return this->boolVal != VARIANT_FALSE;
+ }
+
+ // signed
+ else if constexpr (std::is_same_v<T, int8_t>) {
+ assert(this->vt == VT_I1);
+ return this->cVal;
+ } else if constexpr (std::is_same_v<T, int16_t>) {
+ assert(this->vt == VT_I2);
+ return this->iVal;
+ } else if constexpr (std::is_same_v<T, int32_t>) {
+ assert(this->vt == VT_I4 || this->vt == VT_INT);
+ return this->intVal;
+ } else if constexpr (std::is_same_v<T, int64_t>) {
+ assert(this->vt == VT_I8);
+ return this->llVal;
+ }
+
+ // unsigned
+ else if constexpr (std::is_same_v<T, uint8_t>) {
+ assert(this->vt == VT_UI1);
+ return this->bVal;
+ } else if constexpr (std::is_same_v<T, uint16_t>) {
+ assert(this->vt == VT_UI2);
+ return this->uiVal;
+ } else if constexpr (std::is_same_v<T, uint32_t>) {
+ assert(this->vt == VT_UI4 || this->vt == VT_UINT);
+ return this->uintVal;
+ } else if constexpr (std::is_same_v<T, uint64_t>) {
+ assert(this->vt == VT_UI8);
+ return this->ullVal;
+ }
+
+ // decimal
+ else if constexpr (std::is_same_v<T, float>) {
+ assert(this->vt == VT_R4);
+ return this->fltVal;
+ } else if constexpr (std::is_same_v<T, double>) {
+ assert(this->vt == VT_R8);
+ return this->dblVal;
+ }
+
+ // string
+ else if constexpr (std::is_same_v<T, std::string_view>) {
+ assert(this->vt == VT_LPSTR);
+ return this->pcVal;
+ } else if constexpr (std::is_same_v<T, std::wstring_view>) {
+ assert(this->vt == VT_BSTR || this->vt == VT_LPWSTR);
+ if (this->vt == VT_LPWSTR) {
+ return this->bstrVal;
+ } else {
+ return { this->bstrVal, SysStringLen(this->bstrVal) };
+ }
+ }
+
+ // array signed
+ else if constexpr (std::is_same_v<T, std::pair<const int8_t*, uint32_t>>) {
+ assert(this->vt & VT_ARRAY);
+ assert((this->vt & ~VT_ARRAY) == VT_I1);
+ return std::make_pair((int8_t*) this->parray->pvData, this->parray->cDims);
+ } else if constexpr (std::is_same_v<T, std::pair<const int16_t*, uint32_t>>) {
+ assert(this->vt & VT_ARRAY);
+ assert((this->vt & ~VT_ARRAY) == VT_I2);
+ return std::make_pair((int16_t*) this->parray->pvData, this->parray->cDims);
+ } else if constexpr (std::is_same_v<T, std::pair<const int32_t*, uint32_t>>) {
+ assert(this->vt & VT_ARRAY);
+ assert((this->vt & ~VT_ARRAY) == VT_I4);
+ return std::make_pair((int32_t*) this->parray->pvData, this->parray->cDims);
+ } else if constexpr (std::is_same_v<T, std::pair<const int64_t*, uint32_t>>) {
+ assert(this->vt & VT_ARRAY);
+ assert((this->vt & ~VT_ARRAY) == VT_I8);
+ return std::make_pair((int64_t*) this->parray->pvData, this->parray->cDims);
+ }
+
+ // array unsigned
+ else if constexpr (std::is_same_v<T, std::pair<const uint8_t*, uint32_t>>) {
+ assert(this->vt & VT_ARRAY);
+ assert((this->vt & ~VT_ARRAY) == VT_UI1);
+ return std::make_pair((uint8_t*) this->parray->pvData, this->parray->cDims);
+ } else if constexpr (std::is_same_v<T, std::pair<const uint16_t*, uint32_t>>) {
+ assert(this->vt & VT_ARRAY);
+ assert((this->vt & ~VT_ARRAY) == VT_UI2);
+ return std::make_pair((uint16_t*) this->parray->pvData, this->parray->cDims);
+ } else if constexpr (std::is_same_v<T, std::pair<const uint32_t*, uint32_t>>) {
+ assert(this->vt & VT_ARRAY);
+ assert((this->vt & ~VT_ARRAY) == VT_UI4);
+ return std::make_pair((uint32_t*) this->parray->pvData, this->parray->cDims);
+ } else if constexpr (std::is_same_v<T, std::pair<const uint64_t*, uint32_t>>) {
+ assert(this->vt & VT_ARRAY);
+ assert((this->vt & ~VT_ARRAY) == VT_UI8);
+ return std::make_pair((uint64_t*) this->parray->pvData, this->parray->cDims);
+ } else {
+ assert(false && "unsupported type");
+ __builtin_unreachable();
+ }
+ }
+};
+
+struct FFWmiVariant : FFBaseVariant<VARIANT> {
+ FFWmiVariant(const FFWmiVariant&) = delete;
+ FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization
+ explicit FFWmiVariant() {
+ VariantInit(this);
+ }
+ explicit FFWmiVariant(std::initializer_list<PCWSTR> strings);
+ ~FFWmiVariant() {
+ VariantClear(this);
+ }
+};
+static_assert(sizeof(FFWmiVariant) == sizeof(VARIANT), "");
+
+struct FFPropVariant : FFBaseVariant<PROPVARIANT> {
+ FFPropVariant(const FFPropVariant&) = delete;
+ FFPropVariant(FFPropVariant&&); // don't define it to enforce NRVO optimization
+ explicit FFPropVariant() {
+ PropVariantInit(this);
+ }
+ ~FFPropVariant() {
+ PropVariantClear(this);
+ }
+};
+static_assert(sizeof(FFPropVariant) == sizeof(PROPVARIANT), "");
+
+namespace {
+// Provide our bstr_t to avoid libstdc++ dependency
+struct bstr_t {
+ explicit bstr_t(const wchar_t* str) noexcept : _bstr(SysAllocString(str)) {}
+ ~bstr_t(void) noexcept {
+ SysFreeString(_bstr);
+ }
+ explicit operator const wchar_t*(void) const noexcept {
+ return _bstr;
+ }
+ operator BSTR(void) const noexcept {
+ return _bstr;
+ }
+
+ private:
+ BSTR _bstr;
+};
+} // namespace