#include #include #include #include #include #include #include template struct FFBaseVariant : TVariant { bool hasValue() { return this->vt != VT_EMPTY; } explicit operator bool() { return this->hasValue(); } template T get() { // boolean if constexpr (std::is_same_v) { assert(this->vt == VT_BOOL); return this->boolVal != VARIANT_FALSE; } // signed else if constexpr (std::is_same_v) { assert(this->vt == VT_I1); return this->cVal; } else if constexpr (std::is_same_v) { assert(this->vt == VT_I2); return this->iVal; } else if constexpr (std::is_same_v) { assert(this->vt == VT_I4 || this->vt == VT_INT); return this->intVal; } else if constexpr (std::is_same_v) { assert(this->vt == VT_I8); return this->llVal; } // unsigned else if constexpr (std::is_same_v) { assert(this->vt == VT_UI1); return this->bVal; } else if constexpr (std::is_same_v) { assert(this->vt == VT_UI2); return this->uiVal; } else if constexpr (std::is_same_v) { assert(this->vt == VT_UI4 || this->vt == VT_UINT); return this->uintVal; } else if constexpr (std::is_same_v) { assert(this->vt == VT_UI8); return this->ullVal; } // decimal else if constexpr (std::is_same_v) { assert(this->vt == VT_R4); return this->fltVal; } else if constexpr (std::is_same_v) { assert(this->vt == VT_R8); return this->dblVal; } // string else if constexpr (std::is_same_v) { assert(this->vt == VT_LPSTR); return this->pcVal; } else if constexpr (std::is_same_v) { 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>) { 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>) { 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>) { 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>) { 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>) { 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>) { 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>) { 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>) { 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 { FFWmiVariant(const FFWmiVariant&) = delete; FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization explicit FFWmiVariant() { VariantInit(this); } explicit FFWmiVariant(std::initializer_list strings); ~FFWmiVariant() { VariantClear(this); } }; static_assert(sizeof(FFWmiVariant) == sizeof(VARIANT), ""); struct FFPropVariant : FFBaseVariant { 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