COM: Add helper for SAFEARRAY creation

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2025-01-15 15:00:25 +01:00
parent b0cf45a0f1
commit f33010e6b6

View File

@ -34,7 +34,8 @@ namespace winstd
/// \param[in] msg Error message /// \param[in] msg Error message
/// ///
com_runtime_error(_In_ error_type num, _In_ const std::string& msg) : num_runtime_error<HRESULT>(num, msg) com_runtime_error(_In_ error_type num, _In_ const std::string& msg) : num_runtime_error<HRESULT>(num, msg)
{} {
}
/// ///
/// Constructs an exception /// Constructs an exception
@ -42,8 +43,9 @@ namespace winstd
/// \param[in] num COM error code /// \param[in] num COM error code
/// \param[in] msg Error message /// \param[in] msg Error message
/// ///
com_runtime_error(_In_ error_type num, _In_opt_z_ const char *msg = nullptr) : num_runtime_error<HRESULT>(num, msg) com_runtime_error(_In_ error_type num, _In_opt_z_ const char* msg = nullptr) : num_runtime_error<HRESULT>(num, msg)
{} {
}
}; };
/// @} /// @}
@ -67,7 +69,7 @@ namespace winstd
/// \sa [CoTaskMemFree function](https://docs.microsoft.com/en-us/windows/desktop/api/combaseapi/nf-combaseapi-cotaskmemfree) /// \sa [CoTaskMemFree function](https://docs.microsoft.com/en-us/windows/desktop/api/combaseapi/nf-combaseapi-cotaskmemfree)
/// ///
template <class _T> template <class _T>
void operator()(_T *_Ptr) const void operator()(_T* _Ptr) const
{ {
CoTaskMemFree(_Ptr); CoTaskMemFree(_Ptr);
} }
@ -105,7 +107,7 @@ namespace winstd
/// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx)
/// ///
template <class _Other> template <class _Other>
com_obj(_In_ _Other *other) com_obj(_In_ _Other* other)
{ {
assert(other); assert(other);
HRESULT hr = other->QueryInterface(__uuidof(T), (void**)&m_h); HRESULT hr = other->QueryInterface(__uuidof(T), (void**)&m_h);
@ -119,7 +121,7 @@ namespace winstd
/// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx)
/// ///
template <class _Other> template <class _Other>
com_obj(_In_ com_obj<_Other> &other) com_obj(_In_ com_obj<_Other>& other)
{ {
HRESULT hr = other->QueryInterface(__uuidof(T), (void**)&m_h); HRESULT hr = other->QueryInterface(__uuidof(T), (void**)&m_h);
if (FAILED(hr)) if (FAILED(hr))
@ -141,7 +143,7 @@ namespace winstd
/// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx)
/// ///
template <class _Other> template <class _Other>
HRESULT query_interface(_Out_ _Other **h) const HRESULT query_interface(_Out_ _Other** h) const
{ {
assert(h); assert(h);
assert(m_h); assert(m_h);
@ -154,10 +156,10 @@ namespace winstd
/// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx)
/// ///
template <class _Other> template <class _Other>
HRESULT query_interface(_Out_ com_obj<_Other> &h) const HRESULT query_interface(_Out_ com_obj<_Other>& h) const
{ {
assert(m_h); assert(m_h);
_Other *_h; _Other* _h;
HRESULT hr = m_h->QueryInterface(__uuidof(_Other), (void**)&_h); HRESULT hr = m_h->QueryInterface(__uuidof(_Other), (void**)&_h);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
h.attach(_h); h.attach(_h);
@ -223,7 +225,7 @@ namespace winstd
/// Constructs BSTR from std::basic_string /// Constructs BSTR from std::basic_string
/// ///
template<class _Traits, class _Ax> template<class _Traits, class _Ax>
bstr(_In_ const std::basic_string<OLECHAR, _Traits, _Ax> &src) bstr(_In_ const std::basic_string<OLECHAR, _Traits, _Ax>& src)
{ {
size_t len = src.length(); size_t len = src.length();
if (len > UINT_MAX) if (len > UINT_MAX)
@ -286,8 +288,8 @@ namespace winstd
/// ///
/// VARIANT struct wrapper /// VARIANT struct wrapper
/// ///
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 26432) // Copy constructor and assignment operator are also present, but not detected by code analysis as they are using base type source object reference. #pragma warning(disable: 26432) // Copy constructor and assignment operator are also present, but not detected by code analysis as they are using base type source object reference.
class variant : public VARIANT class variant : public VARIANT
{ {
public: public:
@ -313,7 +315,7 @@ namespace winstd
/// ///
/// Moves VARIANT from another /// Moves VARIANT from another
/// ///
#pragma warning(suppress: 26495) // vt member is initialized as a result of memcpy() #pragma warning(suppress: 26495) // vt member is initialized as a result of memcpy()
variant(_Inout_ VARIANT&& varSrc) noexcept variant(_Inout_ VARIANT&& varSrc) noexcept
{ {
memcpy(this, &varSrc, sizeof(VARIANT)); memcpy(this, &varSrc, sizeof(VARIANT));
@ -382,7 +384,7 @@ namespace winstd
{ {
assert(vtSrc == VT_UI4 || vtSrc == VT_UINT); assert(vtSrc == VT_UI4 || vtSrc == VT_UINT);
vt = vtSrc; vt = vtSrc;
uintVal= nSrc; uintVal = nSrc;
} }
/// ///
@ -496,7 +498,7 @@ namespace winstd
/// ///
/// Constructs VARIANT from SAFEARRAY /// Constructs VARIANT from SAFEARRAY
/// ///
variant(_In_ const SAFEARRAY *pSrc) variant(_In_ const SAFEARRAY* pSrc)
{ {
assert(pSrc != NULL); assert(pSrc != NULL);
@ -631,7 +633,7 @@ namespace winstd
VariantClear(this); VariantClear(this);
vt = VT_UI4; vt = VT_UI4;
} }
uintVal= nSrc; uintVal = nSrc;
return *this; return *this;
} }
@ -770,9 +772,9 @@ namespace winstd
/// ///
variant& operator=(_In_ unsigned char* pbSrc) noexcept variant& operator=(_In_ unsigned char* pbSrc) noexcept
{ {
if (vt != (VT_UI1|VT_BYREF)) { if (vt != (VT_UI1 | VT_BYREF)) {
VariantClear(this); VariantClear(this);
vt = VT_UI1|VT_BYREF; vt = VT_UI1 | VT_BYREF;
} }
pbVal = pbSrc; pbVal = pbSrc;
return *this; return *this;
@ -783,9 +785,9 @@ namespace winstd
/// ///
variant& operator=(_In_ short* pnSrc) noexcept variant& operator=(_In_ short* pnSrc) noexcept
{ {
if (vt != (VT_I2|VT_BYREF)) { if (vt != (VT_I2 | VT_BYREF)) {
VariantClear(this); VariantClear(this);
vt = VT_I2|VT_BYREF; vt = VT_I2 | VT_BYREF;
} }
piVal = pnSrc; piVal = pnSrc;
return *this; return *this;
@ -796,9 +798,9 @@ namespace winstd
/// ///
variant& operator=(_In_ unsigned short* pnSrc) noexcept variant& operator=(_In_ unsigned short* pnSrc) noexcept
{ {
if (vt != (VT_UI2|VT_BYREF)) { if (vt != (VT_UI2 | VT_BYREF)) {
VariantClear(this); VariantClear(this);
vt = VT_UI2|VT_BYREF; vt = VT_UI2 | VT_BYREF;
} }
puiVal = pnSrc; puiVal = pnSrc;
return *this; return *this;
@ -809,9 +811,9 @@ namespace winstd
/// ///
variant& operator=(_In_ int* pnSrc) noexcept variant& operator=(_In_ int* pnSrc) noexcept
{ {
if (vt != (VT_I4|VT_BYREF)) { if (vt != (VT_I4 | VT_BYREF)) {
VariantClear(this); VariantClear(this);
vt = VT_I4|VT_BYREF; vt = VT_I4 | VT_BYREF;
} }
pintVal = pnSrc; pintVal = pnSrc;
return *this; return *this;
@ -822,9 +824,9 @@ namespace winstd
/// ///
variant& operator=(_In_ unsigned int* pnSrc) noexcept variant& operator=(_In_ unsigned int* pnSrc) noexcept
{ {
if (vt != (VT_UI4|VT_BYREF)) { if (vt != (VT_UI4 | VT_BYREF)) {
VariantClear(this); VariantClear(this);
vt = VT_UI4|VT_BYREF; vt = VT_UI4 | VT_BYREF;
} }
puintVal = pnSrc; puintVal = pnSrc;
return *this; return *this;
@ -835,9 +837,9 @@ namespace winstd
/// ///
variant& operator=(_In_ long* pnSrc) noexcept variant& operator=(_In_ long* pnSrc) noexcept
{ {
if (vt != (VT_I4|VT_BYREF)) { if (vt != (VT_I4 | VT_BYREF)) {
VariantClear(this); VariantClear(this);
vt = VT_I4|VT_BYREF; vt = VT_I4 | VT_BYREF;
} }
plVal = pnSrc; plVal = pnSrc;
return *this; return *this;
@ -848,9 +850,9 @@ namespace winstd
/// ///
variant& operator=(_In_ unsigned long* pnSrc) noexcept variant& operator=(_In_ unsigned long* pnSrc) noexcept
{ {
if (vt != (VT_UI4|VT_BYREF)) { if (vt != (VT_UI4 | VT_BYREF)) {
VariantClear(this); VariantClear(this);
vt = VT_UI4|VT_BYREF; vt = VT_UI4 | VT_BYREF;
} }
pulVal = pnSrc; pulVal = pnSrc;
return *this; return *this;
@ -861,9 +863,9 @@ namespace winstd
/// ///
variant& operator=(_In_ long long* pnSrc) noexcept variant& operator=(_In_ long long* pnSrc) noexcept
{ {
if (vt != (VT_I8|VT_BYREF)) { if (vt != (VT_I8 | VT_BYREF)) {
VariantClear(this); VariantClear(this);
vt = VT_I8|VT_BYREF; vt = VT_I8 | VT_BYREF;
} }
pllVal = pnSrc; pllVal = pnSrc;
return *this; return *this;
@ -874,9 +876,9 @@ namespace winstd
/// ///
variant& operator=(_In_ unsigned long long* pnSrc) noexcept variant& operator=(_In_ unsigned long long* pnSrc) noexcept
{ {
if (vt != (VT_UI8|VT_BYREF)) { if (vt != (VT_UI8 | VT_BYREF)) {
VariantClear(this); VariantClear(this);
vt = VT_UI8|VT_BYREF; vt = VT_UI8 | VT_BYREF;
} }
pullVal = pnSrc; pullVal = pnSrc;
return *this; return *this;
@ -887,9 +889,9 @@ namespace winstd
/// ///
variant& operator=(_In_ float* pfSrc) noexcept variant& operator=(_In_ float* pfSrc) noexcept
{ {
if (vt != (VT_R4|VT_BYREF)) { if (vt != (VT_R4 | VT_BYREF)) {
VariantClear(this); VariantClear(this);
vt = VT_R4|VT_BYREF; vt = VT_R4 | VT_BYREF;
} }
pfltVal = pfSrc; pfltVal = pfSrc;
return *this; return *this;
@ -900,9 +902,9 @@ namespace winstd
/// ///
variant& operator=(_In_ double* pfSrc) noexcept variant& operator=(_In_ double* pfSrc) noexcept
{ {
if (vt != (VT_R8|VT_BYREF)) { if (vt != (VT_R8 | VT_BYREF)) {
VariantClear(this); VariantClear(this);
vt = VT_R8|VT_BYREF; vt = VT_R8 | VT_BYREF;
} }
pdblVal = pfSrc; pdblVal = pfSrc;
return *this; return *this;
@ -911,7 +913,7 @@ namespace winstd
/// ///
/// Copy from SAFEARRAY /// Copy from SAFEARRAY
/// ///
variant& operator=(_In_ const SAFEARRAY *pSrc) variant& operator=(_In_ const SAFEARRAY* pSrc)
{ {
assert(pSrc != NULL); assert(pSrc != NULL);
VariantClear(this); VariantClear(this);
@ -967,7 +969,7 @@ namespace winstd
bool operator<(_In_ const VARIANT& varSrc) const noexcept bool operator<(_In_ const VARIANT& varSrc) const noexcept
{ {
if (vt == VT_NULL && varSrc.vt == VT_NULL) return false; if (vt == VT_NULL && varSrc.vt == VT_NULL) return false;
return compare(static_cast<const VARIANT&>(*this), varSrc, LOCALE_USER_DEFAULT, 0)== static_cast<HRESULT>(VARCMP_LT); return compare(static_cast<const VARIANT&>(*this), varSrc, LOCALE_USER_DEFAULT, 0) == static_cast<HRESULT>(VARCMP_LT);
} }
/// ///
@ -981,7 +983,7 @@ namespace winstd
bool operator>(_In_ const VARIANT& varSrc) const noexcept bool operator>(_In_ const VARIANT& varSrc) const noexcept
{ {
if (vt == VT_NULL && varSrc.vt == VT_NULL) return false; if (vt == VT_NULL && varSrc.vt == VT_NULL) return false;
return compare(static_cast<const VARIANT&>(*this), varSrc, LOCALE_USER_DEFAULT, 0)== static_cast<HRESULT>(VARCMP_GT); return compare(static_cast<const VARIANT&>(*this), varSrc, LOCALE_USER_DEFAULT, 0) == static_cast<HRESULT>(VARCMP_GT);
} }
/// ///
@ -1022,19 +1024,19 @@ namespace winstd
private: private:
/// \cond internal /// \cond internal
HRESULT compare(_In_ const VARIANT &varLeft, _In_ const VARIANT &varRight, _In_ LCID lcid, _In_ ULONG dwFlags) const noexcept HRESULT compare(_In_ const VARIANT& varLeft, _In_ const VARIANT& varRight, _In_ LCID lcid, _In_ ULONG dwFlags) const noexcept
{ {
switch(vt) { switch (vt) {
case VT_I1: return varLeft.cVal == varRight.cVal ? VARCMP_EQ : varLeft.cVal > varRight.cVal ? VARCMP_GT : VARCMP_LT; case VT_I1: return varLeft.cVal == varRight.cVal ? VARCMP_EQ : varLeft.cVal > varRight.cVal ? VARCMP_GT : VARCMP_LT;
case VT_UI2: return varLeft.uiVal == varRight.uiVal ? VARCMP_EQ : varLeft.uiVal > varRight.uiVal ? VARCMP_GT : VARCMP_LT; case VT_UI2: return varLeft.uiVal == varRight.uiVal ? VARCMP_EQ : varLeft.uiVal > varRight.uiVal ? VARCMP_GT : VARCMP_LT;
case VT_UI4: return varLeft.uintVal == varRight.uintVal ? VARCMP_EQ : varLeft.uintVal > varRight.uintVal ? VARCMP_GT : VARCMP_LT; case VT_UI4: return varLeft.uintVal == varRight.uintVal ? VARCMP_EQ : varLeft.uintVal > varRight.uintVal ? VARCMP_GT : VARCMP_LT;
case VT_UI8: return varLeft.ullVal == varRight.ullVal ? VARCMP_EQ : varLeft.ullVal > varRight.ullVal ? VARCMP_GT : VARCMP_LT; case VT_UI8: return varLeft.ullVal == varRight.ullVal ? VARCMP_EQ : varLeft.ullVal > varRight.ullVal ? VARCMP_GT : VARCMP_LT;
default: return VarCmp(const_cast<LPVARIANT>(&varLeft), const_cast<LPVARIANT>(&varRight), lcid, dwFlags); default: return VarCmp(const_cast<LPVARIANT>(&varLeft), const_cast<LPVARIANT>(&varRight), lcid, dwFlags);
} }
} }
/// \endcond /// \endcond
}; };
#pragma warning(pop) #pragma warning(pop)
/// ///
/// SAFEARRAY string wrapper /// SAFEARRAY string wrapper
@ -1092,7 +1094,7 @@ namespace winstd
class safearray_accessor class safearray_accessor
{ {
WINSTD_NONCOPYABLE(safearray_accessor) WINSTD_NONCOPYABLE(safearray_accessor)
WINSTD_NONMOVABLE(safearray_accessor) WINSTD_NONMOVABLE(safearray_accessor)
public: public:
/// ///
@ -1102,7 +1104,7 @@ namespace winstd
/// ///
safearray_accessor(_In_ SAFEARRAY* psa) : m_sa(psa) safearray_accessor(_In_ SAFEARRAY* psa) : m_sa(psa)
{ {
HRESULT hr = SafeArrayAccessData(psa, (void HUGEP**)&m_data); HRESULT hr = SafeArrayAccessData(psa, (void HUGEP**) & m_data);
if (FAILED(hr)) if (FAILED(hr))
throw com_runtime_error(hr, "SafeArrayAccessData failed"); throw com_runtime_error(hr, "SafeArrayAccessData failed");
} }
@ -1136,7 +1138,7 @@ namespace winstd
class com_initializer class com_initializer
{ {
WINSTD_NONCOPYABLE(com_initializer) WINSTD_NONCOPYABLE(com_initializer)
WINSTD_NONMOVABLE(com_initializer) WINSTD_NONMOVABLE(com_initializer)
public: public:
/// ///
@ -1186,7 +1188,7 @@ namespace winstd
/// \sa [CoCreateInstance function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686615.aspx) /// \sa [CoCreateInstance function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686615.aspx)
/// ///
template <class T> template <class T>
static _Check_return_ HRESULT CoCreateInstance(_In_ REFCLSID rclsid, _In_opt_ LPUNKNOWN pUnkOuter, _In_ DWORD dwClsContext, _Inout_ winstd::com_obj<T> &v) static _Check_return_ HRESULT CoCreateInstance(_In_ REFCLSID rclsid, _In_opt_ LPUNKNOWN pUnkOuter, _In_ DWORD dwClsContext, _Inout_ winstd::com_obj<T>& v)
{ {
T* ppv; T* ppv;
HRESULT hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (LPVOID*)&ppv); HRESULT hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (LPVOID*)&ppv);
@ -1460,6 +1462,58 @@ namespace winstd
/// \addtogroup WinStdCOMHelpers /// \addtogroup WinStdCOMHelpers
/// @{ /// @{
///
/// Builds SAFEARRAY of uniform data
///
/// \param[in] vt Type of array element
/// \param[in] array Pointer to data
/// \param[in] columns Number of columns. When 1, SafeArrayCreateVector is used; when >1, SafeArrayCreate is used.
/// \param[in] rows Number of rows
///
/// \return Returns SAFEARRAY
///
inline _Ret_notnull_ LPSAFEARRAY BuildSAFEARRAY(_In_ VARTYPE vt, _In_opt_ LPCVOID array, _In_ ULONG columns, _In_ ULONG rows)
{
const size_t n = columns * rows;
if (!array && n)
throw std::invalid_argument("array is NULL");
safearray sa;
if (columns == 1) {
// Make vector when one column only.
sa = SafeArrayCreateVector(vt, 0, rows);
}
else {
// Make 2-dimensional array when more columns.
SAFEARRAYBOUND dim[2] = {
{ columns, 0 },
{ rows, 0 }
};
sa = SafeArrayCreate(vt, 2, dim);
}
if (!sa)
throw std::bad_alloc();
size_t elem_size;
switch (vt) {
case VT_UI4:
case VT_I4: elem_size = 4; break;
case VT_UI2:
case VT_I2:
case VT_BOOL: elem_size = 2; break;
case VT_UI1:
case VT_I1: elem_size = 1; break;
default: throw std::invalid_argument("unsupported type");
};
{
safearray_accessor<void> saa(sa);
memcpy(saa.data(), array, elem_size * n);
}
return sa.detach();
}
/// ///
/// Builds VBARRAY of uniform data /// Builds VBARRAY of uniform data
/// ///
@ -1476,7 +1530,7 @@ namespace winstd
if (!array && n) if (!array && n)
throw std::invalid_argument("array is NULL"); throw std::invalid_argument("array is NULL");
LPSAFEARRAY sa; safearray sa;
if (columns == 1) { if (columns == 1) {
// Make vector when one column only. // Make vector when one column only.
sa = SafeArrayCreateVector(VT_VARIANT, 0, rows); sa = SafeArrayCreateVector(VT_VARIANT, 0, rows);
@ -1536,7 +1590,7 @@ namespace winstd
VARIANT var; VARIANT var;
V_VT(&var) = VT_ARRAY | VT_VARIANT; V_VT(&var) = VT_ARRAY | VT_VARIANT;
V_ARRAY(&var) = sa; V_ARRAY(&var) = sa.detach();
return var; return var;
} }
@ -1560,7 +1614,7 @@ namespace winstd
if (!array && rows) if (!array && rows)
throw std::invalid_argument("array is NULL"); throw std::invalid_argument("array is NULL");
LPSAFEARRAY sa; safearray sa;
if constexpr (columns == 1) { if constexpr (columns == 1) {
// Make vector when one column only. // Make vector when one column only.
sa = SafeArrayCreateVector(VT_VARIANT, 0, rows); sa = SafeArrayCreateVector(VT_VARIANT, 0, rows);
@ -1590,7 +1644,7 @@ namespace winstd
VARIANT var; VARIANT var;
V_VT(&var) = VT_ARRAY | VT_VARIANT; V_VT(&var) = VT_ARRAY | VT_VARIANT;
V_ARRAY(&var) = sa; V_ARRAY(&var) = sa.detach();
return var; return var;
} }
@ -1614,7 +1668,7 @@ namespace winstd
// Allocate. // Allocate.
size_t pallete_size = sizeof(RGBQUAD) * bmh.biClrUsed; size_t pallete_size = sizeof(RGBQUAD) * bmh.biClrUsed;
LPSAFEARRAY sa = SafeArrayCreateVector(VT_UI1, 0, static_cast<ULONG>(sizeof(BITMAPFILEHEADER) + sizeof(bmh) + pallete_size + bmh.biSizeImage)); safearray sa = SafeArrayCreateVector(VT_UI1, 0, static_cast<ULONG>(sizeof(BITMAPFILEHEADER) + sizeof(bmh) + pallete_size + bmh.biSizeImage));
if (!sa) if (!sa)
throw std::bad_alloc(); throw std::bad_alloc();
@ -1642,7 +1696,7 @@ namespace winstd
VARIANT var; VARIANT var;
V_VT(&var) = VT_ARRAY | VT_UI1; V_VT(&var) = VT_ARRAY | VT_UI1;
V_ARRAY(&var) = sa; V_ARRAY(&var) = sa.detach();
return var; return var;
} }