# WinStd: include/WinStd/COM.h Source File

Loading...
Searching...
No Matches
COM.h
/*
SPDX-License-Identifier: MIT
Copyright © 1991-2024 Amebis
Copyright © 2016 GÉANT
*/
#pragma once
#include "Common.h"
#include <assert.h>
#include <unknwn.h>
#include <stdexcept>
#include <string>
namespace winstd
{
class com_runtime_error : public num_runtime_error<HRESULT>
{
public:
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_opt_z_ const char *msg = nullptr) : num_runtime_error<HRESULT>(num, msg)
{}
};
struct CoTaskMemFree_delete
{
CoTaskMemFree_delete() noexcept {}
template <class _T>
void operator()(_T *_Ptr) const
{
CoTaskMemFree(_Ptr);
}
};
template <class T>
class com_obj : public dplhandle<T*, NULL>
{
WINSTD_DPLHANDLE_IMPL(com_obj, T*, NULL)
public:
com_obj(
_In_ REFCLSID rclsid,
_In_opt_ LPUNKNOWN pUnkOuter,
_In_ DWORD dwClsContext)
{
HRESULT hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (LPVOID*)&m_h);
if (FAILED(hr))
throw com_runtime_error(hr, "CoCreateInstance failed");
}
template <class _Other>
com_obj(_In_ _Other *other)
{
assert(other);
HRESULT hr = other->QueryInterface(__uuidof(T), (void**)&m_h);
if (FAILED(hr))
throw com_runtime_error(hr, "QueryInterface failed");
}
template <class _Other>
com_obj(_In_ com_obj<_Other> &other)
{
HRESULT hr = other->QueryInterface(__uuidof(T), (void**)&m_h);
if (FAILED(hr))
throw com_runtime_error(hr, "QueryInterface failed");
}
virtual ~com_obj()
{
if (m_h != invalid)
free_internal();
}
template <class _Other>
HRESULT query_interface(_Out_ _Other **h) const
{
assert(h);
assert(m_h);
return m_h->QueryInterface(__uuidof(_Other), (void**)h);
}
template <class _Other>
HRESULT query_interface(_Out_ com_obj<_Other> &h) const
{
assert(m_h);
_Other *_h;
HRESULT hr = m_h->QueryInterface(__uuidof(_Other), (void**)&_h);
if (SUCCEEDED(hr))
h.attach(_h);
return hr;
}
protected:
void free_internal() noexcept override
{
m_h->Release();
}
T* duplicate_internal(_In_ T* h) const override
{
h->AddRef();
return h;
}
};
class bstr : public dplhandle<BSTR, NULL>
{
WINSTD_DPLHANDLE_IMPL(bstr, BSTR, NULL)
public:
bstr(_In_opt_z_ LPCOLESTR src)
{
m_h = SysAllocString(src);
if (!m_h)
throw std::bad_alloc();
}
bstr(_In_reads_opt_(len) LPCOLESTR src, _In_ UINT len)
{
m_h = SysAllocStringLen(src, len);
if (!m_h)
throw std::bad_alloc();
}
template<class _Traits, class _Ax>
bstr(_In_ const std::basic_string<OLECHAR, _Traits, _Ax> &src)
{
size_t len = src.length();
if (len > UINT_MAX)
throw std::invalid_argument("string too long");
m_h = SysAllocStringLen(src.c_str(), static_cast<UINT>(len));
if (!m_h)
throw std::bad_alloc();
}
virtual ~bstr()
{
if (m_h != invalid)
free_internal();
}
UINT length() const noexcept
{
return SysStringLen(m_h);
}
protected:
void free_internal() noexcept override
{
SysFreeString(m_h);
}
handle_type duplicate_internal(_In_ handle_type h) const override
{
handle_type h_new = SysAllocStringLen(h, SysStringLen(h));
if (h_new != invalid)
return h_new;
throw std::bad_alloc();
}
};
#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:
variant() noexcept
{
VariantInit(this);
}
variant(_In_ const VARIANT& varSrc)
{
vt = VT_EMPTY;
const HRESULT hr = VariantCopy(this, &varSrc);
if (FAILED(hr))
throw winstd::com_runtime_error(hr, "VariantCopy failed");
}
#pragma warning(suppress: 26495) // vt member is initialized as a result of memcpy()
variant(_Inout_ VARIANT&& varSrc) noexcept
{
memcpy(this, &varSrc, sizeof(VARIANT));
varSrc.vt = VT_EMPTY;
}
variant(_In_ bool bSrc) noexcept
{
vt = VT_BOOL;
boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
}
variant(_In_ char cSrc) noexcept
{
vt = VT_I1;
cVal = cSrc;
}
variant(_In_ unsigned char nSrc) noexcept
{
vt = VT_UI1;
bVal = nSrc;
}
variant(_In_ short nSrc) noexcept
{
vt = VT_I2;
iVal = nSrc;
}
variant(_In_ unsigned short nSrc) noexcept
{
vt = VT_UI2;
uiVal = nSrc;
}
variant(_In_ int nSrc, _In_ VARTYPE vtSrc = VT_I4) noexcept
{
assert(vtSrc == VT_I4 || vtSrc == VT_INT);
vt = vtSrc;
intVal = nSrc;
}
variant(_In_ unsigned int nSrc, _In_ VARTYPE vtSrc = VT_UI4) noexcept
{
assert(vtSrc == VT_UI4 || vtSrc == VT_UINT);
vt = vtSrc;
uintVal= nSrc;
}
variant(_In_ long nSrc, _In_ VARTYPE vtSrc = VT_I4) noexcept
{
assert(vtSrc == VT_I4 || vtSrc == VT_ERROR);
vt = vtSrc;
lVal = nSrc;
}
variant(_In_ unsigned long nSrc) noexcept
{
vt = VT_UI4;
ulVal = nSrc;
}
variant(_In_ float fltSrc) noexcept
{
vt = VT_R4;
fltVal = fltSrc;
}
variant(_In_ double dblSrc, _In_ VARTYPE vtSrc = VT_R8) noexcept
{
assert(vtSrc == VT_R8 || vtSrc == VT_DATE);
vt = vtSrc;
dblVal = dblSrc;
}
variant(_In_ long long nSrc) noexcept
{
vt = VT_I8;
llVal = nSrc;
}
variant(_In_ unsigned long long nSrc) noexcept
{
vt = VT_UI8;
ullVal = nSrc;
}
variant(_In_ CY cySrc) noexcept
{
vt = VT_CY;
cyVal.Hi = cySrc.Hi;
cyVal.Lo = cySrc.Lo;
}
variant(_In_z_ LPCOLESTR lpszSrc) noexcept
{
vt = VT_EMPTY;
*this = lpszSrc;
}
variant(_In_z_ BSTR bstr) noexcept
{
vt = VT_EMPTY;
*this = bstr;
}
variant(_In_opt_ IDispatch* pSrc)
{
vt = VT_DISPATCH;
pdispVal = pSrc;
if (pdispVal != NULL)
pdispVal->AddRef();
}
variant(_In_opt_ IUnknown* pSrc)
{
vt = VT_UNKNOWN;
punkVal = pSrc;
if (punkVal != NULL)
punkVal->AddRef();
}
variant(_In_ const SAFEARRAY *pSrc)
{
assert(pSrc != NULL);
LPSAFEARRAY pCopy;
const HRESULT hr = SafeArrayCopy(const_cast<LPSAFEARRAY>(pSrc), &pCopy);
if (FAILED(hr))
throw winstd::com_runtime_error(hr, "SafeArrayCopy failed");
SafeArrayGetVartype(const_cast<LPSAFEARRAY>(pSrc), &vt);
vt |= VT_ARRAY;
parray = pCopy;
}
virtual ~variant()
{
VariantClear(this);
}
variant& operator=(_In_ const VARIANT& varSrc)
{
if (this != &varSrc) {
const HRESULT hr = VariantCopy(this, &varSrc);
if (FAILED(hr))
throw winstd::com_runtime_error(hr, "VariantCopy failed");
}
return *this;
}
variant& operator=(_Inout_ VARIANT&& varSrc) noexcept
{
if (this != &varSrc) {
VariantClear(this);
memcpy(this, &varSrc, sizeof(VARIANT));
varSrc.vt = VT_EMPTY;
}
return *this;
}
variant& operator=(_In_ bool bSrc) noexcept
{
if (vt != VT_BOOL) {
VariantClear(this);
vt = VT_BOOL;
}
boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
return *this;
}
variant& operator=(_In_ char cSrc) noexcept
{
if (vt != VT_I1) {
VariantClear(this);
vt = VT_I1;
}
cVal = cSrc;
return *this;
}
variant& operator=(_In_ unsigned char nSrc) noexcept
{
if (vt != VT_UI1) {
VariantClear(this);
vt = VT_UI1;
}
bVal = nSrc;
return *this;
}
variant& operator=(_In_ short nSrc) noexcept
{
if (vt != VT_I2) {
VariantClear(this);
vt = VT_I2;
}
iVal = nSrc;
return *this;
}
variant& operator=(_In_ unsigned short nSrc) noexcept
{
if (vt != VT_UI2) {
VariantClear(this);
vt = VT_UI2;
}
uiVal = nSrc;
return *this;
}
variant& operator=(_In_ int nSrc) noexcept
{
if (vt != VT_I4) {
VariantClear(this);
vt = VT_I4;
}
intVal = nSrc;
return *this;
}
variant& operator=(_In_ unsigned int nSrc) noexcept
{
if (vt != VT_UI4) {
VariantClear(this);
vt = VT_UI4;
}
uintVal= nSrc;
return *this;
}
variant& operator=(_In_ long nSrc) noexcept
{
if (vt != VT_I4) {
VariantClear(this);
vt = VT_I4;
}
lVal = nSrc;
return *this;
}
variant& operator=(_In_ unsigned long nSrc) noexcept
{
if (vt != VT_UI4) {
VariantClear(this);
vt = VT_UI4;
}
ulVal = nSrc;
return *this;
}
variant& operator=(_In_ long long nSrc) noexcept
{
if (vt != VT_I8) {
VariantClear(this);
vt = VT_I8;
}
llVal = nSrc;
return *this;
}
variant& operator=(_In_ unsigned long long nSrc) noexcept
{
if (vt != VT_UI8) {
VariantClear(this);
vt = VT_UI8;
}
ullVal = nSrc;
return *this;
}
variant& operator=(_In_ float fltSrc) noexcept
{
if (vt != VT_R4) {
VariantClear(this);
vt = VT_R4;
}
fltVal = fltSrc;
return *this;
}
variant& operator=(_In_ double dblSrc) noexcept
{
if (vt != VT_R8) {
VariantClear(this);
vt = VT_R8;
}
dblVal = dblSrc;
return *this;
}
variant& operator=(_In_ CY cySrc) noexcept
{
if (vt != VT_CY) {
VariantClear(this);
vt = VT_CY;
}
cyVal.Hi = cySrc.Hi;
cyVal.Lo = cySrc.Lo;
return *this;
}
variant& operator=(_In_z_ LPCOLESTR lpszSrc) noexcept
{
VariantClear(this);
vt = VT_BSTR;
bstrVal = SysAllocString(lpszSrc);
return *this;
}
variant& operator=(_Inout_opt_ IDispatch* pSrc)
{
VariantClear(this);
vt = VT_DISPATCH;
pdispVal = pSrc;
if (pdispVal != NULL)
pdispVal->AddRef();
return *this;
}
variant& operator=(_Inout_opt_ IUnknown* pSrc)
{
VariantClear(this);
vt = VT_UNKNOWN;
punkVal = pSrc;
if (punkVal != NULL)
punkVal->AddRef();
return *this;
}
variant& operator=(_In_ unsigned char* pbSrc) noexcept
{
if (vt != (VT_UI1|VT_BYREF)) {
VariantClear(this);
vt = VT_UI1|VT_BYREF;
}
pbVal = pbSrc;
return *this;
}
variant& operator=(_In_ short* pnSrc) noexcept
{
if (vt != (VT_I2|VT_BYREF)) {
VariantClear(this);
vt = VT_I2|VT_BYREF;
}
piVal = pnSrc;
return *this;
}
variant& operator=(_In_ unsigned short* pnSrc) noexcept
{
if (vt != (VT_UI2|VT_BYREF)) {
VariantClear(this);
vt = VT_UI2|VT_BYREF;
}
puiVal = pnSrc;
return *this;
}
variant& operator=(_In_ int* pnSrc) noexcept
{
if (vt != (VT_I4|VT_BYREF)) {
VariantClear(this);
vt = VT_I4|VT_BYREF;
}
pintVal = pnSrc;
return *this;
}
variant& operator=(_In_ unsigned int* pnSrc) noexcept
{
if (vt != (VT_UI4|VT_BYREF)) {
VariantClear(this);
vt = VT_UI4|VT_BYREF;
}
puintVal = pnSrc;
return *this;
}
variant& operator=(_In_ long* pnSrc) noexcept
{
if (vt != (VT_I4|VT_BYREF)) {
VariantClear(this);
vt = VT_I4|VT_BYREF;
}
plVal = pnSrc;
return *this;
}
variant& operator=(_In_ unsigned long* pnSrc) noexcept
{
if (vt != (VT_UI4|VT_BYREF)) {
VariantClear(this);
vt = VT_UI4|VT_BYREF;
}
pulVal = pnSrc;
return *this;
}
variant& operator=(_In_ long long* pnSrc) noexcept
{
if (vt != (VT_I8|VT_BYREF)) {
VariantClear(this);
vt = VT_I8|VT_BYREF;
}
pllVal = pnSrc;
return *this;
}
variant& operator=(_In_ unsigned long long* pnSrc) noexcept
{
if (vt != (VT_UI8|VT_BYREF)) {
VariantClear(this);
vt = VT_UI8|VT_BYREF;
}
pullVal = pnSrc;
return *this;
}
variant& operator=(_In_ float* pfSrc) noexcept
{
if (vt != (VT_R4|VT_BYREF)) {
VariantClear(this);
vt = VT_R4|VT_BYREF;
}
pfltVal = pfSrc;
return *this;
}
variant& operator=(_In_ double* pfSrc) noexcept
{
if (vt != (VT_R8|VT_BYREF)) {
VariantClear(this);
vt = VT_R8|VT_BYREF;
}
pdblVal = pfSrc;
return *this;
}
variant& operator=(_In_ const SAFEARRAY *pSrc)
{
assert(pSrc != NULL);
VariantClear(this);
LPSAFEARRAY pCopy;
const HRESULT hr = SafeArrayCopy(const_cast<LPSAFEARRAY>(pSrc), &pCopy);
if (SUCCEEDED(hr)) {
SafeArrayGetVartype(const_cast<LPSAFEARRAY>(pSrc), &vt);
vt |= VT_ARRAY;
parray = pCopy;
return *this;
}
throw com_runtime_error(hr, "SafeArrayCopy failed");
}
public:
bool operator==(_In_ const VARIANT& varSrc) const noexcept
{
if (vt == VT_NULL && varSrc.vt == VT_NULL) return true;
if (vt != varSrc.vt) return false;
return compare(static_cast<const VARIANT&>(*this), varSrc, LOCALE_USER_DEFAULT, 0) == static_cast<HRESULT>(VARCMP_EQ);
}
bool operator!=(_In_ const VARIANT& varSrc) const noexcept
{
return !operator==(varSrc);
}
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);
}
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);
}
bool operator<=(_In_ const VARIANT& varSrc) const noexcept
{
return !operator>(varSrc);
}
bool operator>=(_In_ const VARIANT& varSrc) const noexcept
{
return !operator<(varSrc);
}
HRESULT change_type(_In_ VARTYPE _vt, _In_opt_ USHORT wFlags = 0) noexcept
{
return VariantChangeType(this, this, wFlags, _vt);
}
private:
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);
}
}
};
#pragma warning(pop)
class safearray : public dplhandle<SAFEARRAY*, NULL>
{
WINSTD_DPLHANDLE_IMPL(safearray, SAFEARRAY*, NULL)
public:
virtual ~safearray()
{
if (m_h != invalid)
free_internal();
}
protected:
void free_internal() noexcept override
{
SafeArrayDestroy(m_h);
}
handle_type duplicate_internal(_In_ handle_type h) const override
{
handle_type h_new;
HRESULT hr = SafeArrayCopy(h, &h_new);
if (SUCCEEDED(hr))
return h_new;
throw com_runtime_error(hr, "SafeArrayCopy failed");
}
};
template <class T>
class safearray_accessor
{
WINSTD_NONCOPYABLE(safearray_accessor)
WINSTD_NONMOVABLE(safearray_accessor)
public:
safearray_accessor(_In_ SAFEARRAY* psa) : m_sa(psa)
{
HRESULT hr = SafeArrayAccessData(psa, (void HUGEP**)&m_data);
if (FAILED(hr))
throw com_runtime_error(hr, "SafeArrayAccessData failed");
}
virtual ~safearray_accessor()
{
SafeArrayUnaccessData(m_sa);
}
T HUGEP* data() const noexcept
{
return m_data;
}
protected:
SAFEARRAY* m_sa;
T HUGEP* m_data;
};
class com_initializer
{
WINSTD_NONCOPYABLE(com_initializer)
WINSTD_NONMOVABLE(com_initializer)
public:
com_initializer(_In_opt_ LPVOID pvReserved)
{
HRESULT hr = CoInitialize(pvReserved);
if (FAILED(hr))
throw com_runtime_error(hr, "CoInitialize failed");
}
com_initializer(_In_opt_ LPVOID pvReserved, _In_ DWORD dwCoInit)
{
HRESULT hr = CoInitializeEx(pvReserved, dwCoInit);
if (FAILED(hr))
throw com_runtime_error(hr, "CoInitializeEx failed");
}
virtual ~com_initializer()
{
CoUninitialize();
}
};
}
template <class T>
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);
if (SUCCEEDED(hr))
v.attach(ppv);
return hr;
}
template <class T>
static _Check_return_ HRESULT CoGetObject(_In_ LPCWSTR pszName, _In_opt_ BIND_OPTS* pBindOptions, _In_ REFIID riid, _Inout_ winstd::com_obj<T>& v)
{
T* ppv;
HRESULT hr = CoGetObject(pszName, pBindOptions, riid, (LPVOID*)&ppv);
if (SUCCEEDED(hr))
v.attach(ppv);
return hr;
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ IDispatch* value)
{
V_VT(&v) = VT_DISPATCH;
V_DISPATCH(&v) = value;
value->AddRef();
return *(&v + 1);
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ const CHAR value)
{
V_VT(&v) = VT_I1;
V_I1(&v) = value;
return *(&v + 1);
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ const BYTE value)
{
V_VT(&v) = VT_UI1;
V_UI1(&v) = value;
return *(&v + 1);
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ const SHORT value)
{
V_VT(&v) = VT_I2;
V_I2(&v) = value;
return *(&v + 1);
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ const USHORT value)
{
V_VT(&v) = VT_UI2;
V_UI2(&v) = value;
return *(&v + 1);
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ const LONG value)
{
V_VT(&v) = VT_I4;
V_I4(&v) = value;
return *(&v + 1);
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ const ULONG value)
{
V_VT(&v) = VT_UI4;
V_UI4(&v) = value;
return *(&v + 1);
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ const LONGLONG value)
{
V_VT(&v) = VT_I8;
V_I8(&v) = value;
return *(&v + 1);
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ const ULONGLONG value)
{
V_VT(&v) = VT_UI8;
V_UI8(&v) = value;
return *(&v + 1);
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ const FLOAT value)
{
V_VT(&v) = VT_R4;
V_R4(&v) = value;
return *(&v + 1);
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ const DOUBLE value)
{
V_VT(&v) = VT_R8;
V_R8(&v) = value;
return *(&v + 1);
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ const BOOL value)
{
return v << (value ? VARIANT_TRUE : VARIANT_FALSE);
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ LPCOLESTR value)
{
V_VT(&v) = VT_BSTR;
V_BSTR(&v) = SysAllocString(value);
return *(&v + 1);
}
template<class _Traits, class _Ax>
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ const std::basic_string<OLECHAR, _Traits, _Ax>& value)
{
if (value.size() > UINT_MAX)
throw std::invalid_argument("string too long");
V_VT(&v) = VT_BSTR;
V_BSTR(&v) = SysAllocStringLen(value.data(), static_cast<UINT>(value.size()));
return *(&v + 1);
}
inline VARIANT& operator <<(_Out_ VARIANT& v, _In_ const GUID& value)
{
OLECHAR guid_niz[38 + 1];
V_VT(&v) = VT_BSTR;
V_BSTR(&v) = SysAllocStringLen(guid_niz, _swprintf_s_l(
guid_niz, _countof(guid_niz),
L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
NULL,
value.Data1,
value.Data2,
value.Data3,
value.Data4[0], value.Data4[1],
value.Data4[2], value.Data4[3], value.Data4[4], value.Data4[5], value.Data4[6], value.Data4[7]));
return *(&v + 1);
}
namespace winstd
{
inline VARIANT BuildVBARRAY(_In_ VARTYPE vt, _In_opt_ LPCVOID array, _In_ ULONG columns, _In_ ULONG rows)
{
LPSAFEARRAY sa;
size_t n;
if (columns == 1) {
// Make vector when one column only.
sa = SafeArrayCreateVector(VT_VARIANT, 0, rows);
n = rows;
}
else {
// Make 2-dimensional array when more columns.
SAFEARRAYBOUND dim[2] = {
{ columns, 0 },
{ rows, 0 }
};
sa = SafeArrayCreate(VT_VARIANT, 2, dim);
n = columns * rows;
}
if (!sa)
throw std::bad_alloc();
assert(array || !n);
// Support VARIANT types that may be used for SAFEARRAY
// Source: https://learn.microsoft.com/en-us/windows/win32/api/wtypes/ne-wtypes-varenum#remarks
size_t delta_src;
VARIANT* v = NULL;
switch (vt) {
case VT_BOOL: delta_src = sizeof(V_BOOL(v)); break;
case VT_BSTR: delta_src = sizeof(V_BSTR(v)); break;
case VT_CY: delta_src = sizeof(V_CY(v)); break;
case VT_DATE: delta_src = sizeof(V_DATE(v)); break;
case VT_DECIMAL: delta_src = sizeof(V_DECIMAL(v)); break;
case VT_DISPATCH: delta_src = sizeof(V_DISPATCH(v)); break;
case VT_ERROR: delta_src = sizeof(V_ERROR(v)); break;
case VT_I1: delta_src = sizeof(V_I1(v)); break;
case VT_I2: delta_src = sizeof(V_I2(v)); break;
case VT_I4: delta_src = sizeof(V_I4(v)); break;
case VT_INT: delta_src = sizeof(V_INT(v)); break;
case VT_R4: delta_src = sizeof(V_R4(v)); break;
case VT_R8: delta_src = sizeof(V_R8(v)); break;
case VT_RECORD: delta_src = sizeof(V_RECORD(v)); break;
case VT_UI1: delta_src = sizeof(V_UI1(v)); break;
case VT_UI2: delta_src = sizeof(V_UI2(v)); break;
case VT_UI4: delta_src = sizeof(V_UI4(v)); break;
case VT_UINT: delta_src = sizeof(V_UINT(v)); break;
case VT_UNKNOWN: delta_src = sizeof(V_UNKNOWN(v)); break;
default: throw std::invalid_argument("unsupported VARIANT type");
};
size_t delta_dst = SafeArrayGetElemsize(sa);
{
safearray_accessor<BYTE> ssa(sa);
LPBYTE dst = ssa.data();
LPCBYTE src = reinterpret_cast<LPCBYTE>(array);
for (size_t i = 0; i < n; ++i, src += delta_src, dst += delta_dst) {
v = reinterpret_cast<VARIANT*>(dst);
// No VariantInit, since SafeArrayCreate(Vector) zero-initializes all elements.
// VariantInit(v);
V_VT(v) = vt;
memcpy(&(v->byref), src, delta_src);
}
}
VARIANT var;
V_VT(&var) = VT_ARRAY | VT_VARIANT;
V_ARRAY(&var) = sa;
return var;
}
template <class T, ULONG columns = 1>
VARIANT BuildVBARRAY(_In_reads_opt_(rows) const T* array, _In_ ULONG rows)
{
assert(array || !rows);
LPSAFEARRAY sa;
if constexpr (columns == 1) {
// Make vector when one column only.
sa = SafeArrayCreateVector(VT_VARIANT, 0, rows);
}
else {
// Make 2-dimensional array when more columns.
SAFEARRAYBOUND dim[2] = {
{ columns, 0 },
{ rows, 0 }
};
sa = SafeArrayCreate(VT_VARIANT, _countof(dim), dim);
}
if (!sa)
throw std::bad_alloc();
assert(SafeArrayGetElemsize(sa) == sizeof(VARIANT));
{
safearray_accessor<VARIANT> ssa(sa);
VARIANT* dst = ssa.data();
for (size_t i = 0; i < rows; ++i) {
VARIANT* dst_next = &(*dst << array[i]);
assert(dst + columns == dst_next);
dst = dst_next;
}
}
VARIANT var;
V_VT(&var) = VT_ARRAY | VT_VARIANT;
V_ARRAY(&var) = sa;
return var;
}
inline VARIANT BuildVBARRAY(_In_ HDC dc, _In_ HBITMAP pic)
{
// Get picture parameters.
BITMAP bmp;
GetObject(pic, sizeof(bmp), reinterpret_cast<LPSTR>(&bmp));
// Estimate file parameters.
BITMAPINFOHEADER bmh = { sizeof(bmh) };
GetDIBits(dc, pic, 0, bmp.bmHeight, NULL, reinterpret_cast<LPBITMAPINFO>(&bmh), DIB_RGB_COLORS);
// 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));
if (!sa)
throw std::bad_alloc();
// Locate BITMAPFILEHEADER, BITMAPINFO and pixel map.
safearray_accessor<BYTE> ssa(sa);
auto header = reinterpret_cast<LPBITMAPFILEHEADER>(ssa.data());
auto info = reinterpret_cast<LPBITMAPINFO>(ssa.data() + sizeof(*header));
auto raster = ssa.data() + sizeof(*header) + sizeof(bmh) + pallete_size;
// Fill in BITMAPFILEHEADER.
memset(header, 0, sizeof(*header));
#pragma warning(push)
#pragma warning(disable: 6276) // "BM" is not an UTF16 char.
header->bfType = *reinterpret_cast<WORD*>("BM");
#pragma warning(pop)
header->bfSize = static_cast<DWORD>(sizeof(*header) + sizeof(bmh) + pallete_size + bmh.biSizeImage);
header->bfOffBits = static_cast<DWORD>(sizeof(*header) + sizeof(bmh) + pallete_size);
// Fill in BITMAPINFO.
memcpy(&(info->bmiHeader), &bmh, sizeof(bmh));
memset(&(info->bmiColors), 0, pallete_size);
// Set pallete and pixel map.
GetDIBits(dc, pic, 0, bmp.bmHeight, raster, info, DIB_RGB_COLORS);
VARIANT var;
V_VT(&var) = VT_ARRAY | VT_UI1;
V_ARRAY(&var) = sa;
return var;
}
template <class T>
void IDispatchInvoke(_In_ T* cp, _In_ DISPID id, _In_opt_ DISPPARAMS* param, _In_ LCID locale = LOCALE_USER_DEFAULT)
{
assert(cp);
com_obj<IEnumConnections> e;
HRESULT hr = cp->EnumConnections(&e);
if (FAILED(hr))
throw com_runtime_error(hr, "IDispatch::EnumConnections failed");
CONNECTDATA cd;
while (e->Next(1, &cd, NULL) == S_OK) {
com_obj<IDispatch> d(cd.pUnk);
d->Invoke(id, IID_NULL, locale, DISPATCH_METHOD, param, NULL, NULL, NULL);
}
}
template <class T>
T VariantAsInteger(_In_ const VARIANT* var, _In_ T fallback = 0)
{
assert(var);
switch (V_VT(var)) {
case VT_UINT_PTR: return static_cast<T>(V_UINT_PTR(var));
case VT_INT_PTR: return static_cast<T>(V_INT_PTR(var));
case VT_UINT: return static_cast<T>(V_UINT(var));
case VT_INT: return static_cast<T>(V_INT(var));
case VT_UI4: return static_cast<T>(V_UI4(var));
case VT_I4: return static_cast<T>(V_I4(var));
case VT_UI2: return static_cast<T>(V_UI2(var));
case VT_I2: return static_cast<T>(V_I2(var));
case VT_UI1: return static_cast<T>(V_UI1(var));
case VT_I1: return static_cast<T>(V_I1(var));
}
return fallback;
}
inline BOOL VariantAsBoolean(_In_ const VARIANT* var, _In_ BOOL fallback = FALSE)
{
assert(var);
switch (V_VT(var)) {
case VT_BOOL: return V_BOOL(var) != VARIANT_FALSE;
case VT_UI4: return V_UI4(var) != 0;
case VT_I4: return V_I4(var) != 0;
case VT_UI2: return V_UI2(var) != 0;
case VT_I2: return V_I2(var) != 0;
case VT_UI1: return V_UI1(var) != 0;
case VT_I1: return V_I1(var) != 0;
case VT_UINT: return V_UINT(var) != 0;
case VT_INT: return V_INT(var) != 0;
case VT_UINT_PTR: return V_UINT_PTR(var) != 0;
case VT_INT_PTR: return V_INT_PTR(var) != 0;
}
return fallback;
}
}
winstd::bstr
BSTR string wrapper.
Definition COM.h:198
winstd::bstr::bstr
bstr(LPCOLESTR src)
Constructs BSTR from OLE string.
Definition COM.h:205
winstd::bstr::duplicate_internal
handle_type duplicate_internal(handle_type h) const override
Duplicates the string.
Definition COM.h:277
winstd::bstr::~bstr
virtual ~bstr()
Destroys the string.
Definition COM.h:241
winstd::bstr::free_internal
void free_internal() noexcept override
Destroys the string.
Definition COM.h:263
winstd::bstr::length
UINT length() const noexcept
Returns the length of the string.
Definition COM.h:252
winstd::bstr::bstr
bstr(LPCOLESTR src, UINT len)
Constructs BSTR from OLE string with length.
Definition COM.h:215
winstd::bstr::bstr
bstr(const std::basic_string< OLECHAR, _Traits, _Ax > &src)
Constructs BSTR from std::basic_string.
Definition COM.h:226
winstd::com_initializer
Context scope automatic COM (un)initialization.
Definition COM.h:1137
winstd::com_initializer::com_initializer
com_initializer(LPVOID pvReserved, DWORD dwCoInit)
Initializes the COM library for use by the calling thread, sets the thread's concurrency model,...
Definition COM.h:1159
winstd::com_initializer::~com_initializer
virtual ~com_initializer()
Uninitializes COM.
Definition COM.h:1171
winstd::com_initializer::com_initializer
com_initializer(LPVOID pvReserved)
Initializes the COM library on the current thread and identifies the concurrency model as single-thre...
Definition COM.h:1147
winstd::com_obj
COM object wrapper template.
Definition COM.h:83
winstd::com_obj::free_internal
void free_internal() noexcept override
Releases the object by decrementing reference counter.
Definition COM.h:173
winstd::com_obj::com_obj
com_obj(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext)
Creates a new instance of a class.
Definition COM.h:92
winstd::com_obj::query_interface
HRESULT query_interface(_Other **h) const
Queries the object for another interface.
Definition COM.h:144
winstd::com_obj::duplicate_internal
T * duplicate_internal(T *h) const override
Duplicates the object by incrementing the reference counter.
Definition COM.h:187
winstd::com_obj::query_interface
HRESULT query_interface(com_obj< _Other > &h) const
Queries the object for another interface.
Definition COM.h:157
winstd::com_obj::~com_obj
virtual ~com_obj()
Releases object.
Definition COM.h:132
winstd::com_obj::com_obj
com_obj(_Other *other)
Queries the object for another interface and creates new class with it.
Definition COM.h:108
winstd::com_obj::com_obj
com_obj(com_obj< _Other > &other)
Queries the object for another interface and creates new class with it.
Definition COM.h:122
winstd::com_runtime_error
COM runtime error.
Definition COM.h:28
winstd::com_runtime_error::com_runtime_error
com_runtime_error(error_type num, const std::string &msg)
Constructs an exception.
Definition COM.h:36
winstd::com_runtime_error::com_runtime_error
com_runtime_error(error_type num, const char *msg=nullptr)
Constructs an exception.
Definition COM.h:45
winstd::dc
Device context wrapper class.
Definition GDI.h:84
winstd::dplhandle
Base abstract template class to support object handle keeping for objects that support trivial handle...
Definition Common.h:1137
winstd::handle::m_h
handle_type m_h
Object handle.
Definition Common.h:1126
winstd::handle< BSTR, INVAL >::handle_type
BSTR handle_type
Definition Common.h:879
winstd::num_runtime_error
Numerical runtime error.
Definition Common.h:1331
winstd::num_runtime_error< HRESULT >::error_type
HRESULT error_type
Definition Common.h:1333
winstd::safearray_accessor
Context scope automatic SAFEARRAY (un)access.
Definition COM.h:1093
winstd::safearray_accessor::safearray_accessor
safearray_accessor(SAFEARRAY *psa)
Increments the lock count of an array, and retrieves a pointer to the array data.
Definition COM.h:1103
winstd::safearray_accessor::data
T HUGEP * data() const noexcept
Return SAFEARRAY data pointer.
Definition COM.h:1123
winstd::safearray_accessor::m_sa
SAFEARRAY * m_sa
SAFEARRAY.
Definition COM.h:1129
winstd::safearray_accessor::~safearray_accessor
virtual ~safearray_accessor()
Decrements the lock count of an array.
Definition COM.h:1115
winstd::safearray_accessor::m_data
T HUGEP * m_data
SAFEARRAY data.
Definition COM.h:1130
winstd::safearray
SAFEARRAY string wrapper.
Definition COM.h:1043
winstd::safearray::~safearray
virtual ~safearray()
Destroys the array.
Definition COM.h:1052
winstd::safearray::duplicate_internal
handle_type duplicate_internal(handle_type h) const override
Duplicates the array.
Definition COM.h:1078
winstd::safearray::free_internal
void free_internal() noexcept override
Destroys the array.
Definition COM.h:1064
winstd::variant
VARIANT struct wrapper.
Definition COM.h:292
winstd::variant::operator<=
bool operator<=(const VARIANT &varSrc) const noexcept
Is variant less than or equal to?
Definition COM.h:995
winstd::variant::variant
variant(bool bSrc) noexcept
Constructs VARIANT from bool.
Definition COM.h:326
winstd::variant::operator=
variant & operator=(unsigned int nSrc) noexcept
Copy from unsigned int value.
Definition COM.h:628
winstd::variant::operator=
variant & operator=(unsigned long nSrc) noexcept
Copy from unsigned long value.
Definition COM.h:654
winstd::variant::variant
variant(float fltSrc) noexcept
Constructs VARIANT from float.
Definition COM.h:410
winstd::variant::variant
variant(VARIANT &&varSrc) noexcept
Moves VARIANT from another.
Definition COM.h:317
winstd::variant::operator=
variant & operator=(float fltSrc) noexcept
Copy from float value.
Definition COM.h:694
winstd::variant::operator=
variant & operator=(float *pfSrc) noexcept
Copy from float reference.
Definition COM.h:888
winstd::variant::variant
variant(IDispatch *pSrc)
Constructs VARIANT from IDispatch.
Definition COM.h:475
winstd::variant::variant
variant(int nSrc, VARTYPE vtSrc=VT_I4) noexcept
Constructs VARIANT from integer.
Definition COM.h:371
winstd::variant::variant
variant(const SAFEARRAY *pSrc)
Constructs VARIANT from SAFEARRAY.
Definition COM.h:499
winstd::variant::operator=
variant & operator=(double *pfSrc) noexcept
Copy from double reference.
Definition COM.h:901
winstd::variant::operator=
variant & operator=(const SAFEARRAY *pSrc)
Copy from SAFEARRAY.
Definition COM.h:914
winstd::variant::operator=
variant & operator=(int *pnSrc) noexcept
Copy from int reference.
Definition COM.h:810
winstd::variant::operator>
bool operator>(const VARIANT &varSrc) const noexcept
Is variant greater than?
Definition COM.h:981
winstd::variant::operator=
variant & operator=(bool bSrc) noexcept
Copy from bool value.
Definition COM.h:550
winstd::variant::operator=
variant & operator=(long nSrc) noexcept
Copy from long value.
Definition COM.h:641
winstd::variant::change_type
HRESULT change_type(VARTYPE _vt, USHORT wFlags=0) noexcept
Converts a variant from one type to another.
Definition COM.h:1018
winstd::variant::operator=
variant & operator=(IUnknown *pSrc)
Copy from IUnknown.
Definition COM.h:758
winstd::variant::operator=
variant & operator=(short nSrc) noexcept
Copy from short value.
Definition COM.h:589
winstd::variant::operator=
variant & operator=(unsigned char *pbSrc) noexcept
Copy from unsigned char reference.
Definition COM.h:771
winstd::variant::operator=
variant & operator=(unsigned short nSrc) noexcept
Copy from unsigned short value.
Definition COM.h:602
winstd::variant::operator=
variant & operator=(unsigned char nSrc) noexcept
Copy from unsigned char value.
Definition COM.h:576
winstd::variant::operator=
variant & operator=(char cSrc) noexcept
Copy from char value.
Definition COM.h:563
winstd::variant::variant
variant(LPCOLESTR lpszSrc) noexcept
Constructs VARIANT from OLE string.
Definition COM.h:457
winstd::variant::~variant
virtual ~variant()
Destroys VARIANT.
Definition COM.h:516
winstd::variant::variant
variant(const VARIANT &varSrc)
Constructs VARIANT from another.
Definition COM.h:305
winstd::variant::variant
variant(unsigned char nSrc) noexcept
Constructs VARIANT from byte.
Definition COM.h:344
winstd::variant::operator=
variant & operator=(double dblSrc) noexcept
Copy from double value.
Definition COM.h:707
winstd::variant::operator!=
bool operator!=(const VARIANT &varSrc) const noexcept
Is variant not equal to?
Definition COM.h:954
winstd::variant::operator=
variant & operator=(int nSrc) noexcept
Copy from int value.
Definition COM.h:615
winstd::variant::variant
variant(unsigned long nSrc) noexcept
Constructs VARIANT from unsigned long.
Definition COM.h:401
winstd::variant::operator==
bool operator==(const VARIANT &varSrc) const noexcept
Is variant equal to?
Definition COM.h:939
winstd::variant::variant
variant(IUnknown *pSrc)
Constructs VARIANT from IUnknown.
Definition COM.h:487
winstd::variant::variant
variant(unsigned int nSrc, VARTYPE vtSrc=VT_UI4) noexcept
Constructs VARIANT from unsigned integer.
Definition COM.h:381
winstd::variant::operator=
variant & operator=(CY cySrc) noexcept
Copy from CY value.
Definition COM.h:720
winstd::variant::operator=
variant & operator=(LPCOLESTR lpszSrc) noexcept
Copy from OLE string value.
Definition COM.h:734
winstd::variant::variant
variant(long long nSrc) noexcept
Constructs VARIANT from 64-bit integer.
Definition COM.h:429
winstd::variant::operator=
variant & operator=(unsigned int *pnSrc) noexcept
Copy from unsigned int reference.
Definition COM.h:823
winstd::variant::variant
variant(long nSrc, VARTYPE vtSrc=VT_I4) noexcept
Constructs VARIANT from long.
Definition COM.h:391
winstd::variant::operator=
variant & operator=(long *pnSrc) noexcept
Copy from long reference.
Definition COM.h:836
winstd::variant::variant
variant(unsigned short nSrc) noexcept
Constructs VARIANT from unsigned short.
Definition COM.h:362
winstd::variant::operator>=
bool operator>=(const VARIANT &varSrc) const noexcept
Is variant greater than or equal to?
Definition COM.h:1008
winstd::variant::operator=
variant & operator=(short *pnSrc) noexcept
Copy from short reference.
Definition COM.h:784
winstd::variant::variant
variant() noexcept
Constructs blank VARIANT.
Definition COM.h:297
winstd::variant::operator<
bool operator<(const VARIANT &varSrc) const noexcept
Is variant less than?
Definition COM.h:967
winstd::variant::variant
variant(unsigned long long nSrc) noexcept
Constructs VARIANT from unsigned integer.
Definition COM.h:438
winstd::variant::variant
variant(char cSrc) noexcept
Constructs VARIANT from character.
Definition COM.h:335
winstd::variant::operator=
variant & operator=(unsigned short *pnSrc) noexcept
Copy from unsigned short reference.
Definition COM.h:797
winstd::variant::operator=
variant & operator=(long long *pnSrc) noexcept
Copy from long long reference.
Definition COM.h:862
winstd::variant::variant
variant(BSTR bstr) noexcept
Constructs VARIANT from BSTR.
Definition COM.h:466
winstd::variant::operator=
variant & operator=(unsigned long long *pnSrc) noexcept
Copy from unsigned long long reference.
Definition COM.h:875
winstd::variant::variant
variant(double dblSrc, VARTYPE vtSrc=VT_R8) noexcept
Constructs VARIANT from double or variant date.
Definition COM.h:419
winstd::variant::variant
variant(short nSrc) noexcept
Constructs VARIANT from short.
Definition COM.h:353
winstd::variant::variant
variant(CY cySrc) noexcept
Constructs VARIANT from CY (64-bit integer)
Definition COM.h:447
winstd::variant::operator=
variant & operator=(unsigned long long nSrc) noexcept
Copy from unsigned long long value.
Definition COM.h:680
winstd::variant::operator=
variant & operator=(VARIANT &&varSrc) noexcept
Moves from another VARIANT.
Definition COM.h:537
winstd::variant::operator=
variant & operator=(long long nSrc) noexcept
Copy from long long value.
Definition COM.h:667
winstd::variant::operator=
variant & operator=(IDispatch *pSrc)
Copy from IDispatch.
Definition COM.h:745
winstd::variant::operator=
variant & operator=(unsigned long *pnSrc) noexcept
Copy from unsigned long reference.
Definition COM.h:849
winstd::variant::operator=
variant & operator=(const VARIANT &varSrc)
Copy from another VARIANT.
Definition COM.h:524
operator<<
VARIANT & operator<<(VARIANT &v, IDispatch *value)
Saves value to VARIANT.
Definition COM.h:1226
winstd::IDispatchInvoke
void IDispatchInvoke(T *cp, DISPID id, DISPPARAMS *param, LCID locale=LOCALE_USER_DEFAULT)
Calls IDispatch::Invoke.
Definition COM.h:1659
winstd::VariantAsInteger
T VariantAsInteger(const VARIANT *var, T fallback=0)
Check VARIANT value for integer value.
Definition COM.h:1685
winstd::BuildVBARRAY
VARIANT BuildVBARRAY(VARTYPE vt, LPCVOID array, ULONG columns, ULONG rows)
Builds VBARRAY of uniform data.
Definition COM.h:1473
winstd::VariantAsBoolean
BOOL VariantAsBoolean(const VARIANT *var, BOOL fallback=FALSE)
Check VARIANT value for boolean value.
Definition COM.h:1711
CoGetObject
static _Check_return_ HRESULT CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions, REFIID riid, winstd::com_obj< T > &v)
Converts a display name into a moniker that identifies the object named, and then binds to the object...
Definition COM.h:1204
CoCreateInstance
static _Check_return_ HRESULT CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, winstd::com_obj< T > &v)
Creates and default-initializes a single object of the class associated with a specified CLSID.
Definition COM.h:1189
WINSTD_NONCOPYABLE
#define WINSTD_NONCOPYABLE(C)
Declares a class as non-copyable.
Definition Common.h:67
WINSTD_NONMOVABLE
#define WINSTD_NONMOVABLE(C)
Declares a class as non-movable.
Definition Common.h:75
WINSTD_DPLHANDLE_IMPL
#define WINSTD_DPLHANDLE_IMPL(C, T, INVAL)
Implements default constructors and operators to prevent their auto-generation by compiler.
Definition Common.h:176
winstd::handle::invalid
static const T invalid
Invalid handle value.
Definition Common.h:884
winstd::CoTaskMemFree_delete
Deleter for unique_ptr using CoTaskMemFree.
Definition COM.h:58
winstd::CoTaskMemFree_delete::operator()
void operator()(_T *_Ptr) const
Delete a pointer.
Definition COM.h:70
winstd::CoTaskMemFree_delete::CoTaskMemFree_delete
CoTaskMemFree_delete() noexcept
Default constructor.
Definition COM.h:62