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
///
com_runtime_error(_In_ error_type num, _In_ const std::string& msg) : num_runtime_error<HRESULT>(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<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)
///
template <class _T>
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 <class _Other>
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 <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);
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 <class _Other>
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 <class _Other>
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<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();
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<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
{
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:
/// \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<LPVARIANT>(&varLeft), const_cast<LPVARIANT>(&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<LPVARIANT>(&varLeft), const_cast<LPVARIANT>(&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 <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;
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<void> 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<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)
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;
}