#pragma once #include <Convert.h> #include <Utils.h> class ComUtils { public: template<VARENUM Tv> class DiscernType { }; #define DECLARE_DISCERN_COM_TYPE(ComType, CppType) \ public: template<> class DiscernType<ComType> \ { \ public: typedef CppType DataType; \ }; DECLARE_DISCERN_COM_TYPE(VT_BOOL, bool); DECLARE_DISCERN_COM_TYPE(VT_I1, char); DECLARE_DISCERN_COM_TYPE(VT_I2, short); DECLARE_DISCERN_COM_TYPE(VT_INT, int); DECLARE_DISCERN_COM_TYPE(VT_I4, long); DECLARE_DISCERN_COM_TYPE(VT_I8, long long); DECLARE_DISCERN_COM_TYPE(VT_R4, float); DECLARE_DISCERN_COM_TYPE(VT_R8, double); DECLARE_DISCERN_COM_TYPE(VT_DECIMAL, long double); DECLARE_DISCERN_COM_TYPE(VT_BSTR, CComBSTR); DECLARE_DISCERN_COM_TYPE(VT_LPSTR, const char*); DECLARE_DISCERN_COM_TYPE(VT_VARIANT, CComVariant); DECLARE_DISCERN_COM_TYPE(VT_UI1, unsigned char); DECLARE_DISCERN_COM_TYPE(VT_UI2, unsigned short); DECLARE_DISCERN_COM_TYPE(VT_UINT, unsigned int); DECLARE_DISCERN_COM_TYPE(VT_UI4, unsigned long); DECLARE_DISCERN_COM_TYPE(VT_UI8, unsigned long long); DECLARE_DISCERN_COM_TYPE(VT_VOID, void); DECLARE_DISCERN_COM_TYPE(VT_HRESULT, HRESULT); DECLARE_DISCERN_COM_TYPE(VT_PTR, void*); public: template<typename TIn, VARENUM Tv> static typename DiscernType<Tv>::DataType Transform(TIn t) { return static_cast<DiscernType<Tv>::DataType>(t); } // +-----------------------------------------------------------------------------+ // This method will create a variant purely initialized to zero. It zeroes out // the biggest possible data size (VT_U8 or ullVal). // // This complete zeroing is required while extracting the (integral) // value without data or sign loss. // +-----------------------------------------------------------------------------+ public: static CComVariant ZeroCreateVariant() { CComVariant cv; cv.ullVal = 0; cv.vt = VT_EMPTY; return cv; } // +-----------------------------------------------------------------------------+ // This is another flavor of the parameter-less ZeroCreateVariant. This method // zeroes out and then assigns\initializes the variant specified value. This // makes extracting value without data\sign loss, when underlying data type of // the variant is smaller-sized than the target type. // +-----------------------------------------------------------------------------+ public: template<typename T> static CComVariant ZeroCreateVariant(T& t) { CComVariant cv = ZeroCreateVariant(); cv = t; return cv; } // +-----------------------------------------------------------------------------------+ // This is a helper method that provides sign bit extension for small-sized positive // or negative integral types when they are copied (casted\converted) from a variant // to higher-sized integer types. For example, char to long. This method extracts the // integral positive\negative values. // // CAUTION: This method does not have a wider or general purpose use. This method has // to be used when the data value in a variant could be one of the several integral // types and the value has to be copied to a C++ integral type with sign-bit extension. // +-----------------------------------------------------------------------------------+ public: static long long NormalizeValue(const CComVariant& cv) { const int srcSize = ComUtils::SizeOf(static_cast<VARENUM>(cv.vt)); const int bitsToShift = srcSize * 8 /*Bits Per Byte*/; const long long llMask = 0xFFFFFFFFFFFFFFFF << bitsToShift; const long long ullMaskedValue = ~llMask & cv.ullVal; const bool isNegative = ((ullMaskedValue & (1i64 << (bitsToShift - 1))) != 0); return static_cast<long long>(isNegative ? llMask | ullMaskedValue : ullMaskedValue); } public: static int SizeOf(VARENUM vt) { switch (vt) { case VT_BOOL: return sizeof(VARIANT_BOOL); case VT_I1: case VT_UI1: return sizeof(unsigned char); case VT_I2: case VT_UI2: return sizeof(unsigned short); case VT_I4: case VT_UI4: return sizeof(unsigned long); case VT_INT: case VT_UINT: return sizeof(unsigned int); case VT_I8: case VT_UI8: return sizeof(unsigned long long); case VT_R4: return sizeof(float); case VT_R8: return sizeof(double); default: _ASSERTE(FALSE); //const std::string errorText = KTFAUtils::CStringFormatter("Cannot deduce size for item type %d (%s)", vt, Convert::ToString(vt)); throw std::exception(/*errorText.c_str()*/); } } public: static bool IsNegativeInteger(const CComVariant& cv) { return GetIntegerValue(cv) < 0; } public: static long long GetIntegerValue(const CComVariant& cv) { _ASSERTE(IsInteger(cv.vt)); switch (cv.vt) { case VT_BOOL: return cv.boolVal; case VT_I1: return cv.cVal; case VT_UI1: return cv.bVal; case VT_I2: return cv.iVal; case VT_UI2: return cv.uiVal; case VT_I4: return cv.lVal; case VT_UI4: return cv.ulVal; case VT_INT: return cv.intVal; case VT_UINT: return cv.uintVal; case VT_I8: return cv.llVal; case VT_UI8: return cv.ullVal; } _ASSERTE(FALSE); return 0; } // Returns true if vt is one of VT_I1/2/4/8 // or VT_UI1/2/4/8 or VT_BOOL types public: static bool IsInteger(VARTYPE vt) { switch (vt) { case VT_BOOL: case VT_I1: case VT_I2: case VT_I4: case VT_I8: case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8: return true; } return false; } public: static long long Normalize(const CComVariant& cv) { _ASSERTE(IsNegativeInteger(cv)); const int srcSize = ComUtils::SizeOf(static_cast<VARENUM>(cv.vt)); const int destSize = sizeof(long long); // 8 - Bits per byte const int bitsToShift = srcSize * 8; const long long maskValue = 0xFFFFFFFFFFFFFFFF << bitsToShift; long long llValue = maskValue; switch (cv.vt) { case VT_BOOL: llValue |= cv.boolVal; break; case VT_I1: llValue |= cv.cVal; break; case VT_UI1: llValue |= cv.bVal; break; case VT_I2: llValue |= cv.iVal; break; case VT_UI2: llValue |= cv.uiVal; break; case VT_I4: llValue |= cv.lVal; break; case VT_UI4: llValue |= cv.ulVal; break; case VT_INT: llValue |= cv.intVal; break; case VT_UINT: llValue |= cv.uintVal; break; case VT_I8: llValue |= cv.llVal; break; case VT_UI8: llValue |= cv.ullVal; break; default: _ASSERTE(FALSE); break; } return llValue; } };