From f33010e6b6e9488aa9bd0efbd11aa4a9900f3414 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Wed, 15 Jan 2025 15:00:25 +0100 Subject: [PATCH] COM: Add helper for SAFEARRAY creation Signed-off-by: Simon Rozman --- include/WinStd/COM.h | 172 ++++++++++++++++++++++++++++--------------- 1 file changed, 113 insertions(+), 59 deletions(-) diff --git a/include/WinStd/COM.h b/include/WinStd/COM.h index 2f0edaee..088972ad 100644 --- a/include/WinStd/COM.h +++ b/include/WinStd/COM.h @@ -34,7 +34,8 @@ namespace winstd /// \param[in] msg Error message /// com_runtime_error(_In_ error_type num, _In_ const std::string& msg) : num_runtime_error(num, msg) - {} + { + } /// /// Constructs an exception @@ -42,8 +43,9 @@ namespace winstd /// \param[in] num COM error code /// \param[in] msg Error message /// - com_runtime_error(_In_ error_type num, _In_opt_z_ const char *msg = nullptr) : num_runtime_error(num, msg) - {} + com_runtime_error(_In_ error_type num, _In_opt_z_ const char* msg = nullptr) : num_runtime_error(num, msg) + { + } }; /// @} @@ -67,7 +69,7 @@ namespace winstd /// \sa [CoTaskMemFree function](https://docs.microsoft.com/en-us/windows/desktop/api/combaseapi/nf-combaseapi-cotaskmemfree) /// template - void operator()(_T *_Ptr) const + void operator()(_T* _Ptr) const { CoTaskMemFree(_Ptr); } @@ -105,7 +107,7 @@ namespace winstd /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) /// template - com_obj(_In_ _Other *other) + com_obj(_In_ _Other* other) { assert(other); 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) /// template - com_obj(_In_ com_obj<_Other> &other) + com_obj(_In_ com_obj<_Other>& other) { HRESULT hr = other->QueryInterface(__uuidof(T), (void**)&m_h); if (FAILED(hr)) @@ -141,7 +143,7 @@ namespace winstd /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) /// template - HRESULT query_interface(_Out_ _Other **h) const + HRESULT query_interface(_Out_ _Other** h) const { assert(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) /// template - HRESULT query_interface(_Out_ com_obj<_Other> &h) const + HRESULT query_interface(_Out_ com_obj<_Other>& h) const { assert(m_h); - _Other *_h; + _Other* _h; HRESULT hr = m_h->QueryInterface(__uuidof(_Other), (void**)&_h); if (SUCCEEDED(hr)) h.attach(_h); @@ -223,7 +225,7 @@ namespace winstd /// Constructs BSTR from std::basic_string /// template - bstr(_In_ const std::basic_string &src) + bstr(_In_ const std::basic_string& src) { size_t len = src.length(); if (len > UINT_MAX) @@ -286,8 +288,8 @@ namespace winstd /// /// VARIANT struct wrapper /// - #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(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. class variant : public VARIANT { public: @@ -313,7 +315,7 @@ namespace winstd /// /// 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 { memcpy(this, &varSrc, sizeof(VARIANT)); @@ -382,7 +384,7 @@ namespace winstd { assert(vtSrc == VT_UI4 || vtSrc == VT_UINT); vt = vtSrc; - uintVal= nSrc; + uintVal = nSrc; } /// @@ -496,7 +498,7 @@ namespace winstd /// /// Constructs VARIANT from SAFEARRAY /// - variant(_In_ const SAFEARRAY *pSrc) + variant(_In_ const SAFEARRAY* pSrc) { assert(pSrc != NULL); @@ -631,7 +633,7 @@ namespace winstd VariantClear(this); vt = VT_UI4; } - uintVal= nSrc; + uintVal = nSrc; return *this; } @@ -770,9 +772,9 @@ namespace winstd /// variant& operator=(_In_ unsigned char* pbSrc) noexcept { - if (vt != (VT_UI1|VT_BYREF)) { + if (vt != (VT_UI1 | VT_BYREF)) { VariantClear(this); - vt = VT_UI1|VT_BYREF; + vt = VT_UI1 | VT_BYREF; } pbVal = pbSrc; return *this; @@ -783,9 +785,9 @@ namespace winstd /// variant& operator=(_In_ short* pnSrc) noexcept { - if (vt != (VT_I2|VT_BYREF)) { + if (vt != (VT_I2 | VT_BYREF)) { VariantClear(this); - vt = VT_I2|VT_BYREF; + vt = VT_I2 | VT_BYREF; } piVal = pnSrc; return *this; @@ -796,9 +798,9 @@ namespace winstd /// variant& operator=(_In_ unsigned short* pnSrc) noexcept { - if (vt != (VT_UI2|VT_BYREF)) { + if (vt != (VT_UI2 | VT_BYREF)) { VariantClear(this); - vt = VT_UI2|VT_BYREF; + vt = VT_UI2 | VT_BYREF; } puiVal = pnSrc; return *this; @@ -809,9 +811,9 @@ namespace winstd /// variant& operator=(_In_ int* pnSrc) noexcept { - if (vt != (VT_I4|VT_BYREF)) { + if (vt != (VT_I4 | VT_BYREF)) { VariantClear(this); - vt = VT_I4|VT_BYREF; + vt = VT_I4 | VT_BYREF; } pintVal = pnSrc; return *this; @@ -822,9 +824,9 @@ namespace winstd /// variant& operator=(_In_ unsigned int* pnSrc) noexcept { - if (vt != (VT_UI4|VT_BYREF)) { + if (vt != (VT_UI4 | VT_BYREF)) { VariantClear(this); - vt = VT_UI4|VT_BYREF; + vt = VT_UI4 | VT_BYREF; } puintVal = pnSrc; return *this; @@ -835,9 +837,9 @@ namespace winstd /// variant& operator=(_In_ long* pnSrc) noexcept { - if (vt != (VT_I4|VT_BYREF)) { + if (vt != (VT_I4 | VT_BYREF)) { VariantClear(this); - vt = VT_I4|VT_BYREF; + vt = VT_I4 | VT_BYREF; } plVal = pnSrc; return *this; @@ -848,9 +850,9 @@ namespace winstd /// variant& operator=(_In_ unsigned long* pnSrc) noexcept { - if (vt != (VT_UI4|VT_BYREF)) { + if (vt != (VT_UI4 | VT_BYREF)) { VariantClear(this); - vt = VT_UI4|VT_BYREF; + vt = VT_UI4 | VT_BYREF; } pulVal = pnSrc; return *this; @@ -861,9 +863,9 @@ namespace winstd /// variant& operator=(_In_ long long* pnSrc) noexcept { - if (vt != (VT_I8|VT_BYREF)) { + if (vt != (VT_I8 | VT_BYREF)) { VariantClear(this); - vt = VT_I8|VT_BYREF; + vt = VT_I8 | VT_BYREF; } pllVal = pnSrc; return *this; @@ -874,9 +876,9 @@ namespace winstd /// variant& operator=(_In_ unsigned long long* pnSrc) noexcept { - if (vt != (VT_UI8|VT_BYREF)) { + if (vt != (VT_UI8 | VT_BYREF)) { VariantClear(this); - vt = VT_UI8|VT_BYREF; + vt = VT_UI8 | VT_BYREF; } pullVal = pnSrc; return *this; @@ -887,9 +889,9 @@ namespace winstd /// variant& operator=(_In_ float* pfSrc) noexcept { - if (vt != (VT_R4|VT_BYREF)) { + if (vt != (VT_R4 | VT_BYREF)) { VariantClear(this); - vt = VT_R4|VT_BYREF; + vt = VT_R4 | VT_BYREF; } pfltVal = pfSrc; return *this; @@ -900,9 +902,9 @@ namespace winstd /// variant& operator=(_In_ double* pfSrc) noexcept { - if (vt != (VT_R8|VT_BYREF)) { + if (vt != (VT_R8 | VT_BYREF)) { VariantClear(this); - vt = VT_R8|VT_BYREF; + vt = VT_R8 | VT_BYREF; } pdblVal = pfSrc; return *this; @@ -911,7 +913,7 @@ namespace winstd /// /// Copy from SAFEARRAY /// - variant& operator=(_In_ const SAFEARRAY *pSrc) + variant& operator=(_In_ const SAFEARRAY* pSrc) { assert(pSrc != NULL); VariantClear(this); @@ -967,7 +969,7 @@ namespace winstd bool operator<(_In_ const VARIANT& varSrc) const noexcept { if (vt == VT_NULL && varSrc.vt == VT_NULL) return false; - return compare(static_cast(*this), varSrc, LOCALE_USER_DEFAULT, 0)== static_cast(VARCMP_LT); + return compare(static_cast(*this), varSrc, LOCALE_USER_DEFAULT, 0) == static_cast(VARCMP_LT); } /// @@ -981,7 +983,7 @@ namespace winstd bool operator>(_In_ const VARIANT& varSrc) const noexcept { if (vt == VT_NULL && varSrc.vt == VT_NULL) return false; - return compare(static_cast(*this), varSrc, LOCALE_USER_DEFAULT, 0)== static_cast(VARCMP_GT); + return compare(static_cast(*this), varSrc, LOCALE_USER_DEFAULT, 0) == static_cast(VARCMP_GT); } /// @@ -1022,19 +1024,19 @@ namespace winstd private: /// \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) { - 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_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; - default: return VarCmp(const_cast(&varLeft), const_cast(&varRight), lcid, dwFlags); + switch (vt) { + 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_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; + default: return VarCmp(const_cast(&varLeft), const_cast(&varRight), lcid, dwFlags); } } /// \endcond }; - #pragma warning(pop) +#pragma warning(pop) /// /// SAFEARRAY string wrapper @@ -1092,7 +1094,7 @@ namespace winstd class safearray_accessor { WINSTD_NONCOPYABLE(safearray_accessor) - WINSTD_NONMOVABLE(safearray_accessor) + WINSTD_NONMOVABLE(safearray_accessor) public: /// @@ -1102,7 +1104,7 @@ namespace winstd /// 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)) throw com_runtime_error(hr, "SafeArrayAccessData failed"); } @@ -1136,7 +1138,7 @@ namespace winstd class com_initializer { WINSTD_NONCOPYABLE(com_initializer) - WINSTD_NONMOVABLE(com_initializer) + WINSTD_NONMOVABLE(com_initializer) public: /// @@ -1186,7 +1188,7 @@ namespace winstd /// \sa [CoCreateInstance function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686615.aspx) /// template -static _Check_return_ HRESULT CoCreateInstance(_In_ REFCLSID rclsid, _In_opt_ LPUNKNOWN pUnkOuter, _In_ DWORD dwClsContext, _Inout_ winstd::com_obj &v) +static _Check_return_ HRESULT CoCreateInstance(_In_ REFCLSID rclsid, _In_opt_ LPUNKNOWN pUnkOuter, _In_ DWORD dwClsContext, _Inout_ winstd::com_obj& v) { T* ppv; HRESULT hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (LPVOID*)&ppv); @@ -1460,6 +1462,58 @@ namespace winstd /// \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 saa(sa); + memcpy(saa.data(), array, elem_size * n); + } + + return sa.detach(); + } + /// /// Builds VBARRAY of uniform data /// @@ -1476,7 +1530,7 @@ namespace winstd if (!array && n) throw std::invalid_argument("array is NULL"); - LPSAFEARRAY sa; + safearray sa; if (columns == 1) { // Make vector when one column only. sa = SafeArrayCreateVector(VT_VARIANT, 0, rows); @@ -1536,7 +1590,7 @@ namespace winstd VARIANT var; V_VT(&var) = VT_ARRAY | VT_VARIANT; - V_ARRAY(&var) = sa; + V_ARRAY(&var) = sa.detach(); return var; } @@ -1560,7 +1614,7 @@ namespace winstd if (!array && rows) throw std::invalid_argument("array is NULL"); - LPSAFEARRAY sa; + safearray sa; if constexpr (columns == 1) { // Make vector when one column only. sa = SafeArrayCreateVector(VT_VARIANT, 0, rows); @@ -1590,7 +1644,7 @@ namespace winstd VARIANT var; V_VT(&var) = VT_ARRAY | VT_VARIANT; - V_ARRAY(&var) = sa; + V_ARRAY(&var) = sa.detach(); return var; } @@ -1614,7 +1668,7 @@ namespace winstd // Allocate. size_t pallete_size = sizeof(RGBQUAD) * bmh.biClrUsed; - LPSAFEARRAY sa = SafeArrayCreateVector(VT_UI1, 0, static_cast(sizeof(BITMAPFILEHEADER) + sizeof(bmh) + pallete_size + bmh.biSizeImage)); + safearray sa = SafeArrayCreateVector(VT_UI1, 0, static_cast(sizeof(BITMAPFILEHEADER) + sizeof(bmh) + pallete_size + bmh.biSizeImage)); if (!sa) throw std::bad_alloc(); @@ -1642,7 +1696,7 @@ namespace winstd VARIANT var; V_VT(&var) = VT_ARRAY | VT_UI1; - V_ARRAY(&var) = sa; + V_ARRAY(&var) = sa.detach(); return var; }