| /* |
| * Low level variant functions |
| * |
| * Copyright 2003 Jon Griffiths |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #define COBJMACROS |
| #define NONAMELESSUNION |
| #define NONAMELESSSTRUCT |
| |
| #include "wine/debug.h" |
| #include "wine/unicode.h" |
| #include "winbase.h" |
| #include "winuser.h" |
| #include "winnt.h" |
| #include "variant.h" |
| #include "resource.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(variant); |
| |
| extern HMODULE OLEAUT32_hModule; |
| |
| #define CY_MULTIPLIER 10000 /* 4 dp of precision */ |
| #define CY_MULTIPLIER_F 10000.0 |
| #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */ |
| #define CY_HALF_F (CY_MULTIPLIER_F/2.0) |
| |
| static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' }; |
| static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' }; |
| |
| /* Copy data from one variant to another. */ |
| static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut) |
| { |
| switch (vt) |
| { |
| case VT_I1: |
| case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break; |
| case VT_BOOL: |
| case VT_I2: |
| case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break; |
| case VT_R4: |
| case VT_INT: |
| case VT_I4: |
| case VT_UINT: |
| case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break; |
| case VT_R8: |
| case VT_DATE: |
| case VT_CY: |
| case VT_I8: |
| case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break; |
| case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break; |
| case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break; |
| default: |
| FIXME("VT_ type %d unhandled, please report!\n", vt); |
| } |
| } |
| |
| /* Macro to inline conversion from a float or double to any integer type, |
| * rounding according to the 'dutch' convention. |
| */ |
| #define VARIANT_DutchRound(typ, value, res) do { \ |
| double whole = value < 0 ? ceil(value) : floor(value); \ |
| double fract = value - whole; \ |
| if (fract > 0.5) res = (typ)whole + (typ)1; \ |
| else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \ |
| else if (fract >= 0.0) res = (typ)whole; \ |
| else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \ |
| else if (fract > -0.5) res = (typ)whole; \ |
| else res = (typ)whole - (typ)1; \ |
| } while(0); |
| |
| |
| /* Coerce VT_BSTR to a numeric type */ |
| static HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags, |
| void* pOut, VARTYPE vt) |
| { |
| VARIANTARG dstVar; |
| HRESULT hRet; |
| NUMPARSE np; |
| BYTE rgb[1024]; |
| |
| /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */ |
| np.cDig = sizeof(rgb) / sizeof(BYTE); |
| np.dwInFlags = NUMPRS_STD; |
| |
| hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb); |
| |
| if (SUCCEEDED(hRet)) |
| { |
| /* 1 << vt gives us the VTBIT constant for the destination number type */ |
| hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar); |
| if (SUCCEEDED(hRet)) |
| VARIANT_CopyData(&dstVar, vt, pOut); |
| } |
| return hRet; |
| } |
| |
| /* Coerce VT_DISPATCH to another type */ |
| static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, |
| VARTYPE vt, DWORD dwFlags) |
| { |
| static const DISPPARAMS emptyParams = { NULL, NULL, 0, 0 }; |
| VARIANTARG srcVar, dstVar; |
| HRESULT hRet; |
| |
| if (!pdispIn) |
| return DISP_E_BADVARTYPE; |
| |
| /* Get the default 'value' property from the IDispatch */ |
| hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET, |
| (DISPPARAMS*)&emptyParams, &srcVar, NULL, NULL); |
| |
| if (SUCCEEDED(hRet)) |
| { |
| /* Convert the property to the requested type */ |
| V_VT(&dstVar) = VT_EMPTY; |
| hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt); |
| VariantClear(&srcVar); |
| |
| if (SUCCEEDED(hRet)) |
| { |
| VARIANT_CopyData(&dstVar, vt, pOut); |
| VariantClear(&srcVar); |
| } |
| } |
| else |
| hRet = DISP_E_TYPEMISMATCH; |
| return hRet; |
| } |
| |
| /* Inline return type */ |
| #define RETTYP inline static HRESULT |
| |
| |
| /* Simple compiler cast from one type to another */ |
| #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \ |
| *out = in; return S_OK; } |
| |
| /* Compiler cast where input cannot be negative */ |
| #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \ |
| if (in < (src)0) return DISP_E_OVERFLOW; *out = in; return S_OK; } |
| |
| /* Compiler cast where input cannot be > some number */ |
| #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \ |
| if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; } |
| |
| /* Compiler cast where input cannot be < some number or >= some other number */ |
| #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \ |
| if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; } |
| |
| /* I1 */ |
| POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX); |
| BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX); |
| BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX); |
| SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool); |
| POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX); |
| POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX); |
| BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX); |
| POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX); |
| |
| /* UI1 */ |
| BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX); |
| SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool); |
| NEGTST(BYTE, signed char, VarUI1FromI1); |
| POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX); |
| BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX); |
| POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX); |
| BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX); |
| POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX); |
| |
| /* I2 */ |
| SIMPLE(SHORT, BYTE, VarI2FromUI1); |
| BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX); |
| SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool); |
| SIMPLE(SHORT, signed char, VarI2FromI1); |
| POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX); |
| POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX); |
| BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX); |
| POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX); |
| |
| /* UI2 */ |
| SIMPLE(USHORT, BYTE, VarUI2FromUI1); |
| NEGTST(USHORT, SHORT, VarUI2FromI2); |
| BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX); |
| SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool); |
| NEGTST(USHORT, signed char, VarUI2FromI1); |
| POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX); |
| BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX); |
| POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX); |
| |
| /* I4 */ |
| SIMPLE(LONG, BYTE, VarI4FromUI1); |
| SIMPLE(LONG, SHORT, VarI4FromI2); |
| SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool); |
| SIMPLE(LONG, signed char, VarI4FromI1); |
| SIMPLE(LONG, USHORT, VarI4FromUI2); |
| POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX); |
| BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX); |
| POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX); |
| |
| /* UI4 */ |
| SIMPLE(ULONG, BYTE, VarUI4FromUI1); |
| NEGTST(ULONG, SHORT, VarUI4FromI2); |
| NEGTST(ULONG, LONG, VarUI4FromI4); |
| SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool); |
| NEGTST(ULONG, signed char, VarUI4FromI1); |
| SIMPLE(ULONG, USHORT, VarUI4FromUI2); |
| BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX); |
| POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX); |
| |
| /* I8 */ |
| SIMPLE(LONG64, BYTE, VarI8FromUI1); |
| SIMPLE(LONG64, SHORT, VarI8FromI2); |
| SIMPLE(LONG64, signed char, VarI8FromI1); |
| SIMPLE(LONG64, USHORT, VarI8FromUI2); |
| SIMPLE(LONG64, LONG, VarI8FromI4); |
| SIMPLE(LONG64, ULONG, VarI8FromUI4); |
| POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX); |
| |
| /* UI8 */ |
| SIMPLE(ULONG64, BYTE, VarUI8FromUI1); |
| NEGTST(ULONG64, SHORT, VarUI8FromI2); |
| NEGTST(ULONG64, signed char, VarUI8FromI1); |
| SIMPLE(ULONG64, USHORT, VarUI8FromUI2); |
| NEGTST(ULONG64, LONG, VarUI8FromI4); |
| SIMPLE(ULONG64, ULONG, VarUI8FromUI4); |
| NEGTST(ULONG64, LONG64, VarUI8FromI8); |
| |
| /* R4 (float) */ |
| SIMPLE(float, BYTE, VarR4FromUI1); |
| SIMPLE(float, SHORT, VarR4FromI2); |
| SIMPLE(float, signed char, VarR4FromI1); |
| SIMPLE(float, USHORT, VarR4FromUI2); |
| SIMPLE(float, LONG, VarR4FromI4); |
| SIMPLE(float, ULONG, VarR4FromUI4); |
| SIMPLE(float, LONG64, VarR4FromI8); |
| SIMPLE(float, ULONG64, VarR4FromUI8); |
| |
| /* R8 (double) */ |
| SIMPLE(double, BYTE, VarR8FromUI1); |
| SIMPLE(double, SHORT, VarR8FromI2); |
| SIMPLE(double, float, VarR8FromR4); |
| RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; } |
| SIMPLE(double, DATE, VarR8FromDate); |
| SIMPLE(double, signed char, VarR8FromI1); |
| SIMPLE(double, USHORT, VarR8FromUI2); |
| SIMPLE(double, LONG, VarR8FromI4); |
| SIMPLE(double, ULONG, VarR8FromUI4); |
| SIMPLE(double, LONG64, VarR8FromI8); |
| SIMPLE(double, ULONG64, VarR8FromUI8); |
| |
| |
| /* I1 |
| */ |
| |
| /************************************************************************ |
| * VarI1FromUI1 (OLEAUT32.244) |
| * |
| * Convert a VT_UI1 to a VT_I1. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut) |
| { |
| return _VarI1FromUI1(bIn, pcOut); |
| } |
| |
| /************************************************************************ |
| * VarI1FromI2 (OLEAUT32.245) |
| * |
| * Convert a VT_I2 to a VT_I1. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut) |
| { |
| return _VarI1FromI2(sIn, pcOut); |
| } |
| |
| /************************************************************************ |
| * VarI1FromI4 (OLEAUT32.246) |
| * |
| * Convert a VT_I4 to a VT_I1. |
| * |
| * PARAMS |
| * iIn [I] Source |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut) |
| { |
| return _VarI1FromI4(iIn, pcOut); |
| } |
| |
| /************************************************************************ |
| * VarI1FromR4 (OLEAUT32.247) |
| * |
| * Convert a VT_R4 to a VT_I1. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut) |
| { |
| return VarI1FromR8(fltIn, pcOut); |
| } |
| |
| /************************************************************************ |
| * VarI1FromR8 (OLEAUT32.248) |
| * |
| * Convert a VT_R8 to a VT_I1. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * See VarI8FromR8() for details concerning rounding. |
| */ |
| HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut) |
| { |
| if (dblIn < (double)I1_MIN || dblIn > (double)I1_MAX) |
| return DISP_E_OVERFLOW; |
| VARIANT_DutchRound(CHAR, dblIn, *pcOut); |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarI1FromDate (OLEAUT32.249) |
| * |
| * Convert a VT_DATE to a VT_I1. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut) |
| { |
| return VarI1FromR8(dateIn, pcOut); |
| } |
| |
| /************************************************************************ |
| * VarI1FromCy (OLEAUT32.250) |
| * |
| * Convert a VT_CY to a VT_I1. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut) |
| { |
| LONG i = I1_MAX + 1; |
| |
| VarI4FromCy(cyIn, &i); |
| return _VarI1FromI4(i, pcOut); |
| } |
| |
| /************************************************************************ |
| * VarI1FromStr (OLEAUT32.251) |
| * |
| * Convert a VT_BSTR to a VT_I1. |
| * |
| * PARAMS |
| * strIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut) |
| { |
| return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1); |
| } |
| |
| /************************************************************************ |
| * VarI1FromDisp (OLEAUT32.252) |
| * |
| * Convert a VT_DISPATCH to a VT_I1. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0); |
| } |
| |
| /************************************************************************ |
| * VarI1FromBool (OLEAUT32.253) |
| * |
| * Convert a VT_BOOL to a VT_I1. |
| * |
| * PARAMS |
| * boolIn [I] Source |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut) |
| { |
| return _VarI1FromBool(boolIn, pcOut); |
| } |
| |
| /************************************************************************ |
| * VarI1FromUI2 (OLEAUT32.254) |
| * |
| * Convert a VT_UI2 to a VT_I1. |
| * |
| * PARAMS |
| * usIn [I] Source |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut) |
| { |
| return _VarI1FromUI2(usIn, pcOut); |
| } |
| |
| /************************************************************************ |
| * VarI1FromUI4 (OLEAUT32.255) |
| * |
| * Convert a VT_UI4 to a VT_I1. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut) |
| { |
| return _VarI1FromUI4(ulIn, pcOut); |
| } |
| |
| /************************************************************************ |
| * VarI1FromDec (OLEAUT32.256) |
| * |
| * Convert a VT_DECIMAL to a VT_I1. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut) |
| { |
| LONG64 i64; |
| HRESULT hRet; |
| |
| hRet = VarI8FromDec(pdecIn, &i64); |
| |
| if (SUCCEEDED(hRet)) |
| hRet = _VarI1FromI8(i64, pcOut); |
| return hRet; |
| } |
| |
| /************************************************************************ |
| * VarI1FromI8 (OLEAUT32.376) |
| * |
| * Convert a VT_I8 to a VT_I1. |
| * |
| * PARAMS |
| * llIn [I] Source |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut) |
| { |
| return _VarI1FromI8(llIn, pcOut); |
| } |
| |
| /************************************************************************ |
| * VarI1FromUI8 (OLEAUT32.377) |
| * |
| * Convert a VT_UI8 to a VT_I1. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pcOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut) |
| { |
| return _VarI1FromUI8(ullIn, pcOut); |
| } |
| |
| /* UI1 |
| */ |
| |
| /************************************************************************ |
| * VarUI1FromI2 (OLEAUT32.130) |
| * |
| * Convert a VT_I2 to a VT_UI1. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut) |
| { |
| return _VarUI1FromI2(sIn, pbOut); |
| } |
| |
| /************************************************************************ |
| * VarUI1FromI4 (OLEAUT32.131) |
| * |
| * Convert a VT_I4 to a VT_UI1. |
| * |
| * PARAMS |
| * iIn [I] Source |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut) |
| { |
| return _VarUI1FromI4(iIn, pbOut); |
| } |
| |
| /************************************************************************ |
| * VarUI1FromR4 (OLEAUT32.132) |
| * |
| * Convert a VT_R4 to a VT_UI1. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut) |
| { |
| return VarUI1FromR8(fltIn, pbOut); |
| } |
| |
| /************************************************************************ |
| * VarUI1FromR8 (OLEAUT32.133) |
| * |
| * Convert a VT_R8 to a VT_UI1. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * See VarI8FromR8() for details concerning rounding. |
| */ |
| HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut) |
| { |
| if (dblIn < -0.5 || dblIn > (double)UI1_MAX) |
| return DISP_E_OVERFLOW; |
| VARIANT_DutchRound(BYTE, dblIn, *pbOut); |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarUI1FromCy (OLEAUT32.134) |
| * |
| * Convert a VT_CY to a VT_UI1. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * Negative values >= -5000 will be converted to 0. |
| */ |
| HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) |
| { |
| ULONG i = UI1_MAX + 1; |
| |
| VarUI4FromCy(cyIn, &i); |
| return _VarUI1FromUI4(i, pbOut); |
| } |
| |
| /************************************************************************ |
| * VarUI1FromDate (OLEAUT32.135) |
| * |
| * Convert a VT_DATE to a VT_UI1. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut) |
| { |
| return VarUI1FromR8(dateIn, pbOut); |
| } |
| |
| /************************************************************************ |
| * VarUI1FromStr (OLEAUT32.136) |
| * |
| * Convert a VT_BSTR to a VT_UI1. |
| * |
| * PARAMS |
| * strIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut) |
| { |
| return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1); |
| } |
| |
| /************************************************************************ |
| * VarUI1FromDisp (OLEAUT32.137) |
| * |
| * Convert a VT_DISPATCH to a VT_UI1. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0); |
| } |
| |
| /************************************************************************ |
| * VarUI1FromBool (OLEAUT32.138) |
| * |
| * Convert a VT_BOOL to a VT_UI1. |
| * |
| * PARAMS |
| * boolIn [I] Source |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut) |
| { |
| return _VarUI1FromBool(boolIn, pbOut); |
| } |
| |
| /************************************************************************ |
| * VarUI1FromI1 (OLEAUT32.237) |
| * |
| * Convert a VT_I1 to a VT_UI1. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut) |
| { |
| return _VarUI1FromI1(cIn, pbOut); |
| } |
| |
| /************************************************************************ |
| * VarUI1FromUI2 (OLEAUT32.238) |
| * |
| * Convert a VT_UI2 to a VT_UI1. |
| * |
| * PARAMS |
| * usIn [I] Source |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut) |
| { |
| return _VarUI1FromUI2(usIn, pbOut); |
| } |
| |
| /************************************************************************ |
| * VarUI1FromUI4 (OLEAUT32.239) |
| * |
| * Convert a VT_UI4 to a VT_UI1. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut) |
| { |
| return _VarUI1FromUI4(ulIn, pbOut); |
| } |
| |
| /************************************************************************ |
| * VarUI1FromDec (OLEAUT32.240) |
| * |
| * Convert a VT_DECIMAL to a VT_UI1. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut) |
| { |
| LONG64 i64; |
| HRESULT hRet; |
| |
| hRet = VarI8FromDec(pdecIn, &i64); |
| |
| if (SUCCEEDED(hRet)) |
| hRet = _VarUI1FromI8(i64, pbOut); |
| return hRet; |
| } |
| |
| /************************************************************************ |
| * VarUI1FromI8 (OLEAUT32.372) |
| * |
| * Convert a VT_I8 to a VT_UI1. |
| * |
| * PARAMS |
| * llIn [I] Source |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut) |
| { |
| return _VarUI1FromI8(llIn, pbOut); |
| } |
| |
| /************************************************************************ |
| * VarUI1FromUI8 (OLEAUT32.373) |
| * |
| * Convert a VT_UI8 to a VT_UI1. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pbOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut) |
| { |
| return _VarUI1FromUI8(ullIn, pbOut); |
| } |
| |
| |
| /* I2 |
| */ |
| |
| /************************************************************************ |
| * VarI2FromUI1 (OLEAUT32.48) |
| * |
| * Convert a VT_UI2 to a VT_I2. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut) |
| { |
| return _VarI2FromUI1(bIn, psOut); |
| } |
| |
| /************************************************************************ |
| * VarI2FromI4 (OLEAUT32.49) |
| * |
| * Convert a VT_I4 to a VT_I2. |
| * |
| * PARAMS |
| * iIn [I] Source |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut) |
| { |
| return _VarI2FromI4(iIn, psOut); |
| } |
| |
| /************************************************************************ |
| * VarI2FromR4 (OLEAUT32.50) |
| * |
| * Convert a VT_R4 to a VT_I2. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut) |
| { |
| return VarI2FromR8(fltIn, psOut); |
| } |
| |
| /************************************************************************ |
| * VarI2FromR8 (OLEAUT32.51) |
| * |
| * Convert a VT_R8 to a VT_I2. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * See VarI8FromR8() for details concerning rounding. |
| */ |
| HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut) |
| { |
| if (dblIn < (double)I2_MIN || dblIn > (double)I2_MAX) |
| return DISP_E_OVERFLOW; |
| VARIANT_DutchRound(SHORT, dblIn, *psOut); |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarI2FromCy (OLEAUT32.52) |
| * |
| * Convert a VT_CY to a VT_I2. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut) |
| { |
| LONG i = I2_MAX + 1; |
| |
| VarI4FromCy(cyIn, &i); |
| return _VarI2FromI4(i, psOut); |
| } |
| |
| /************************************************************************ |
| * VarI2FromDate (OLEAUT32.53) |
| * |
| * Convert a VT_DATE to a VT_I2. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut) |
| { |
| return VarI2FromR8(dateIn, psOut); |
| } |
| |
| /************************************************************************ |
| * VarI2FromStr (OLEAUT32.54) |
| * |
| * Convert a VT_BSTR to a VT_I2. |
| * |
| * PARAMS |
| * strIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if any parameter is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut) |
| { |
| return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2); |
| } |
| |
| /************************************************************************ |
| * VarI2FromDisp (OLEAUT32.55) |
| * |
| * Convert a VT_DISPATCH to a VT_I2. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pdispIn is invalid, |
| * DISP_E_OVERFLOW, if the value will not fit in the destination, |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0); |
| } |
| |
| /************************************************************************ |
| * VarI2FromBool (OLEAUT32.56) |
| * |
| * Convert a VT_BOOL to a VT_I2. |
| * |
| * PARAMS |
| * boolIn [I] Source |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut) |
| { |
| return _VarI2FromBool(boolIn, psOut); |
| } |
| |
| /************************************************************************ |
| * VarI2FromI1 (OLEAUT32.205) |
| * |
| * Convert a VT_I1 to a VT_I2. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut) |
| { |
| return _VarI2FromI1(cIn, psOut); |
| } |
| |
| /************************************************************************ |
| * VarI2FromUI2 (OLEAUT32.206) |
| * |
| * Convert a VT_UI2 to a VT_I2. |
| * |
| * PARAMS |
| * usIn [I] Source |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut) |
| { |
| return _VarI2FromUI2(usIn, psOut); |
| } |
| |
| /************************************************************************ |
| * VarI2FromUI4 (OLEAUT32.207) |
| * |
| * Convert a VT_UI4 to a VT_I2. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut) |
| { |
| return _VarI2FromUI4(ulIn, psOut); |
| } |
| |
| /************************************************************************ |
| * VarI2FromDec (OLEAUT32.208) |
| * |
| * Convert a VT_DECIMAL to a VT_I2. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut) |
| { |
| LONG64 i64; |
| HRESULT hRet; |
| |
| hRet = VarI8FromDec(pdecIn, &i64); |
| |
| if (SUCCEEDED(hRet)) |
| hRet = _VarI2FromI8(i64, psOut); |
| return hRet; |
| } |
| |
| /************************************************************************ |
| * VarI2FromI8 (OLEAUT32.346) |
| * |
| * Convert a VT_I8 to a VT_I2. |
| * |
| * PARAMS |
| * llIn [I] Source |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut) |
| { |
| return _VarI2FromI8(llIn, psOut); |
| } |
| |
| /************************************************************************ |
| * VarI2FromUI8 (OLEAUT32.347) |
| * |
| * Convert a VT_UI8 to a VT_I2. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * psOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut) |
| { |
| return _VarI2FromUI8(ullIn, psOut); |
| } |
| |
| /* UI2 |
| */ |
| |
| /************************************************************************ |
| * VarUI2FromUI1 (OLEAUT32.257) |
| * |
| * Convert a VT_UI1 to a VT_UI2. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut) |
| { |
| return _VarUI2FromUI1(bIn, pusOut); |
| } |
| |
| /************************************************************************ |
| * VarUI2FromI2 (OLEAUT32.258) |
| * |
| * Convert a VT_I2 to a VT_UI2. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut) |
| { |
| return _VarUI2FromI2(sIn, pusOut); |
| } |
| |
| /************************************************************************ |
| * VarUI2FromI4 (OLEAUT32.259) |
| * |
| * Convert a VT_I4 to a VT_UI2. |
| * |
| * PARAMS |
| * iIn [I] Source |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut) |
| { |
| return _VarUI2FromI4(iIn, pusOut); |
| } |
| |
| /************************************************************************ |
| * VarUI2FromR4 (OLEAUT32.260) |
| * |
| * Convert a VT_R4 to a VT_UI2. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut) |
| { |
| return VarUI2FromR8(fltIn, pusOut); |
| } |
| |
| /************************************************************************ |
| * VarUI2FromR8 (OLEAUT32.261) |
| * |
| * Convert a VT_R8 to a VT_UI2. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * See VarI8FromR8() for details concerning rounding. |
| */ |
| HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut) |
| { |
| if (dblIn < -0.5 || dblIn > (double)UI2_MAX) |
| return DISP_E_OVERFLOW; |
| VARIANT_DutchRound(USHORT, dblIn, *pusOut); |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarUI2FromDate (OLEAUT32.262) |
| * |
| * Convert a VT_DATE to a VT_UI2. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut) |
| { |
| return VarUI2FromR8(dateIn, pusOut); |
| } |
| |
| /************************************************************************ |
| * VarUI2FromCy (OLEAUT32.263) |
| * |
| * Convert a VT_CY to a VT_UI2. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * Negative values >= -5000 will be converted to 0. |
| */ |
| HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) |
| { |
| ULONG i = UI2_MAX + 1; |
| |
| VarUI4FromCy(cyIn, &i); |
| return _VarUI2FromUI4(i, pusOut); |
| } |
| |
| /************************************************************************ |
| * VarUI2FromStr (OLEAUT32.264) |
| * |
| * Convert a VT_BSTR to a VT_UI2. |
| * |
| * PARAMS |
| * strIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut) |
| { |
| return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2); |
| } |
| |
| /************************************************************************ |
| * VarUI2FromDisp (OLEAUT32.265) |
| * |
| * Convert a VT_DISPATCH to a VT_UI2. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0); |
| } |
| |
| /************************************************************************ |
| * VarUI2FromBool (OLEAUT32.266) |
| * |
| * Convert a VT_BOOL to a VT_UI2. |
| * |
| * PARAMS |
| * boolIn [I] Source |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut) |
| { |
| return _VarUI2FromBool(boolIn, pusOut); |
| } |
| |
| /************************************************************************ |
| * VarUI2FromI1 (OLEAUT32.267) |
| * |
| * Convert a VT_I1 to a VT_UI2. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut) |
| { |
| return _VarUI2FromI1(cIn, pusOut); |
| } |
| |
| /************************************************************************ |
| * VarUI2FromUI4 (OLEAUT32.268) |
| * |
| * Convert a VT_UI4 to a VT_UI2. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut) |
| { |
| return _VarUI2FromUI4(ulIn, pusOut); |
| } |
| |
| /************************************************************************ |
| * VarUI2FromDec (OLEAUT32.269) |
| * |
| * Convert a VT_DECIMAL to a VT_UI2. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut) |
| { |
| LONG64 i64; |
| HRESULT hRet; |
| |
| hRet = VarI8FromDec(pdecIn, &i64); |
| |
| if (SUCCEEDED(hRet)) |
| hRet = _VarUI2FromI8(i64, pusOut); |
| return hRet; |
| } |
| |
| /************************************************************************ |
| * VarUI2FromI8 (OLEAUT32.378) |
| * |
| * Convert a VT_I8 to a VT_UI2. |
| * |
| * PARAMS |
| * llIn [I] Source |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut) |
| { |
| return _VarUI2FromI8(llIn, pusOut); |
| } |
| |
| /************************************************************************ |
| * VarUI2FromUI8 (OLEAUT32.379) |
| * |
| * Convert a VT_UI8 to a VT_UI2. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pusOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut) |
| { |
| return _VarUI2FromUI8(ullIn, pusOut); |
| } |
| |
| /* I4 |
| */ |
| |
| /************************************************************************ |
| * VarI4FromUI1 (OLEAUT32.58) |
| * |
| * Convert a VT_UI1 to a VT_I4. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut) |
| { |
| return _VarI4FromUI1(bIn, piOut); |
| } |
| |
| /************************************************************************ |
| * VarI4FromI2 (OLEAUT32.59) |
| * |
| * Convert a VT_I2 to a VT_I4. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut) |
| { |
| return _VarI4FromI2(sIn, piOut); |
| } |
| |
| /************************************************************************ |
| * VarI4FromR4 (OLEAUT32.60) |
| * |
| * Convert a VT_R4 to a VT_I4. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut) |
| { |
| return VarI4FromR8(fltIn, piOut); |
| } |
| |
| /************************************************************************ |
| * VarI4FromR8 (OLEAUT32.61) |
| * |
| * Convert a VT_R8 to a VT_I4. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * See VarI8FromR8() for details concerning rounding. |
| */ |
| HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut) |
| { |
| if (dblIn < (double)I4_MIN || dblIn > (double)I4_MAX) |
| return DISP_E_OVERFLOW; |
| VARIANT_DutchRound(LONG, dblIn, *piOut); |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarI4FromCy (OLEAUT32.62) |
| * |
| * Convert a VT_CY to a VT_I4. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut) |
| { |
| double d = cyIn.int64 / CY_MULTIPLIER_F; |
| return VarI4FromR8(d, piOut); |
| } |
| |
| /************************************************************************ |
| * VarI4FromDate (OLEAUT32.63) |
| * |
| * Convert a VT_DATE to a VT_I4. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut) |
| { |
| return VarI4FromR8(dateIn, piOut); |
| } |
| |
| /************************************************************************ |
| * VarI4FromStr (OLEAUT32.64) |
| * |
| * Convert a VT_BSTR to a VT_I4. |
| * |
| * PARAMS |
| * strIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if any parameter is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if strIn cannot be converted |
| */ |
| HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut) |
| { |
| return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4); |
| } |
| |
| /************************************************************************ |
| * VarI4FromDisp (OLEAUT32.65) |
| * |
| * Convert a VT_DISPATCH to a VT_I4. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0); |
| } |
| |
| /************************************************************************ |
| * VarI4FromBool (OLEAUT32.66) |
| * |
| * Convert a VT_BOOL to a VT_I4. |
| * |
| * PARAMS |
| * boolIn [I] Source |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut) |
| { |
| return _VarI4FromBool(boolIn, piOut); |
| } |
| |
| /************************************************************************ |
| * VarI4FromI1 (OLEAUT32.209) |
| * |
| * Convert a VT_I4 to a VT_I4. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut) |
| { |
| return _VarI4FromI1(cIn, piOut); |
| } |
| |
| /************************************************************************ |
| * VarI4FromUI2 (OLEAUT32.210) |
| * |
| * Convert a VT_UI2 to a VT_I4. |
| * |
| * PARAMS |
| * usIn [I] Source |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut) |
| { |
| return _VarI4FromUI2(usIn, piOut); |
| } |
| |
| /************************************************************************ |
| * VarI4FromUI4 (OLEAUT32.211) |
| * |
| * Convert a VT_UI4 to a VT_I4. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut) |
| { |
| return _VarI4FromUI4(ulIn, piOut); |
| } |
| |
| /************************************************************************ |
| * VarI4FromDec (OLEAUT32.212) |
| * |
| * Convert a VT_DECIMAL to a VT_I4. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pdecIn is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut) |
| { |
| LONG64 i64; |
| HRESULT hRet; |
| |
| hRet = VarI8FromDec(pdecIn, &i64); |
| |
| if (SUCCEEDED(hRet)) |
| hRet = _VarI4FromI8(i64, piOut); |
| return hRet; |
| } |
| |
| /************************************************************************ |
| * VarI4FromI8 (OLEAUT32.348) |
| * |
| * Convert a VT_I8 to a VT_I4. |
| * |
| * PARAMS |
| * llIn [I] Source |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut) |
| { |
| return _VarI4FromI8(llIn, piOut); |
| } |
| |
| /************************************************************************ |
| * VarI4FromUI8 (OLEAUT32.349) |
| * |
| * Convert a VT_UI8 to a VT_I4. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * piOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut) |
| { |
| return _VarI4FromUI8(ullIn, piOut); |
| } |
| |
| /* UI4 |
| */ |
| |
| /************************************************************************ |
| * VarUI4FromUI1 (OLEAUT32.270) |
| * |
| * Convert a VT_UI1 to a VT_UI4. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut) |
| { |
| return _VarUI4FromUI1(bIn, pulOut); |
| } |
| |
| /************************************************************************ |
| * VarUI4FromI2 (OLEAUT32.271) |
| * |
| * Convert a VT_I2 to a VT_UI4. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut) |
| { |
| return _VarUI4FromI2(sIn, pulOut); |
| } |
| |
| /************************************************************************ |
| * VarUI4FromI4 (OLEAUT32.272) |
| * |
| * Convert a VT_I4 to a VT_UI4. |
| * |
| * PARAMS |
| * iIn [I] Source |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut) |
| { |
| return _VarUI4FromI4(iIn, pulOut); |
| } |
| |
| /************************************************************************ |
| * VarUI4FromR4 (OLEAUT32.273) |
| * |
| * Convert a VT_R4 to a VT_UI4. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut) |
| { |
| return VarUI4FromR8(fltIn, pulOut); |
| } |
| |
| /************************************************************************ |
| * VarUI4FromR8 (OLEAUT32.274) |
| * |
| * Convert a VT_R8 to a VT_UI4. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * See VarI8FromR8() for details concerning rounding. |
| */ |
| HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut) |
| { |
| if (dblIn < -0.5 || dblIn > (double)UI4_MAX) |
| return DISP_E_OVERFLOW; |
| VARIANT_DutchRound(ULONG, dblIn, *pulOut); |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarUI4FromDate (OLEAUT32.275) |
| * |
| * Convert a VT_DATE to a VT_UI4. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut) |
| { |
| return VarUI4FromR8(dateIn, pulOut); |
| } |
| |
| /************************************************************************ |
| * VarUI4FromCy (OLEAUT32.276) |
| * |
| * Convert a VT_CY to a VT_UI4. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut) |
| { |
| double d = cyIn.int64 / CY_MULTIPLIER_F; |
| return VarUI4FromR8(d, pulOut); |
| } |
| |
| /************************************************************************ |
| * VarUI4FromStr (OLEAUT32.277) |
| * |
| * Convert a VT_BSTR to a VT_UI4. |
| * |
| * PARAMS |
| * strIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if any parameter is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if strIn cannot be converted |
| */ |
| HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut) |
| { |
| return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4); |
| } |
| |
| /************************************************************************ |
| * VarUI4FromDisp (OLEAUT32.278) |
| * |
| * Convert a VT_DISPATCH to a VT_UI4. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0); |
| } |
| |
| /************************************************************************ |
| * VarUI4FromBool (OLEAUT32.279) |
| * |
| * Convert a VT_BOOL to a VT_UI4. |
| * |
| * PARAMS |
| * boolIn [I] Source |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut) |
| { |
| return _VarUI4FromBool(boolIn, pulOut); |
| } |
| |
| /************************************************************************ |
| * VarUI4FromI1 (OLEAUT32.280) |
| * |
| * Convert a VT_I1 to a VT_UI4. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut) |
| { |
| return _VarUI4FromI1(cIn, pulOut); |
| } |
| |
| /************************************************************************ |
| * VarUI4FromUI2 (OLEAUT32.281) |
| * |
| * Convert a VT_UI2 to a VT_UI4. |
| * |
| * PARAMS |
| * usIn [I] Source |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut) |
| { |
| return _VarUI4FromUI2(usIn, pulOut); |
| } |
| |
| /************************************************************************ |
| * VarUI4FromDec (OLEAUT32.282) |
| * |
| * Convert a VT_DECIMAL to a VT_UI4. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pdecIn is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut) |
| { |
| LONG64 i64; |
| HRESULT hRet; |
| |
| hRet = VarI8FromDec(pdecIn, &i64); |
| |
| if (SUCCEEDED(hRet)) |
| hRet = _VarUI4FromI8(i64, pulOut); |
| return hRet; |
| } |
| |
| /************************************************************************ |
| * VarUI4FromI8 (OLEAUT32.425) |
| * |
| * Convert a VT_I8 to a VT_UI4. |
| * |
| * PARAMS |
| * llIn [I] Source |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut) |
| { |
| return _VarUI4FromI8(llIn, pulOut); |
| } |
| |
| /************************************************************************ |
| * VarUI4FromUI8 (OLEAUT32.426) |
| * |
| * Convert a VT_UI8 to a VT_UI4. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pulOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut) |
| { |
| return _VarUI4FromUI8(ullIn, pulOut); |
| } |
| |
| /* I8 |
| */ |
| |
| /************************************************************************ |
| * VarI8FromUI1 (OLEAUT32.333) |
| * |
| * Convert a VT_UI1 to a VT_I8. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out) |
| { |
| return _VarI8FromUI1(bIn, pi64Out); |
| } |
| |
| |
| /************************************************************************ |
| * VarI8FromI2 (OLEAUT32.334) |
| * |
| * Convert a VT_I2 to a VT_I8. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out) |
| { |
| return _VarI8FromI2(sIn, pi64Out); |
| } |
| |
| /************************************************************************ |
| * VarI8FromR4 (OLEAUT32.335) |
| * |
| * Convert a VT_R4 to a VT_I8. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out) |
| { |
| return VarI8FromR8(fltIn, pi64Out); |
| } |
| |
| /************************************************************************ |
| * VarI8FromR8 (OLEAUT32.336) |
| * |
| * Convert a VT_R8 to a VT_I8. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * Only values that fit into 63 bits are accepted. Due to rounding issues, |
| * very high or low values will not be accurately converted. |
| * |
| * Numbers are rounded using Dutch rounding, as follows: |
| * |
| *| Fractional Part Sign Direction Example |
| *| --------------- ---- --------- ------- |
| *| < 0.5 + Down 0.4 -> 0.0 |
| *| < 0.5 - Up -0.4 -> 0.0 |
| *| > 0.5 + Up 0.6 -> 1.0 |
| *| < 0.5 - Up -0.6 -> -1.0 |
| *| = 0.5 + Up/Down Down if even, Up if odd |
| *| = 0.5 - Up/Down Up if even, Down if odd |
| * |
| * This system is often used in supermarkets. |
| */ |
| HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out) |
| { |
| if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0) |
| return DISP_E_OVERFLOW; |
| VARIANT_DutchRound(LONG64, dblIn, *pi64Out); |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarI8FromCy (OLEAUT32.337) |
| * |
| * Convert a VT_CY to a VT_I8. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| * |
| * NOTES |
| * All negative numbers are rounded down by 1, including those that are |
| * evenly divisible by 10000 (this is a Win32 bug that Wine mimics). |
| * Positive numbers are rounded using Dutch rounding: See VarI8FromR8() |
| * for details. |
| */ |
| HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out) |
| { |
| *pi64Out = cyIn.int64 / CY_MULTIPLIER; |
| |
| if (cyIn.int64 < 0) |
| (*pi64Out)--; /* Mimic Win32 bug */ |
| else |
| { |
| cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */ |
| |
| if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1))) |
| (*pi64Out)++; |
| } |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarI8FromDate (OLEAUT32.338) |
| * |
| * Convert a VT_DATE to a VT_I8. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out) |
| { |
| return VarI8FromR8(dateIn, pi64Out); |
| } |
| |
| /************************************************************************ |
| * VarI8FromStr (OLEAUT32.339) |
| * |
| * Convert a VT_BSTR to a VT_I8. |
| * |
| * PARAMS |
| * strIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out) |
| { |
| return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8); |
| } |
| |
| /************************************************************************ |
| * VarI8FromDisp (OLEAUT32.340) |
| * |
| * Convert a VT_DISPATCH to a VT_I8. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0); |
| } |
| |
| /************************************************************************ |
| * VarI8FromBool (OLEAUT32.341) |
| * |
| * Convert a VT_BOOL to a VT_I8. |
| * |
| * PARAMS |
| * boolIn [I] Source |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out) |
| { |
| return VarI8FromI2(boolIn, pi64Out); |
| } |
| |
| /************************************************************************ |
| * VarI8FromI1 (OLEAUT32.342) |
| * |
| * Convert a VT_I1 to a VT_I8. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out) |
| { |
| return _VarI8FromI1(cIn, pi64Out); |
| } |
| |
| /************************************************************************ |
| * VarI8FromUI2 (OLEAUT32.343) |
| * |
| * Convert a VT_UI2 to a VT_I8. |
| * |
| * PARAMS |
| * usIn [I] Source |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out) |
| { |
| return _VarI8FromUI2(usIn, pi64Out); |
| } |
| |
| /************************************************************************ |
| * VarI8FromUI4 (OLEAUT32.344) |
| * |
| * Convert a VT_UI4 to a VT_I8. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out) |
| { |
| return _VarI8FromUI4(ulIn, pi64Out); |
| } |
| |
| /************************************************************************ |
| * VarI8FromDec (OLEAUT32.345) |
| * |
| * Convert a VT_DECIMAL to a VT_I8. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out) |
| { |
| if (!DEC_SCALE(pdecIn)) |
| { |
| /* This decimal is just a 96 bit integer */ |
| if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG) |
| return E_INVALIDARG; |
| |
| if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000) |
| return DISP_E_OVERFLOW; |
| |
| if (DEC_SIGN(pdecIn)) |
| *pi64Out = -DEC_LO64(pdecIn); |
| else |
| *pi64Out = DEC_LO64(pdecIn); |
| return S_OK; |
| } |
| else |
| { |
| /* Decimal contains a floating point number */ |
| HRESULT hRet; |
| double dbl; |
| |
| hRet = VarR8FromDec(pdecIn, &dbl); |
| if (SUCCEEDED(hRet)) |
| hRet = VarI8FromR8(dbl, pi64Out); |
| return hRet; |
| } |
| } |
| |
| /************************************************************************ |
| * VarI8FromUI8 (OLEAUT32.427) |
| * |
| * Convert a VT_UI8 to a VT_I8. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pi64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out) |
| { |
| return _VarI8FromUI8(ullIn, pi64Out); |
| } |
| |
| /* UI8 |
| */ |
| |
| /************************************************************************ |
| * VarUI8FromI8 (OLEAUT32.428) |
| * |
| * Convert a VT_I8 to a VT_UI8. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out) |
| { |
| return _VarUI8FromI8(llIn, pui64Out); |
| } |
| |
| /************************************************************************ |
| * VarUI8FromUI1 (OLEAUT32.429) |
| * |
| * Convert a VT_UI1 to a VT_UI8. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out) |
| { |
| return _VarUI8FromUI1(bIn, pui64Out); |
| } |
| |
| /************************************************************************ |
| * VarUI8FromI2 (OLEAUT32.430) |
| * |
| * Convert a VT_I2 to a VT_UI8. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out) |
| { |
| return _VarUI8FromI2(sIn, pui64Out); |
| } |
| |
| /************************************************************************ |
| * VarUI8FromR4 (OLEAUT32.431) |
| * |
| * Convert a VT_R4 to a VT_UI8. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out) |
| { |
| return VarUI8FromR8(fltIn, pui64Out); |
| } |
| |
| /************************************************************************ |
| * VarUI8FromR8 (OLEAUT32.432) |
| * |
| * Convert a VT_R8 to a VT_UI8. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * See VarI8FromR8() for details concerning rounding. |
| */ |
| HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out) |
| { |
| if (dblIn < -0.5 || dblIn > 1.844674407370955e19) |
| return DISP_E_OVERFLOW; |
| VARIANT_DutchRound(ULONG64, dblIn, *pui64Out); |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarUI8FromCy (OLEAUT32.433) |
| * |
| * Convert a VT_CY to a VT_UI8. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * Negative values >= -5000 will be converted to 0. |
| */ |
| HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out) |
| { |
| if (cyIn.int64 < 0) |
| { |
| if (cyIn.int64 < -CY_HALF) |
| return DISP_E_OVERFLOW; |
| *pui64Out = 0; |
| } |
| else |
| { |
| *pui64Out = cyIn.int64 / CY_MULTIPLIER; |
| |
| cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */ |
| |
| if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1))) |
| (*pui64Out)++; |
| } |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarUI8FromDate (OLEAUT32.434) |
| * |
| * Convert a VT_DATE to a VT_UI8. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out) |
| { |
| return VarUI8FromR8(dateIn, pui64Out); |
| } |
| |
| /************************************************************************ |
| * VarUI8FromStr (OLEAUT32.435) |
| * |
| * Convert a VT_BSTR to a VT_UI8. |
| * |
| * PARAMS |
| * strIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out) |
| { |
| return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8); |
| } |
| |
| /************************************************************************ |
| * VarUI8FromDisp (OLEAUT32.436) |
| * |
| * Convert a VT_DISPATCH to a VT_UI8. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0); |
| } |
| |
| /************************************************************************ |
| * VarUI8FromBool (OLEAUT32.437) |
| * |
| * Convert a VT_BOOL to a VT_UI8. |
| * |
| * PARAMS |
| * boolIn [I] Source |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out) |
| { |
| return VarI8FromI2(boolIn, (LONG64 *)pui64Out); |
| } |
| /************************************************************************ |
| * VarUI8FromI1 (OLEAUT32.438) |
| * |
| * Convert a VT_I1 to a VT_UI8. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out) |
| { |
| return _VarUI8FromI1(cIn, pui64Out); |
| } |
| |
| /************************************************************************ |
| * VarUI8FromUI2 (OLEAUT32.439) |
| * |
| * Convert a VT_UI2 to a VT_UI8. |
| * |
| * PARAMS |
| * usIn [I] Source |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out) |
| { |
| return _VarUI8FromUI2(usIn, pui64Out); |
| } |
| |
| /************************************************************************ |
| * VarUI8FromUI4 (OLEAUT32.440) |
| * |
| * Convert a VT_UI4 to a VT_UI8. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out) |
| { |
| return _VarUI8FromUI4(ulIn, pui64Out); |
| } |
| |
| /************************************************************************ |
| * VarUI8FromDec (OLEAUT32.441) |
| * |
| * Convert a VT_DECIMAL to a VT_UI8. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * pui64Out [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * Under native Win32, if the source value has a scale of 0, its sign is |
| * ignored, i.e. this function takes the absolute value rather than fail |
| * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation |
| * (use VarAbs() on pDecIn first if you really want this behaviour). |
| */ |
| HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out) |
| { |
| if (!DEC_SCALE(pdecIn)) |
| { |
| /* This decimal is just a 96 bit integer */ |
| if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG) |
| return E_INVALIDARG; |
| |
| if (DEC_HI32(pdecIn)) |
| return DISP_E_OVERFLOW; |
| |
| if (DEC_SIGN(pdecIn)) |
| { |
| WARN("Sign would be ignored under Win32!\n"); |
| return DISP_E_OVERFLOW; |
| } |
| |
| *pui64Out = DEC_LO64(pdecIn); |
| return S_OK; |
| } |
| else |
| { |
| /* Decimal contains a floating point number */ |
| HRESULT hRet; |
| double dbl; |
| |
| hRet = VarR8FromDec(pdecIn, &dbl); |
| if (SUCCEEDED(hRet)) |
| hRet = VarUI8FromR8(dbl, pui64Out); |
| return hRet; |
| } |
| } |
| |
| /* R4 |
| */ |
| |
| /************************************************************************ |
| * VarR4FromUI1 (OLEAUT32.68) |
| * |
| * Convert a VT_UI1 to a VT_R4. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut) |
| { |
| return _VarR4FromUI1(bIn, pFltOut); |
| } |
| |
| /************************************************************************ |
| * VarR4FromI2 (OLEAUT32.69) |
| * |
| * Convert a VT_I2 to a VT_R4. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut) |
| { |
| return _VarR4FromI2(sIn, pFltOut); |
| } |
| |
| /************************************************************************ |
| * VarR4FromI4 (OLEAUT32.70) |
| * |
| * Convert a VT_I4 to a VT_R4. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut) |
| { |
| return _VarR4FromI4(lIn, pFltOut); |
| } |
| |
| /************************************************************************ |
| * VarR4FromR8 (OLEAUT32.71) |
| * |
| * Convert a VT_R8 to a VT_R4. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination. |
| */ |
| HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut) |
| { |
| double d = dblIn < 0.0 ? -dblIn : dblIn; |
| if (d > R4_MAX) return DISP_E_OVERFLOW; |
| *pFltOut = dblIn; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarR4FromCy (OLEAUT32.72) |
| * |
| * Convert a VT_CY to a VT_R4. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut) |
| { |
| *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarR4FromDate (OLEAUT32.73) |
| * |
| * Convert a VT_DATE to a VT_R4. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination. |
| */ |
| HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut) |
| { |
| return VarR4FromR8(dateIn, pFltOut); |
| } |
| |
| /************************************************************************ |
| * VarR4FromStr (OLEAUT32.74) |
| * |
| * Convert a VT_BSTR to a VT_R4. |
| * |
| * PARAMS |
| * strIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if strIn or pFltOut is invalid. |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut) |
| { |
| return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4); |
| } |
| |
| /************************************************************************ |
| * VarR4FromDisp (OLEAUT32.75) |
| * |
| * Convert a VT_DISPATCH to a VT_R4. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0); |
| } |
| |
| /************************************************************************ |
| * VarR4FromBool (OLEAUT32.76) |
| * |
| * Convert a VT_BOOL to a VT_R4. |
| * |
| * PARAMS |
| * boolIn [I] Source |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut) |
| { |
| return VarR4FromI2(boolIn, pFltOut); |
| } |
| |
| /************************************************************************ |
| * VarR4FromI1 (OLEAUT32.213) |
| * |
| * Convert a VT_I1 to a VT_R4. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut) |
| { |
| return _VarR4FromI1(cIn, pFltOut); |
| } |
| |
| /************************************************************************ |
| * VarR4FromUI2 (OLEAUT32.214) |
| * |
| * Convert a VT_UI2 to a VT_R4. |
| * |
| * PARAMS |
| * usIn [I] Source |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut) |
| { |
| return _VarR4FromUI2(usIn, pFltOut); |
| } |
| |
| /************************************************************************ |
| * VarR4FromUI4 (OLEAUT32.215) |
| * |
| * Convert a VT_UI4 to a VT_R4. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut) |
| { |
| return _VarR4FromUI4(ulIn, pFltOut); |
| } |
| |
| /************************************************************************ |
| * VarR4FromDec (OLEAUT32.216) |
| * |
| * Convert a VT_DECIMAL to a VT_R4. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid. |
| */ |
| HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut) |
| { |
| BYTE scale = DEC_SCALE(pDecIn); |
| int divisor = 1; |
| double highPart; |
| |
| if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG) |
| return E_INVALIDARG; |
| |
| while (scale--) |
| divisor *= 10; |
| |
| if (DEC_SIGN(pDecIn)) |
| divisor = -divisor; |
| |
| if (DEC_HI32(pDecIn)) |
| { |
| highPart = (double)DEC_HI32(pDecIn) / (double)divisor; |
| highPart *= 4294967296.0F; |
| highPart *= 4294967296.0F; |
| } |
| else |
| highPart = 0.0; |
| |
| *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarR4FromI8 (OLEAUT32.360) |
| * |
| * Convert a VT_I8 to a VT_R4. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut) |
| { |
| return _VarR4FromI8(llIn, pFltOut); |
| } |
| |
| /************************************************************************ |
| * VarR4FromUI8 (OLEAUT32.361) |
| * |
| * Convert a VT_UI8 to a VT_R4. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pFltOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut) |
| { |
| return _VarR4FromUI8(ullIn, pFltOut); |
| } |
| |
| /************************************************************************ |
| * VarR4CmpR8 (OLEAUT32.316) |
| * |
| * Compare a VT_R4 to a VT_R8. |
| * |
| * PARAMS |
| * fltLeft [I] Source |
| * dblRight [I] Value to compare |
| * |
| * RETURNS |
| * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than, |
| * equal to or greater than dblRight respectively. |
| */ |
| HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight) |
| { |
| if (fltLeft < dblRight) |
| return VARCMP_LT; |
| else if (fltLeft > dblRight) |
| return VARCMP_GT; |
| return VARCMP_EQ; |
| } |
| |
| /* R8 |
| */ |
| |
| /************************************************************************ |
| * VarR8FromUI1 (OLEAUT32.78) |
| * |
| * Convert a VT_UI1 to a VT_R8. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut) |
| { |
| return _VarR8FromUI1(bIn, pDblOut); |
| } |
| |
| /************************************************************************ |
| * VarR8FromI2 (OLEAUT32.79) |
| * |
| * Convert a VT_I2 to a VT_R8. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut) |
| { |
| return _VarR8FromI2(sIn, pDblOut); |
| } |
| |
| /************************************************************************ |
| * VarR8FromI4 (OLEAUT32.80) |
| * |
| * Convert a VT_I4 to a VT_R8. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut) |
| { |
| return _VarR8FromI4(lIn, pDblOut); |
| } |
| |
| /************************************************************************ |
| * VarR8FromR4 (OLEAUT32.81) |
| * |
| * Convert a VT_R4 to a VT_R8. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut) |
| { |
| return _VarR8FromR4(fltIn, pDblOut); |
| } |
| |
| /************************************************************************ |
| * VarR8FromCy (OLEAUT32.82) |
| * |
| * Convert a VT_CY to a VT_R8. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut) |
| { |
| return _VarR8FromCy(cyIn, pDblOut); |
| } |
| |
| /************************************************************************ |
| * VarR8FromDate (OLEAUT32.83) |
| * |
| * Convert a VT_DATE to a VT_R8. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut) |
| { |
| return _VarR8FromDate(dateIn, pDblOut); |
| } |
| |
| /************************************************************************ |
| * VarR8FromStr (OLEAUT32.84) |
| * |
| * Convert a VT_BSTR to a VT_R8. |
| * |
| * PARAMS |
| * strIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if strIn or pDblOut is invalid. |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut) |
| { |
| return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8); |
| } |
| |
| /************************************************************************ |
| * VarR8FromDisp (OLEAUT32.85) |
| * |
| * Convert a VT_DISPATCH to a VT_R8. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0); |
| } |
| |
| /************************************************************************ |
| * VarR8FromBool (OLEAUT32.86) |
| * |
| * Convert a VT_BOOL to a VT_R8. |
| * |
| * PARAMS |
| * boolIn [I] Source |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut) |
| { |
| return VarR8FromI2(boolIn, pDblOut); |
| } |
| |
| /************************************************************************ |
| * VarR8FromI1 (OLEAUT32.217) |
| * |
| * Convert a VT_I1 to a VT_R8. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut) |
| { |
| return _VarR8FromI1(cIn, pDblOut); |
| } |
| |
| /************************************************************************ |
| * VarR8FromUI2 (OLEAUT32.218) |
| * |
| * Convert a VT_UI2 to a VT_R8. |
| * |
| * PARAMS |
| * usIn [I] Source |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut) |
| { |
| return _VarR8FromUI2(usIn, pDblOut); |
| } |
| |
| /************************************************************************ |
| * VarR8FromUI4 (OLEAUT32.219) |
| * |
| * Convert a VT_UI4 to a VT_R8. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut) |
| { |
| return _VarR8FromUI4(ulIn, pDblOut); |
| } |
| |
| /************************************************************************ |
| * VarR8FromDec (OLEAUT32.220) |
| * |
| * Convert a VT_DECIMAL to a VT_R8. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid. |
| */ |
| HRESULT WINAPI VarR8FromDec(DECIMAL* pDecIn, double *pDblOut) |
| { |
| BYTE scale = DEC_SCALE(pDecIn); |
| double divisor = 1.0, highPart; |
| |
| if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG) |
| return E_INVALIDARG; |
| |
| while (scale--) |
| divisor *= 10; |
| |
| if (DEC_SIGN(pDecIn)) |
| divisor = -divisor; |
| |
| if (DEC_HI32(pDecIn)) |
| { |
| highPart = (double)DEC_HI32(pDecIn) / divisor; |
| highPart *= 4294967296.0F; |
| highPart *= 4294967296.0F; |
| } |
| else |
| highPart = 0.0; |
| |
| *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarR8FromI8 (OLEAUT32.362) |
| * |
| * Convert a VT_I8 to a VT_R8. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut) |
| { |
| return _VarR8FromI8(llIn, pDblOut); |
| } |
| |
| /************************************************************************ |
| * VarR8FromUI8 (OLEAUT32.363) |
| * |
| * Convert a VT_UI8 to a VT_R8. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut) |
| { |
| return _VarR8FromUI8(ullIn, pDblOut); |
| } |
| |
| /************************************************************************ |
| * VarR8Pow (OLEAUT32.315) |
| * |
| * Raise a VT_R8 to a power. |
| * |
| * PARAMS |
| * dblLeft [I] Source |
| * dblPow [I] Power to raise dblLeft by |
| * pDblOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. pDblOut contains dblLeft to the power of dblRight. |
| */ |
| HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut) |
| { |
| *pDblOut = pow(dblLeft, dblPow); |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarR8Round (OLEAUT32.317) |
| * |
| * Round a VT_R8 to a given number of decimal points. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * nDig [I] Number of decimal points to round to |
| * pDblOut [O] Destination for rounded number |
| * |
| * RETURNS |
| * Success: S_OK. pDblOut is rounded to nDig digits. |
| * Failure: E_INVALIDARG, if cDecimals is less than 0. |
| * |
| * NOTES |
| * The native version of this function rounds using the internal |
| * binary representation of the number. Wine uses the dutch rounding |
| * convention, so therefore small differences can occur in the value returned. |
| * MSDN says that you should use your own rounding function if you want |
| * rounding to be predictable in your application. |
| */ |
| HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut) |
| { |
| double scale, whole, fract; |
| |
| if (nDig < 0) |
| return E_INVALIDARG; |
| |
| scale = pow(10.0, nDig); |
| |
| dblIn *= scale; |
| whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn); |
| fract = dblIn - whole; |
| |
| if (fract > 0.5) |
| dblIn = whole + 1.0; |
| else if (fract == 0.5) |
| dblIn = whole + fmod(whole, 2.0); |
| else if (fract >= 0.0) |
| dblIn = whole; |
| else if (fract == -0.5) |
| dblIn = whole - fmod(whole, 2.0); |
| else if (fract > -0.5) |
| dblIn = whole; |
| else |
| dblIn = whole - 1.0; |
| |
| *pDblOut = dblIn / scale; |
| return S_OK; |
| } |
| |
| /* CY |
| */ |
| |
| /* Powers of 10 from 0..4 D.P. */ |
| static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000, |
| CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER }; |
| |
| /************************************************************************ |
| * VarCyFromUI1 (OLEAUT32.98) |
| * |
| * Convert a VT_UI1 to a VT_CY. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut) |
| { |
| return VarCyFromR8(bIn, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCyFromI2 (OLEAUT32.99) |
| * |
| * Convert a VT_I2 to a VT_CY. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut) |
| { |
| return VarCyFromR8(sIn, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCyFromI4 (OLEAUT32.100) |
| * |
| * Convert a VT_I4 to a VT_CY. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut) |
| { |
| return VarCyFromR8(lIn, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCyFromR4 (OLEAUT32.101) |
| * |
| * Convert a VT_R4 to a VT_CY. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut) |
| { |
| return VarCyFromR8(fltIn, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCyFromR8 (OLEAUT32.102) |
| * |
| * Convert a VT_R8 to a VT_CY. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut) |
| { |
| #if defined(__GNUC__) && defined(__i386__) |
| /* This code gives identical results to Win32 on Intel. |
| * Here we use fp exceptions to catch overflows when storing the value. |
| */ |
| static const unsigned short r8_fpcontrol = 0x137f; |
| static const double r8_multiplier = CY_MULTIPLIER_F; |
| unsigned short old_fpcontrol, result_fpstatus; |
| |
| /* Clear exceptions, save the old fp state and load the new state */ |
| __asm__ __volatile__( "fnclex" ); |
| __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : ); |
| __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) ); |
| /* Perform the conversion. */ |
| __asm__ __volatile__( "fldl %0" : : "m" (dblIn) ); |
| __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) ); |
| __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) ); |
| /* Save the resulting fp state, load the old state and clear exceptions */ |
| __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : ); |
| __asm__ __volatile__( "fnclex" ); |
| __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) ); |
| |
| if (result_fpstatus & 0x9) /* Overflow | Invalid */ |
| return DISP_E_OVERFLOW; |
| return S_OK; |
| #else |
| /* This version produces slightly different results for boundary cases */ |
| if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807) |
| return DISP_E_OVERFLOW; |
| dblIn *= CY_MULTIPLIER_F; |
| VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64); |
| #endif |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarCyFromDate (OLEAUT32.103) |
| * |
| * Convert a VT_DATE to a VT_CY. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut) |
| { |
| return VarCyFromR8(dateIn, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCyFromStr (OLEAUT32.104) |
| * |
| * Convert a VT_BSTR to a VT_CY. |
| * |
| * PARAMS |
| * strIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut) |
| { |
| return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY); |
| } |
| |
| /************************************************************************ |
| * VarCyFromDisp (OLEAUT32.105) |
| * |
| * Convert a VT_DISPATCH to a VT_CY. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0); |
| } |
| |
| /************************************************************************ |
| * VarCyFromBool (OLEAUT32.106) |
| * |
| * Convert a VT_BOOL to a VT_CY. |
| * |
| * PARAMS |
| * boolIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| * |
| * NOTES |
| * While the sign of the boolean is stored in the currency, the value is |
| * converted to either 0 or 1. |
| */ |
| HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut) |
| { |
| return VarCyFromR8(boolIn, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCyFromI1 (OLEAUT32.225) |
| * |
| * Convert a VT_I1 to a VT_CY. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut) |
| { |
| return VarCyFromR8(cIn, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCyFromUI2 (OLEAUT32.226) |
| * |
| * Convert a VT_UI2 to a VT_CY. |
| * |
| * PARAMS |
| * usIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut) |
| { |
| return VarCyFromR8(usIn, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCyFromUI4 (OLEAUT32.227) |
| * |
| * Convert a VT_UI4 to a VT_CY. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut) |
| { |
| return VarCyFromR8(ulIn, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCyFromDec (OLEAUT32.228) |
| * |
| * Convert a VT_DECIMAL to a VT_CY. |
| * |
| * PARAMS |
| * pdecIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut) |
| { |
| DECIMAL rounded; |
| HRESULT hRet; |
| |
| hRet = VarDecRound(pdecIn, 4, &rounded); |
| |
| if (SUCCEEDED(hRet)) |
| { |
| double d; |
| |
| if (DEC_HI32(&rounded)) |
| return DISP_E_OVERFLOW; |
| |
| /* Note: Without the casts this promotes to int64 which loses precision */ |
| d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)]; |
| if (DEC_SIGN(&rounded)) |
| d = -d; |
| return VarCyFromR8(d, pCyOut); |
| } |
| return hRet; |
| } |
| |
| /************************************************************************ |
| * VarCyFromI8 (OLEAUT32.366) |
| * |
| * Convert a VT_I8 to a VT_CY. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut) |
| { |
| if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW; |
| pCyOut->int64 = llIn * CY_MULTIPLIER; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarCyFromUI8 (OLEAUT32.375) |
| * |
| * Convert a VT_UI8 to a VT_CY. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut) |
| { |
| return VarCyFromR8(ullIn, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCyAdd (OLEAUT32.299) |
| * |
| * Add one CY to another. |
| * |
| * PARAMS |
| * cyLeft [I] Source |
| * cyRight [I] Value to add |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut) |
| { |
| double l,r; |
| _VarR8FromCy(cyLeft, &l); |
| _VarR8FromCy(cyRight, &r); |
| l = l + r; |
| return VarCyFromR8(l, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCyMul (OLEAUT32.303) |
| * |
| * Multiply one CY by another. |
| * |
| * PARAMS |
| * cyLeft [I] Source |
| * cyRight [I] Value to multiply by |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut) |
| { |
| double l,r; |
| _VarR8FromCy(cyLeft, &l); |
| _VarR8FromCy(cyRight, &r); |
| l = l * r; |
| return VarCyFromR8(l, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCyMulI4 (OLEAUT32.304) |
| * |
| * Multiply one CY by a VT_I4. |
| * |
| * PARAMS |
| * cyLeft [I] Source |
| * lRight [I] Value to multiply by |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut) |
| { |
| double d; |
| |
| _VarR8FromCy(cyLeft, &d); |
| d = d * lRight; |
| return VarCyFromR8(d, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCySub (OLEAUT32.305) |
| * |
| * Subtract one CY from another. |
| * |
| * PARAMS |
| * cyLeft [I] Source |
| * cyRight [I] Value to subtract |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut) |
| { |
| double l,r; |
| _VarR8FromCy(cyLeft, &l); |
| _VarR8FromCy(cyRight, &r); |
| l = l - r; |
| return VarCyFromR8(l, pCyOut); |
| } |
| |
| /************************************************************************ |
| * VarCyAbs (OLEAUT32.306) |
| * |
| * Convert a VT_CY into its absolute value. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. pCyOut contains the absolute value. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut) |
| { |
| if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo) |
| return DISP_E_OVERFLOW; |
| |
| pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarCyFix (OLEAUT32.307) |
| * |
| * Return the integer part of a VT_CY. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * - The difference between this function and VarCyInt() is that VarCyInt() rounds |
| * negative numbers away from 0, while this function rounds them towards zero. |
| */ |
| HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut) |
| { |
| pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER; |
| pCyOut->int64 *= CY_MULTIPLIER; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarCyInt (OLEAUT32.308) |
| * |
| * Return the integer part of a VT_CY. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * - The difference between this function and VarCyFix() is that VarCyFix() rounds |
| * negative numbers towards 0, while this function rounds them away from zero. |
| */ |
| HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut) |
| { |
| pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER; |
| pCyOut->int64 *= CY_MULTIPLIER; |
| |
| if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0) |
| { |
| pCyOut->int64 -= CY_MULTIPLIER; |
| } |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarCyNeg (OLEAUT32.309) |
| * |
| * Change the sign of a VT_CY. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut) |
| { |
| if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo) |
| return DISP_E_OVERFLOW; |
| |
| pCyOut->int64 = -cyIn.int64; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarCyRound (OLEAUT32.310) |
| * |
| * Change the precision of a VT_CY. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * cDecimals [I] New number of decimals to keep |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if cDecimals is less than 0. |
| */ |
| HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut) |
| { |
| if (cDecimals < 0) |
| return E_INVALIDARG; |
| |
| if (cDecimals > 3) |
| { |
| /* Rounding to more precision than we have */ |
| *pCyOut = cyIn; |
| return S_OK; |
| } |
| else |
| { |
| double d, div = CY_Divisors[cDecimals]; |
| |
| _VarR8FromCy(cyIn, &d); |
| d = d * div; |
| VARIANT_DutchRound(LONGLONG, d, pCyOut->int64) |
| d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F; |
| VARIANT_DutchRound(LONGLONG, d, pCyOut->int64) |
| return S_OK; |
| } |
| } |
| |
| /************************************************************************ |
| * VarCyCmp (OLEAUT32.311) |
| * |
| * Compare two VT_CY values. |
| * |
| * PARAMS |
| * cyLeft [I] Source |
| * cyRight [I] Value to compare |
| * |
| * RETURNS |
| * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to |
| * compare is less, equal or greater than source respectively. |
| * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison |
| */ |
| HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight) |
| { |
| HRESULT hRet; |
| CY result; |
| |
| /* Subtract right from left, and compare the result to 0 */ |
| hRet = VarCySub(cyLeft, cyRight, &result); |
| |
| if (SUCCEEDED(hRet)) |
| { |
| if (result.int64 < 0) |
| hRet = (HRESULT)VARCMP_LT; |
| else if (result.int64 > 0) |
| hRet = (HRESULT)VARCMP_GT; |
| else |
| hRet = (HRESULT)VARCMP_EQ; |
| } |
| return hRet; |
| } |
| |
| /************************************************************************ |
| * VarCyCmpR8 (OLEAUT32.312) |
| * |
| * Compare a VT_CY to a double |
| * |
| * PARAMS |
| * cyLeft [I] Currency Source |
| * dblRight [I] double to compare to cyLeft |
| * |
| * RETURNS |
| * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is |
| * less than, equal to or greater than cyLeft respectively. |
| * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison |
| */ |
| HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight) |
| { |
| HRESULT hRet; |
| CY cyRight; |
| |
| hRet = VarCyFromR8(dblRight, &cyRight); |
| |
| if (SUCCEEDED(hRet)) |
| hRet = VarCyCmp(cyLeft, cyRight); |
| |
| return hRet; |
| } |
| |
| /************************************************************************ |
| * VarCyMulI8 (OLEAUT32.329) |
| * |
| * Multiply a VT_CY by a VT_I8. |
| * |
| * PARAMS |
| * cyLeft [I] Source |
| * llRight [I] Value to multiply by |
| * pCyOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut) |
| { |
| double d; |
| |
| _VarR8FromCy(cyLeft, &d); |
| d = d * (double)llRight; |
| return VarCyFromR8(d, pCyOut); |
| } |
| |
| /* DECIMAL |
| */ |
| |
| /************************************************************************ |
| * VarDecFromUI1 (OLEAUT32.190) |
| * |
| * Convert a VT_UI1 to a DECIMAL. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut) |
| { |
| return VarDecFromUI4(bIn, pDecOut); |
| } |
| |
| /************************************************************************ |
| * VarDecFromI2 (OLEAUT32.191) |
| * |
| * Convert a VT_I2 to a DECIMAL. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut) |
| { |
| return VarDecFromI4(sIn, pDecOut); |
| } |
| |
| /************************************************************************ |
| * VarDecFromI4 (OLEAUT32.192) |
| * |
| * Convert a VT_I4 to a DECIMAL. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut) |
| { |
| DEC_HI32(pDecOut) = 0; |
| DEC_MID32(pDecOut) = 0; |
| |
| if (lIn < 0) |
| { |
| DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); |
| DEC_LO32(pDecOut) = -lIn; |
| } |
| else |
| { |
| DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); |
| DEC_LO32(pDecOut) = lIn; |
| } |
| return S_OK; |
| } |
| |
| #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT)) |
| |
| /************************************************************************ |
| * VarDecFromR4 (OLEAUT32.193) |
| * |
| * Convert a VT_R4 to a DECIMAL. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut) |
| { |
| WCHAR buff[256]; |
| |
| sprintfW( buff, szFloatFormatW, fltIn ); |
| return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut); |
| } |
| |
| /************************************************************************ |
| * VarDecFromR8 (OLEAUT32.194) |
| * |
| * Convert a VT_R8 to a DECIMAL. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut) |
| { |
| WCHAR buff[256]; |
| |
| sprintfW( buff, szDoubleFormatW, dblIn ); |
| return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut); |
| } |
| |
| /************************************************************************ |
| * VarDecFromDate (OLEAUT32.195) |
| * |
| * Convert a VT_DATE to a DECIMAL. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut) |
| { |
| return VarDecFromR8(dateIn, pDecOut); |
| } |
| |
| /************************************************************************ |
| * VarDecFromCy (OLEAUT32.196) |
| * |
| * Convert a VT_CY to a DECIMAL. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut) |
| { |
| DEC_HI32(pDecOut) = 0; |
| |
| /* Note: This assumes 2s complement integer representation */ |
| if (cyIn.s.Hi & 0x80000000) |
| { |
| DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4); |
| DEC_LO64(pDecOut) = -cyIn.int64; |
| } |
| else |
| { |
| DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4); |
| DEC_MID32(pDecOut) = cyIn.s.Hi; |
| DEC_LO32(pDecOut) = cyIn.s.Lo; |
| } |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarDecFromStr (OLEAUT32.197) |
| * |
| * Convert a VT_BSTR to a DECIMAL. |
| * |
| * PARAMS |
| * strIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut) |
| { |
| return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL); |
| } |
| |
| /************************************************************************ |
| * VarDecFromDisp (OLEAUT32.198) |
| * |
| * Convert a VT_DISPATCH to a DECIMAL. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0); |
| } |
| |
| /************************************************************************ |
| * VarDecFromBool (OLEAUT32.199) |
| * |
| * Convert a VT_BOOL to a DECIMAL. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| * |
| * NOTES |
| * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE). |
| */ |
| HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut) |
| { |
| DEC_HI32(pDecOut) = 0; |
| DEC_MID32(pDecOut) = 0; |
| if (bIn) |
| { |
| DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); |
| DEC_LO32(pDecOut) = 1; |
| } |
| else |
| { |
| DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); |
| DEC_LO32(pDecOut) = 0; |
| } |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarDecFromI1 (OLEAUT32.241) |
| * |
| * Convert a VT_I1 to a DECIMAL. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut) |
| { |
| return VarDecFromI4(cIn, pDecOut); |
| } |
| |
| /************************************************************************ |
| * VarDecFromUI2 (OLEAUT32.242) |
| * |
| * Convert a VT_UI2 to a DECIMAL. |
| * |
| * PARAMS |
| * usIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut) |
| { |
| return VarDecFromUI4(usIn, pDecOut); |
| } |
| |
| /************************************************************************ |
| * VarDecFromUI4 (OLEAUT32.243) |
| * |
| * Convert a VT_UI4 to a DECIMAL. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut) |
| { |
| DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); |
| DEC_HI32(pDecOut) = 0; |
| DEC_MID32(pDecOut) = 0; |
| DEC_LO32(pDecOut) = ulIn; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarDecFromI8 (OLEAUT32.374) |
| * |
| * Convert a VT_I8 to a DECIMAL. |
| * |
| * PARAMS |
| * llIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut) |
| { |
| PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn; |
| |
| DEC_HI32(pDecOut) = 0; |
| |
| /* Note: This assumes 2s complement integer representation */ |
| if (pLi->u.HighPart & 0x80000000) |
| { |
| DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); |
| DEC_LO64(pDecOut) = -pLi->QuadPart; |
| } |
| else |
| { |
| DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); |
| DEC_MID32(pDecOut) = pLi->u.HighPart; |
| DEC_LO32(pDecOut) = pLi->u.LowPart; |
| } |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarDecFromUI8 (OLEAUT32.375) |
| * |
| * Convert a VT_UI8 to a DECIMAL. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut) |
| { |
| DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); |
| DEC_HI32(pDecOut) = 0; |
| DEC_LO64(pDecOut) = ullIn; |
| return S_OK; |
| } |
| |
| /* Make two DECIMALS the same scale; used by math functions below */ |
| static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft, |
| const DECIMAL** ppDecRight, |
| DECIMAL* pDecOut) |
| { |
| static DECIMAL scaleFactor; |
| DECIMAL decTemp; |
| int scaleAmount, i; |
| HRESULT hRet = S_OK; |
| |
| if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG) |
| return E_INVALIDARG; |
| |
| DEC_LO32(&scaleFactor) = 10; |
| |
| i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight); |
| |
| if (!scaleAmount) |
| return S_OK; /* Same scale */ |
| |
| if (scaleAmount > 0) |
| { |
| decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */ |
| *ppDecRight = pDecOut; |
| } |
| else |
| { |
| decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */ |
| *ppDecLeft = pDecOut; |
| i = scaleAmount = -scaleAmount; |
| } |
| |
| if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE) |
| return DISP_E_OVERFLOW; /* Can't scale up */ |
| |
| /* Multiply up the value to be scaled by the correct amount */ |
| while (SUCCEEDED(hRet) && i--) |
| { |
| /* Note we are multiplying by a value with a scale of 0, so we don't recurse */ |
| hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut); |
| decTemp = *pDecOut; |
| } |
| DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */ |
| return hRet; |
| } |
| |
| /* Add two unsigned 32 bit values with overflow */ |
| static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) |
| { |
| ULARGE_INTEGER ul64; |
| |
| ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh; |
| *pulHigh = ul64.u.HighPart; |
| return ul64.u.LowPart; |
| } |
| |
| /* Subtract two unsigned 32 bit values with underflow */ |
| static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) |
| { |
| int invert = 0; |
| ULARGE_INTEGER ul64; |
| |
| ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight; |
| if (ulLeft < ulRight) |
| invert = 1; |
| |
| if (ul64.QuadPart > (ULONG64)*pulHigh) |
| ul64.QuadPart -= (ULONG64)*pulHigh; |
| else |
| { |
| ul64.QuadPart -= (ULONG64)*pulHigh; |
| invert = 1; |
| } |
| if (invert) |
| ul64.u.HighPart = -ul64.u.HighPart ; |
| |
| *pulHigh = ul64.u.HighPart; |
| return ul64.u.LowPart; |
| } |
| |
| /* Multiply two unsigned 32 bit values with overflow */ |
| static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) |
| { |
| ULARGE_INTEGER ul64; |
| |
| ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh; |
| *pulHigh = ul64.u.HighPart; |
| return ul64.u.LowPart; |
| } |
| |
| /* Compare two decimals that have the same scale */ |
| static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight) |
| { |
| if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) || |
| (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight))) |
| return -1; |
| else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight)) |
| return 0; |
| return 1; |
| } |
| |
| /************************************************************************ |
| * VarDecAdd (OLEAUT32.177) |
| * |
| * Add one DECIMAL to another. |
| * |
| * PARAMS |
| * pDecLeft [I] Source |
| * pDecRight [I] Value to add |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) |
| { |
| HRESULT hRet; |
| DECIMAL scaled; |
| |
| hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled); |
| |
| if (SUCCEEDED(hRet)) |
| { |
| /* Our decimals now have the same scale, we can add them as 96 bit integers */ |
| ULONG overflow = 0; |
| BYTE sign = DECIMAL_POS; |
| |
| /* Correct for the sign of the result */ |
| if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight)) |
| { |
| /* -x + -y : Negative */ |
| sign = DECIMAL_NEG; |
| goto VarDecAdd_AsPositive; |
| } |
| else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight)) |
| { |
| int cmp = VARIANT_DecCmp(pDecLeft, pDecRight); |
| |
| /* -x + y : Negative if x > y */ |
| if (cmp > 0) |
| { |
| sign = DECIMAL_NEG; |
| VarDecAdd_AsNegative: |
| DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow); |
| DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow); |
| DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow); |
| } |
| else |
| { |
| VarDecAdd_AsInvertedNegative: |
| DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow); |
| DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow); |
| DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow); |
| } |
| } |
| else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight)) |
| { |
| int cmp = VARIANT_DecCmp(pDecLeft, pDecRight); |
| |
| /* x + -y : Negative if x <= y */ |
| if (cmp <= 0) |
| { |
| sign = DECIMAL_NEG; |
| goto VarDecAdd_AsInvertedNegative; |
| } |
| goto VarDecAdd_AsNegative; |
| } |
| else |
| { |
| /* x + y : Positive */ |
| VarDecAdd_AsPositive: |
| DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow); |
| DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow); |
| DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow); |
| } |
| |
| if (overflow) |
| return DISP_E_OVERFLOW; /* overflowed */ |
| |
| DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft); |
| DEC_SIGN(pDecOut) = sign; |
| } |
| return hRet; |
| } |
| |
| /* internal representation of the value stored in a DECIMAL. The bytes are |
| stored from LSB at index 0 to MSB at index 11 |
| */ |
| typedef struct DECIMAL_internal |
| { |
| DWORD bitsnum[3]; /* 96 significant bits, unsigned */ |
| unsigned char scale; /* number scaled * 10 ^ -(scale) */ |
| unsigned int sign : 1; /* 0 - positive, 1 - negative */ |
| } VARIANT_DI; |
| |
| /* translate from external DECIMAL format into an internal representation */ |
| static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to) |
| { |
| to->scale = DEC_SCALE(from); |
| to->sign = DEC_SIGN(from) ? 1 : 0; |
| |
| to->bitsnum[0] = DEC_LO32(from); |
| to->bitsnum[1] = DEC_MID32(from); |
| to->bitsnum[2] = DEC_HI32(from); |
| } |
| |
| static void VARIANT_DecFromDI(VARIANT_DI * from, DECIMAL * to) |
| { |
| if (from->sign) { |
| DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale); |
| } else { |
| DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale); |
| } |
| |
| DEC_LO32(to) = from->bitsnum[0]; |
| DEC_MID32(to) = from->bitsnum[1]; |
| DEC_HI32(to) = from->bitsnum[2]; |
| } |
| |
| /* clear an internal representation of a DECIMAL */ |
| static void VARIANT_DI_clear(VARIANT_DI * i) |
| { |
| memset(i, 0, sizeof(VARIANT_DI)); |
| } |
| |
| /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero |
| size is supported. The value in p is replaced by the quotient of the division, and |
| the remainder is returned as a result. This routine is most often used with a divisor |
| of 10 in order to scale up numbers, and in the DECIMAL->string conversion. |
| */ |
| static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor) |
| { |
| if (divisor == 0) { |
| /* division by 0 */ |
| return 0xFF; |
| } else if (divisor == 1) { |
| /* dividend remains unchanged */ |
| return 0; |
| } else { |
| unsigned char remainder = 0; |
| ULONGLONG iTempDividend; |
| signed int i; |
| |
| for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */ |
| for (; i >= 0; i--) { |
| iTempDividend = ((ULONGLONG)remainder << 32) + p[i]; |
| remainder = iTempDividend % divisor; |
| p[i] = iTempDividend / divisor; |
| } |
| |
| return remainder; |
| } |
| } |
| |
| /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */ |
| static int VARIANT_int_iszero(DWORD * p, unsigned int n) |
| { |
| for (; n > 0; n--) if (*p++ != 0) return 0; |
| return 1; |
| } |
| |
| /* multiply two DECIMALS, without changing either one, and place result in third |
| parameter. Result is normalized when scale is > 0. Attempts to remove significant |
| digits when scale > 0 in order to fit an overflowing result. Final overflow |
| flag is returned. |
| */ |
| static int VARIANT_DI_mul(VARIANT_DI * a, VARIANT_DI * b, VARIANT_DI * result) |
| { |
| int r_overflow = 0; |
| DWORD running[6]; |
| signed int mulstart; |
| |
| VARIANT_DI_clear(result); |
| result->sign = (a->sign ^ b->sign) ? 1 : 0; |
| |
| /* Multiply 128-bit operands into a (max) 256-bit result. The scale |
| of the result is formed by adding the scales of the operands. |
| */ |
| result->scale = a->scale + b->scale; |
| memset(running, 0, sizeof(running)); |
| |
| /* count number of leading zero-bytes in operand A */ |
| for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--); |
| if (mulstart < 0) { |
| /* result is 0, because operand A is 0 */ |
| result->scale = 0; |
| result->sign = 0; |
| } else { |
| unsigned char remainder = 0; |
| int iA; |
| |
| /* perform actual multiplication */ |
| for (iA = 0; iA <= mulstart; iA++) { |
| ULONG iOverflowMul; |
| int iB; |
| |
| for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) { |
| ULONG iRV; |
| int iR; |
| |
| iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul); |
| iR = iA + iB; |
| do { |
| running[iR] = VARIANT_Add(running[iR], 0, &iRV); |
| iR++; |
| } while (iRV); |
| } |
| } |
| |
| /* Too bad - native oleaut does not do this, so we should not either */ |
| #if 0 |
| /* While the result is divisible by 10, and the scale > 0, divide by 10. |
| This operation should not lose significant digits, and gives an |
| opportunity to reduce the possibility of overflows in future |
| operations issued by the application. |
| */ |
| while (result->scale > 0) { |
| memcpy(quotient, running, sizeof(quotient)); |
| remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10); |
| if (remainder > 0) break; |
| memcpy(running, quotient, sizeof(quotient)); |
| result->scale--; |
| } |
| #endif |
| /* While the 256-bit result overflows, and the scale > 0, divide by 10. |
| This operation *will* lose significant digits of the result because |
| all the factors of 10 were consumed by the previous operation. |
| */ |
| while (result->scale > 0 && !VARIANT_int_iszero( |
| running + sizeof(result->bitsnum) / sizeof(DWORD), |
| (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) { |
| |
| remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10); |
| if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder); |
| result->scale--; |
| } |
| |
| /* round up the result - native oleaut32 does this */ |
| if (remainder >= 5) { |
| unsigned int i; |
| for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) { |
| ULONGLONG digit = running[i] + 1; |
| remainder = (digit > 0xFFFFFFFF) ? 1 : 0; |
| running[i] = digit & 0xFFFFFFFF; |
| } |
| } |
| |
| /* Signal overflow if scale == 0 and 256-bit result still overflows, |
| and copy result bits into result structure |
| */ |
| r_overflow = !VARIANT_int_iszero( |
| running + sizeof(result->bitsnum)/sizeof(DWORD), |
| (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD)); |
| memcpy(result->bitsnum, running, sizeof(result->bitsnum)); |
| } |
| return r_overflow; |
| } |
| |
| /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is |
| hardcoded (period for decimal separator, dash as negative sign). Returns 0 for |
| success, nonzero if insufficient space in output buffer. |
| */ |
| static int VARIANT_DI_tostringW(VARIANT_DI * a, WCHAR * s, unsigned int n) |
| { |
| int overflow = 0; |
| DWORD quotient[3]; |
| unsigned char remainder; |
| unsigned int i; |
| |
| /* place negative sign */ |
| if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) { |
| if (n > 0) { |
| *s++ = '-'; |
| n--; |
| } |
| else overflow = 1; |
| } |
| |
| /* prepare initial 0 */ |
| if (!overflow) { |
| if (n >= 2) { |
| s[0] = '0'; |
| s[1] = '\0'; |
| } else overflow = 1; |
| } |
| |
| i = 0; |
| memcpy(quotient, a->bitsnum, sizeof(a->bitsnum)); |
| while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) { |
| remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10); |
| if (i + 2 > n) { |
| overflow = 1; |
| } else { |
| s[i++] = '0' + remainder; |
| s[i] = '\0'; |
| } |
| } |
| |
| if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) { |
| |
| /* reverse order of digits */ |
| WCHAR * x = s; WCHAR * y = s + i - 1; |
| while (x < y) { |
| *x ^= *y; |
| *y ^= *x; |
| *x++ ^= *y--; |
| } |
| |
| /* check for decimal point. "i" now has string length */ |
| if (i <= a->scale) { |
| unsigned int numzeroes = a->scale + 1 - i; |
| if (i + 1 + numzeroes >= n) { |
| overflow = 1; |
| } else { |
| memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR)); |
| i += numzeroes; |
| while (numzeroes > 0) { |
| s[--numzeroes] = '0'; |
| } |
| } |
| } |
| |
| /* place decimal point */ |
| if (a->scale > 0) { |
| unsigned int periodpos = i - a->scale; |
| if (i + 2 >= n) { |
| overflow = 1; |
| } else { |
| memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR)); |
| s[periodpos] = '.'; i++; |
| |
| /* remove extra zeros at the end, if any */ |
| while (s[i - 1] == '0') s[--i] = '\0'; |
| if (s[i - 1] == '.') s[--i] = '\0'; |
| } |
| } |
| } |
| |
| return overflow; |
| } |
| |
| /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */ |
| static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift) |
| { |
| DWORD shifted; |
| unsigned int i; |
| |
| /* shift whole DWORDs to the left */ |
| while (shift >= 32) |
| { |
| memmove(p + 1, p, (n - 1) * sizeof(DWORD)); |
| *p = 0; shift -= 32; |
| } |
| |
| /* shift remainder (1..31 bits) */ |
| shifted = 0; |
| if (shift > 0) for (i = 0; i < n; i++) |
| { |
| DWORD b; |
| b = p[i] >> (32 - shift); |
| p[i] = (p[i] << shift) | shifted; |
| shifted = b; |
| } |
| } |
| |
| /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0. |
| Value at v is incremented by the value at p. Any size is supported, provided |
| that v is not shorter than p. Any unapplied carry is returned as a result. |
| */ |
| static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, DWORD * p, |
| unsigned int np) |
| { |
| unsigned char carry = 0; |
| |
| if (nv >= np) { |
| ULONGLONG sum; |
| unsigned int i; |
| |
| for (i = 0; i < np; i++) { |
| sum = (ULONGLONG)v[i] |
| + (ULONGLONG)p[i] |
| + (ULONGLONG)carry; |
| v[i] = sum & 0xffffffff; |
| carry = sum >> 32; |
| } |
| for (; i < nv && carry; i++) { |
| sum = (ULONGLONG)v[i] |
| + (ULONGLONG)carry; |
| v[i] = sum & 0xffffffff; |
| carry = sum >> 32; |
| } |
| } |
| return carry; |
| } |
| |
| /* perform integral division with operand p as dividend. Parameter n indicates |
| number of available DWORDs in divisor p, but available space in p must be |
| actually at least 2 * n DWORDs, because the remainder of the integral |
| division is built in the next n DWORDs past the start of the quotient. This |
| routine replaces the dividend in p with the quotient, and appends n |
| additional DWORDs for the remainder. |
| |
| Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on |
| C/C++ :-) where the "longhand binary division" algorithm was exposed for the |
| source code to the VLI (Very Large Integer) division operator. This algorithm |
| was then heavily modified by me (Alex Villacis Lasso) in order to handle |
| variably-scaled integers such as the MS DECIMAL representation. |
| */ |
| static void VARIANT_int_div(DWORD * p, unsigned int n, DWORD * divisor, |
| unsigned int dn) |
| { |
| unsigned int i; |
| DWORD tempsub[8]; |
| DWORD * negdivisor = tempsub + n; |
| |
| /* build 2s-complement of divisor */ |
| for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF; |
| p[n] = 1; |
| VARIANT_int_add(negdivisor, n, p + n, 1); |
| memset(p + n, 0, n * sizeof(DWORD)); |
| |
| /* skip all leading zero DWORDs in quotient */ |
| for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32); |
| /* i is now number of DWORDs left to process */ |
| for (i <<= 5; i < (n << 5); i++) { |
| VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */ |
| |
| /* trial subtraction */ |
| memcpy(tempsub, p + n, n * sizeof(DWORD)); |
| VARIANT_int_add(tempsub, n, negdivisor, n); |
| |
| /* check whether result of subtraction was negative */ |
| if ((tempsub[n - 1] & 0x80000000) == 0) { |
| memcpy(p + n, tempsub, n * sizeof(DWORD)); |
| p[0] |= 1; |
| } |
| } |
| } |
| |
| /* perform integral multiplication by a byte operand. Used for scaling by 10 */ |
| static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m) |
| { |
| unsigned int i; |
| ULONG iOverflowMul; |
| |
| for (iOverflowMul = 0, i = 0; i < n; i++) |
| p[i] = VARIANT_Mul(p[i], m, &iOverflowMul); |
| return (unsigned char)iOverflowMul; |
| } |
| |
| /* increment value in A by the value indicated in B, with scale adjusting. |
| Modifies parameters by adjusting scales. Returns 0 if addition was |
| successful, nonzero if a parameter underflowed before it could be |
| successfully used in the addition. |
| */ |
| static int VARIANT_int_addlossy( |
| DWORD * a, int * ascale, unsigned int an, |
| DWORD * b, int * bscale, unsigned int bn) |
| { |
| int underflow = 0; |
| |
| if (VARIANT_int_iszero(a, an)) { |
| /* if A is zero, copy B into A, after removing digits */ |
| while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) { |
| VARIANT_int_divbychar(b, bn, 10); |
| (*bscale)--; |
| } |
| memcpy(a, b, an * sizeof(DWORD)); |
| *ascale = *bscale; |
| } else if (!VARIANT_int_iszero(b, bn)) { |
| unsigned int tn = an + 1; |
| DWORD t[5]; |
| |
| if (bn + 1 > tn) tn = bn + 1; |
| if (*ascale != *bscale) { |
| /* first (optimistic) try - try to scale down the one with the bigger |
| scale, while this number is divisible by 10 */ |
| DWORD * digitchosen; |
| unsigned int nchosen; |
| int * scalechosen; |
| int targetscale; |
| |
| if (*ascale < *bscale) { |
| targetscale = *ascale; |
| scalechosen = bscale; |
| digitchosen = b; |
| nchosen = bn; |
| } else { |
| targetscale = *bscale; |
| scalechosen = ascale; |
| digitchosen = a; |
| nchosen = an; |
| } |
| memset(t, 0, tn * sizeof(DWORD)); |
| memcpy(t, digitchosen, nchosen * sizeof(DWORD)); |
| |
| /* divide by 10 until target scale is reached */ |
| while (*scalechosen > targetscale) { |
| unsigned char remainder = VARIANT_int_divbychar(t, tn, 10); |
| if (!remainder) { |
| (*scalechosen)--; |
| memcpy(digitchosen, t, nchosen * sizeof(DWORD)); |
| } else break; |
| } |
| } |
| |
| if (*ascale != *bscale) { |
| DWORD * digitchosen; |
| unsigned int nchosen; |
| int * scalechosen; |
| int targetscale; |
| |
| /* try to scale up the one with the smaller scale */ |
| if (*ascale > *bscale) { |
| targetscale = *ascale; |
| scalechosen = bscale; |
| digitchosen = b; |
| nchosen = bn; |
| } else { |
| targetscale = *bscale; |
| scalechosen = ascale; |
| digitchosen = a; |
| nchosen = an; |
| } |
| memset(t, 0, tn * sizeof(DWORD)); |
| memcpy(t, digitchosen, nchosen * sizeof(DWORD)); |
| |
| /* multiply by 10 until target scale is reached, or |
| significant bytes overflow the number |
| */ |
| while (*scalechosen < targetscale && t[nchosen] == 0) { |
| VARIANT_int_mulbychar(t, tn, 10); |
| if (t[nchosen] == 0) { |
| /* still does not overflow */ |
| (*scalechosen)++; |
| memcpy(digitchosen, t, nchosen * sizeof(DWORD)); |
| } |
| } |
| } |
| |
| if (*ascale != *bscale) { |
| /* still different? try to scale down the one with the bigger scale |
| (this *will* lose significant digits) */ |
| DWORD * digitchosen; |
| unsigned int nchosen; |
| int * scalechosen; |
| int targetscale; |
| |
| if (*ascale < *bscale) { |
| targetscale = *ascale; |
| scalechosen = bscale; |
| digitchosen = b; |
| nchosen = bn; |
| } else { |
| targetscale = *bscale; |
| scalechosen = ascale; |
| digitchosen = a; |
| nchosen = an; |
| } |
| memset(t, 0, tn * sizeof(DWORD)); |
| memcpy(t, digitchosen, nchosen * sizeof(DWORD)); |
| |
| /* divide by 10 until target scale is reached */ |
| while (*scalechosen > targetscale) { |
| VARIANT_int_divbychar(t, tn, 10); |
| (*scalechosen)--; |
| memcpy(digitchosen, t, nchosen * sizeof(DWORD)); |
| } |
| } |
| |
| /* check whether any of the operands still has significant digits |
| (underflow case 1) |
| */ |
| if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) { |
| underflow = 1; |
| } else { |
| /* at this step, both numbers have the same scale and can be added |
| as integers. However, the result might not fit in A, so further |
| scaling down might be necessary. |
| */ |
| while (!underflow) { |
| memset(t, 0, tn * sizeof(DWORD)); |
| memcpy(t, a, an * sizeof(DWORD)); |
| |
| VARIANT_int_add(t, tn, b, bn); |
| if (VARIANT_int_iszero(t + an, tn - an)) { |
| /* addition was successful */ |
| memcpy(a, t, an * sizeof(DWORD)); |
| break; |
| } else { |
| /* addition overflowed - remove significant digits |
| from both operands and try again */ |
| VARIANT_int_divbychar(a, an, 10); (*ascale)--; |
| VARIANT_int_divbychar(b, bn, 10); (*bscale)--; |
| /* check whether any operand keeps significant digits after |
| scaledown (underflow case 2) |
| */ |
| underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)); |
| } |
| } |
| } |
| } |
| return underflow; |
| } |
| |
| /* perform complete DECIMAL division in the internal representation. Returns |
| 0 if the division was completed (even if quotient is set to 0), or nonzero |
| in case of quotient overflow. |
| */ |
| static HRESULT VARIANT_DI_div(VARIANT_DI * dividend, VARIANT_DI * divisor, VARIANT_DI * quotient) |
| { |
| HRESULT r_overflow = S_OK; |
| |
| if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) { |
| /* division by 0 */ |
| r_overflow = DISP_E_DIVBYZERO; |
| } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) { |
| VARIANT_DI_clear(quotient); |
| } else { |
| int quotientscale, remainderscale, tempquotientscale; |
| DWORD remainderplusquotient[8]; |
| int underflow; |
| |
| quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale; |
| tempquotientscale = quotientscale; |
| VARIANT_DI_clear(quotient); |
| quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0; |
| |
| /* The following strategy is used for division |
| 1) if there was a nonzero remainder from previous iteration, use it as |
| dividend for this iteration, else (for first iteration) use intended |
| dividend |
| 2) perform integer division in temporary buffer, develop quotient in |
| low-order part, remainder in high-order part |
| 3) add quotient from step 2 to final result, with possible loss of |
| significant digits |
| 4) multiply integer part of remainder by 10, while incrementing the |
| scale of the remainder. This operation preserves the intended value |
| of the remainder. |
| 5) loop to step 1 until one of the following is true: |
| a) remainder is zero (exact division achieved) |
| b) addition in step 3 fails to modify bits in quotient (remainder underflow) |
| */ |
| memset(remainderplusquotient, 0, sizeof(remainderplusquotient)); |
| memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum)); |
| do { |
| VARIANT_int_div( |
| remainderplusquotient, 4, |
| divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD)); |
| underflow = VARIANT_int_addlossy( |
| quotient->bitsnum, "ientscale, sizeof(quotient->bitsnum) / sizeof(DWORD), |
| remainderplusquotient, &tempquotientscale, 4); |
| VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10); |
| memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD)); |
| tempquotientscale = ++remainderscale; |
| } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4)); |
| |
| /* quotient scale might now be negative (extremely big number). If, so, try |
| to multiply quotient by 10 (without overflowing), while adjusting the scale, |
| until scale is 0. If this cannot be done, it is a real overflow. |
| */ |
| while (!r_overflow && quotientscale < 0) { |
| memset(remainderplusquotient, 0, sizeof(remainderplusquotient)); |
| memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum)); |
| VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10); |
| if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD), |
| (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) { |
| quotientscale++; |
| memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum)); |
| } else r_overflow = DISP_E_OVERFLOW; |
| } |
| if (!r_overflow) { |
| if (quotientscale <= 255) quotient->scale = quotientscale; |
| else VARIANT_DI_clear(quotient); |
| } |
| } |
| return r_overflow; |
| } |
| |
| /************************************************************************ |
| * VarDecDiv (OLEAUT32.178) |
| * |
| * Divide one DECIMAL by another. |
| * |
| * PARAMS |
| * pDecLeft [I] Source |
| * pDecRight [I] Value to divide by |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) |
| { |
| HRESULT hRet = S_OK; |
| VARIANT_DI di_left, di_right, di_result; |
| HRESULT divresult; |
| |
| if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG; |
| |
| VARIANT_DIFromDec(pDecLeft, &di_left); |
| VARIANT_DIFromDec(pDecRight, &di_right); |
| divresult = VARIANT_DI_div(&di_left, &di_right, &di_result); |
| if (divresult) |
| { |
| /* division actually overflowed */ |
| hRet = divresult; |
| } |
| else |
| { |
| hRet = S_OK; |
| |
| if (di_result.scale > DEC_MAX_SCALE) |
| { |
| unsigned char remainder = 0; |
| |
| /* division underflowed. In order to comply with the MSDN |
| specifications for DECIMAL ranges, some significant digits |
| must be removed |
| */ |
| WARN("result scale is %u, scaling (with loss of significant digits)...\n", |
| di_result.scale); |
| while (di_result.scale > DEC_MAX_SCALE && |
| !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD))) |
| { |
| remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10); |
| di_result.scale--; |
| } |
| if (di_result.scale > DEC_MAX_SCALE) |
| { |
| WARN("result underflowed, setting to 0\n"); |
| di_result.scale = 0; |
| di_result.sign = 0; |
| } |
| else if (remainder >= 5) /* round up result - native oleaut32 does this */ |
| { |
| unsigned int i; |
| for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) { |
| ULONGLONG digit = di_result.bitsnum[i] + 1; |
| remainder = (digit > 0xFFFFFFFF) ? 1 : 0; |
| di_result.bitsnum[i] = digit & 0xFFFFFFFF; |
| } |
| } |
| } |
| VARIANT_DecFromDI(&di_result, pDecOut); |
| } |
| return hRet; |
| } |
| |
| /************************************************************************ |
| * VarDecMul (OLEAUT32.179) |
| * |
| * Multiply one DECIMAL by another. |
| * |
| * PARAMS |
| * pDecLeft [I] Source |
| * pDecRight [I] Value to multiply by |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) |
| { |
| HRESULT hRet = S_OK; |
| VARIANT_DI di_left, di_right, di_result; |
| int mulresult; |
| |
| VARIANT_DIFromDec(pDecLeft, &di_left); |
| VARIANT_DIFromDec(pDecRight, &di_right); |
| mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result); |
| if (mulresult) |
| { |
| /* multiplication actually overflowed */ |
| hRet = DISP_E_OVERFLOW; |
| } |
| else |
| { |
| if (di_result.scale > DEC_MAX_SCALE) |
| { |
| /* multiplication underflowed. In order to comply with the MSDN |
| specifications for DECIMAL ranges, some significant digits |
| must be removed |
| */ |
| WARN("result scale is %u, scaling (with loss of significant digits)...\n", |
| di_result.scale); |
| while (di_result.scale > DEC_MAX_SCALE && |
| !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD))) |
| { |
| VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10); |
| di_result.scale--; |
| } |
| if (di_result.scale > DEC_MAX_SCALE) |
| { |
| WARN("result underflowed, setting to 0\n"); |
| di_result.scale = 0; |
| di_result.sign = 0; |
| } |
| } |
| VARIANT_DecFromDI(&di_result, pDecOut); |
| } |
| return hRet; |
| } |
| |
| /************************************************************************ |
| * VarDecSub (OLEAUT32.181) |
| * |
| * Subtract one DECIMAL from another. |
| * |
| * PARAMS |
| * pDecLeft [I] Source |
| * pDecRight [I] DECIMAL to subtract from pDecLeft |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) |
| { |
| DECIMAL decRight; |
| |
| /* Implement as addition of the negative */ |
| VarDecNeg(pDecRight, &decRight); |
| return VarDecAdd(pDecLeft, &decRight, pDecOut); |
| } |
| |
| /************************************************************************ |
| * VarDecAbs (OLEAUT32.182) |
| * |
| * Convert a DECIMAL into its absolute value. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. This function does not fail. |
| */ |
| HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut) |
| { |
| *pDecOut = *pDecIn; |
| DEC_SIGN(pDecOut) &= ~DECIMAL_NEG; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarDecFix (OLEAUT32.187) |
| * |
| * Return the integer portion of a DECIMAL. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * - The difference between this function and VarDecInt() is that VarDecInt() rounds |
| * negative numbers away from 0, while this function rounds them towards zero. |
| */ |
| HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut) |
| { |
| if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) |
| return E_INVALIDARG; |
| |
| if (!DEC_SCALE(pDecIn)) |
| { |
| *pDecOut = *pDecIn; /* Already an integer */ |
| return S_OK; |
| } |
| |
| FIXME("semi-stub!\n"); |
| return DISP_E_OVERFLOW; |
| } |
| |
| /************************************************************************ |
| * VarDecInt (OLEAUT32.188) |
| * |
| * Return the integer portion of a DECIMAL. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| * |
| * NOTES |
| * - The difference between this function and VarDecFix() is that VarDecFix() rounds |
| * negative numbers towards 0, while this function rounds them away from zero. |
| */ |
| HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut) |
| { |
| if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) |
| return E_INVALIDARG; |
| |
| if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn)) |
| return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */ |
| |
| FIXME("semi-stub!\n"); |
| return DISP_E_OVERFLOW; |
| } |
| |
| /************************************************************************ |
| * VarDecNeg (OLEAUT32.189) |
| * |
| * Change the sign of a DECIMAL. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. This function does not fail. |
| */ |
| HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut) |
| { |
| *pDecOut = *pDecIn; |
| DEC_SIGN(pDecOut) ^= DECIMAL_NEG; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarDecRound (OLEAUT32.203) |
| * |
| * Change the precision of a DECIMAL. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * cDecimals [I] New number of decimals to keep |
| * pDecOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. pDecOut contains the rounded value. |
| * Failure: E_INVALIDARG if any argument is invalid. |
| */ |
| HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut) |
| { |
| if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE) |
| return E_INVALIDARG; |
| |
| if (cDecimals >= DEC_SCALE(pDecIn)) |
| { |
| *pDecOut = *pDecIn; /* More precision than we have */ |
| return S_OK; |
| } |
| |
| FIXME("semi-stub!\n"); |
| |
| return DISP_E_OVERFLOW; |
| } |
| |
| /************************************************************************ |
| * VarDecCmp (OLEAUT32.204) |
| * |
| * Compare two DECIMAL values. |
| * |
| * PARAMS |
| * pDecLeft [I] Source |
| * pDecRight [I] Value to compare |
| * |
| * RETURNS |
| * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft |
| * is less than, equal to or greater than pDecRight respectively. |
| * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison |
| */ |
| HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight) |
| { |
| HRESULT hRet; |
| DECIMAL result; |
| |
| /* Subtract right from left, and compare the result to 0 */ |
| hRet = VarDecSub(pDecLeft, pDecRight, &result); |
| |
| if (SUCCEEDED(hRet)) |
| { |
| int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result); |
| |
| if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero) |
| hRet = (HRESULT)VARCMP_LT; |
| else if (non_zero) |
| hRet = (HRESULT)VARCMP_GT; |
| else |
| hRet = (HRESULT)VARCMP_EQ; |
| } |
| return hRet; |
| } |
| |
| /************************************************************************ |
| * VarDecCmpR8 (OLEAUT32.298) |
| * |
| * Compare a DECIMAL to a double |
| * |
| * PARAMS |
| * pDecLeft [I] DECIMAL Source |
| * dblRight [I] double to compare to pDecLeft |
| * |
| * RETURNS |
| * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight |
| * is less than, equal to or greater than pDecLeft respectively. |
| * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison |
| */ |
| HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight) |
| { |
| HRESULT hRet; |
| DECIMAL decRight; |
| |
| hRet = VarDecFromR8(dblRight, &decRight); |
| |
| if (SUCCEEDED(hRet)) |
| hRet = VarDecCmp(pDecLeft, &decRight); |
| |
| return hRet; |
| } |
| |
| /* BOOL |
| */ |
| |
| /************************************************************************ |
| * VarBoolFromUI1 (OLEAUT32.118) |
| * |
| * Convert a VT_UI1 to a VT_BOOL. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut) |
| { |
| *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarBoolFromI2 (OLEAUT32.119) |
| * |
| * Convert a VT_I2 to a VT_BOOL. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut) |
| { |
| *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarBoolFromI4 (OLEAUT32.120) |
| * |
| * Convert a VT_I4 to a VT_BOOL. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut) |
| { |
| *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarBoolFromR4 (OLEAUT32.121) |
| * |
| * Convert a VT_R4 to a VT_BOOL. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut) |
| { |
| *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarBoolFromR8 (OLEAUT32.122) |
| * |
| * Convert a VT_R8 to a VT_BOOL. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut) |
| { |
| *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarBoolFromDate (OLEAUT32.123) |
| * |
| * Convert a VT_DATE to a VT_BOOL. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut) |
| { |
| *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarBoolFromCy (OLEAUT32.124) |
| * |
| * Convert a VT_CY to a VT_BOOL. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut) |
| { |
| *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE; |
| return S_OK; |
| } |
| |
| static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest) |
| { |
| HRSRC hrsrc; |
| |
| hrsrc = FindResourceExW( OLEAUT32_hModule, (LPWSTR)RT_STRING, |
| MAKEINTRESOURCEW((dwId >> 4) + 1), langId ); |
| if (hrsrc) |
| { |
| HGLOBAL hmem = LoadResource( OLEAUT32_hModule, hrsrc ); |
| |
| if (hmem) |
| { |
| const WCHAR *p; |
| unsigned int i; |
| |
| p = LockResource( hmem ); |
| for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1; |
| |
| memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) ); |
| lpszDest[*p] = '\0'; |
| TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId); |
| return TRUE; |
| } |
| } |
| return FALSE; |
| } |
| |
| /************************************************************************ |
| * VarBoolFromStr (OLEAUT32.125) |
| * |
| * Convert a VT_BSTR to a VT_BOOL. |
| * |
| * PARAMS |
| * strIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pBoolOut is invalid. |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| * |
| * NOTES |
| * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally, |
| * it may contain (in any case mapping) the text "true" or "false". |
| * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the |
| * localised text of "True" or "False" in the language specified by lcid. |
| * - If none of these matches occur, the string is treated as a numeric string |
| * and the boolean pBoolOut will be set according to whether the number is zero |
| * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion. |
| * - If the text is not numeric and does not match any of the above, then |
| * DISP_E_TYPEMISMATCH is returned. |
| */ |
| HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut) |
| { |
| /* Any VB/VBA programmers out there should recognise these strings... */ |
| static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' }; |
| static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' }; |
| WCHAR szBuff[64]; |
| LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); |
| HRESULT hRes = S_OK; |
| |
| if (!strIn || !pBoolOut) |
| return DISP_E_TYPEMISMATCH; |
| |
| /* Check if we should be comparing against localised text */ |
| if (dwFlags & VAR_LOCALBOOL) |
| { |
| /* Convert our LCID into a usable value */ |
| lcid = ConvertDefaultLocale(lcid); |
| |
| langId = LANGIDFROMLCID(lcid); |
| |
| if (PRIMARYLANGID(langId) == LANG_NEUTRAL) |
| langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); |
| |
| /* Note: Native oleaut32 always copies strIn and maps halfwidth characters. |
| * I don't think this is needed unless any of the localised text strings |
| * contain characters that can be so mapped. In the event that this is |
| * true for a given language (possibly some Asian languages), then strIn |
| * should be mapped here _only_ if langId is an Id for which this can occur. |
| */ |
| } |
| |
| /* Note that if we are not comparing against localised strings, langId |
| * will have its default value of LANG_ENGLISH. This allows us to mimic |
| * the native behaviour of always checking against English strings even |
| * after we've checked for localised ones. |
| */ |
| VarBoolFromStr_CheckLocalised: |
| if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff)) |
| { |
| /* Compare against localised strings, ignoring case */ |
| if (!strcmpiW(strIn, szBuff)) |
| { |
| *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */ |
| return hRes; |
| } |
| VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff); |
| if (!strcmpiW(strIn, szBuff)) |
| { |
| *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */ |
| return hRes; |
| } |
| } |
| |
| if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) |
| { |
| /* We have checked the localised text, now check English */ |
| langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); |
| goto VarBoolFromStr_CheckLocalised; |
| } |
| |
| /* All checks against localised text have failed, try #TRUE#/#FALSE# */ |
| if (!strcmpW(strIn, szFalse)) |
| *pBoolOut = VARIANT_FALSE; |
| else if (!strcmpW(strIn, szTrue)) |
| *pBoolOut = VARIANT_TRUE; |
| else |
| { |
| double d; |
| |
| /* If this string is a number, convert it as one */ |
| hRes = VarR8FromStr(strIn, lcid, dwFlags, &d); |
| if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE; |
| } |
| return hRes; |
| } |
| |
| /************************************************************************ |
| * VarBoolFromDisp (OLEAUT32.126) |
| * |
| * Convert a VT_DISPATCH to a VT_BOOL. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0); |
| } |
| |
| /************************************************************************ |
| * VarBoolFromI1 (OLEAUT32.233) |
| * |
| * Convert a VT_I1 to a VT_BOOL. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut) |
| { |
| *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarBoolFromUI2 (OLEAUT32.234) |
| * |
| * Convert a VT_UI2 to a VT_BOOL. |
| * |
| * PARAMS |
| * usIn [I] Source |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut) |
| { |
| *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarBoolFromUI4 (OLEAUT32.235) |
| * |
| * Convert a VT_UI4 to a VT_BOOL. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut) |
| { |
| *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarBoolFromDec (OLEAUT32.236) |
| * |
| * Convert a VT_DECIMAL to a VT_BOOL. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pDecIn is invalid. |
| */ |
| HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut) |
| { |
| if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)) |
| return E_INVALIDARG; |
| |
| if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn)) |
| *pBoolOut = VARIANT_TRUE; |
| else |
| *pBoolOut = VARIANT_FALSE; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarBoolFromI8 (OLEAUT32.370) |
| * |
| * Convert a VT_I8 to a VT_BOOL. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut) |
| { |
| *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE; |
| return S_OK; |
| } |
| |
| /************************************************************************ |
| * VarBoolFromUI8 (OLEAUT32.371) |
| * |
| * Convert a VT_UI8 to a VT_BOOL. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pBoolOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut) |
| { |
| *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE; |
| return S_OK; |
| } |
| |
| /* BSTR |
| */ |
| |
| /* Write a number from a UI8 and sign */ |
| static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut) |
| { |
| do |
| { |
| WCHAR ulNextDigit = ulVal % 10; |
| |
| *szOut-- = '0' + ulNextDigit; |
| ulVal = (ulVal - ulNextDigit) / 10; |
| } while (ulVal); |
| |
| szOut++; |
| return szOut; |
| } |
| |
| /* Create a (possibly localised) BSTR from a UI8 and sign */ |
| static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut) |
| { |
| WCHAR szConverted[256]; |
| |
| if (dwFlags & VAR_NEGATIVE) |
| *--szOut = '-'; |
| |
| if (dwFlags & LOCALE_USE_NLS) |
| { |
| /* Format the number for the locale */ |
| szConverted[0] = '\0'; |
| GetNumberFormatW(lcid, |
| dwFlags & LOCALE_NOUSEROVERRIDE, |
| szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR)); |
| szOut = szConverted; |
| } |
| return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR)); |
| } |
| |
| /* Create a (possibly localised) BSTR from a UI8 and sign */ |
| static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut) |
| { |
| WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1; |
| |
| if (!pbstrOut) |
| return E_INVALIDARG; |
| |
| /* Create the basic number string */ |
| *szOut-- = '\0'; |
| szOut = VARIANT_WriteNumber(ulVal, szOut); |
| |
| *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut); |
| TRACE("returning %s\n", debugstr_w(*pbstrOut)); |
| return *pbstrOut ? S_OK : E_OUTOFMEMORY; |
| } |
| |
| /****************************************************************************** |
| * VarBstrFromUI1 (OLEAUT32.108) |
| * |
| * Convert a VT_UI1 to a VT_BSTR. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut); |
| } |
| |
| /****************************************************************************** |
| * VarBstrFromI2 (OLEAUT32.109) |
| * |
| * Convert a VT_I2 to a VT_BSTR. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| ULONG64 ul64 = sIn; |
| |
| if (sIn < 0) |
| { |
| ul64 = -sIn; |
| dwFlags |= VAR_NEGATIVE; |
| } |
| return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); |
| } |
| |
| /****************************************************************************** |
| * VarBstrFromI4 (OLEAUT32.110) |
| * |
| * Convert a VT_I4 to a VT_BSTR. |
| * |
| * PARAMS |
| * lIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| ULONG64 ul64 = lIn; |
| |
| if (lIn < 0) |
| { |
| ul64 = (ULONG)-lIn; |
| dwFlags |= VAR_NEGATIVE; |
| } |
| return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); |
| } |
| |
| static BSTR VARIANT_BstrReplaceDecimal(WCHAR * buff, LCID lcid, ULONG dwFlags) |
| { |
| BSTR bstrOut; |
| WCHAR lpDecimalSep[16]; |
| |
| /* Native oleaut32 uses the locale-specific decimal separator even in the |
| absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin |
| American locales will see "one thousand and one tenth" as "1000,1" |
| instead of "1000.1" (notice the comma). The following code checks for |
| the need to replace the decimal separator, and if so, will prepare an |
| appropriate NUMBERFMTW structure to do the job via GetNumberFormatW(). |
| */ |
| GetLocaleInfoW(lcid, LOCALE_SDECIMAL, lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR)); |
| if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0') |
| { |
| /* locale is compatible with English - return original string */ |
| bstrOut = SysAllocString(buff); |
| } |
| else |
| { |
| WCHAR *p; |
| WCHAR numbuff[256]; |
| WCHAR empty[1] = {'\0'}; |
| NUMBERFMTW minFormat; |
| |
| minFormat.NumDigits = 0; |
| minFormat.LeadingZero = 0; |
| minFormat.Grouping = 0; |
| minFormat.lpDecimalSep = lpDecimalSep; |
| minFormat.lpThousandSep = empty; |
| minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */ |
| |
| /* count number of decimal digits in string */ |
| p = strchrW( buff, '.' ); |
| if (p) minFormat.NumDigits = strlenW(p + 1); |
| |
| numbuff[0] = '\0'; |
| if (!GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, |
| buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR))) |
| { |
| WARN("GetNumberFormatW() failed, returning raw number string instead\n"); |
| bstrOut = SysAllocString(buff); |
| } |
| else |
| { |
| TRACE("created minimal NLS string %s\n", debugstr_w(numbuff)); |
| bstrOut = SysAllocString(numbuff); |
| } |
| } |
| return bstrOut; |
| } |
| |
| static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags, |
| BSTR* pbstrOut, LPCWSTR lpszFormat) |
| { |
| WCHAR buff[256]; |
| |
| if (!pbstrOut) |
| return E_INVALIDARG; |
| |
| sprintfW( buff, lpszFormat, dblIn ); |
| |
| /* Negative zeroes are disallowed (some applications depend on this). |
| If buff starts with a minus, and then nothing follows but zeroes |
| and/or a period, it is a negative zero and is replaced with a |
| canonical zero. This duplicates native oleaut32 behavior. |
| */ |
| if (buff[0] == '-') |
| { |
| const WCHAR szAccept[] = {'0', '.', '\0'}; |
| if (strlenW(buff + 1) == strspnW(buff + 1, szAccept)) |
| { buff[0] = '0'; buff[1] = '\0'; } |
| } |
| |
| TRACE("created string %s\n", debugstr_w(buff)); |
| if (dwFlags & LOCALE_USE_NLS) |
| { |
| WCHAR numbuff[256]; |
| |
| /* Format the number for the locale */ |
| numbuff[0] = '\0'; |
| GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, |
| buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR)); |
| TRACE("created NLS string %s\n", debugstr_w(numbuff)); |
| *pbstrOut = SysAllocString(numbuff); |
| } |
| else |
| { |
| *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags); |
| } |
| return *pbstrOut ? S_OK : E_OUTOFMEMORY; |
| } |
| |
| /****************************************************************************** |
| * VarBstrFromR4 (OLEAUT32.111) |
| * |
| * Convert a VT_R4 to a VT_BSTR. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW); |
| } |
| |
| /****************************************************************************** |
| * VarBstrFromR8 (OLEAUT32.112) |
| * |
| * Convert a VT_R8 to a VT_BSTR. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW); |
| } |
| |
| /****************************************************************************** |
| * VarBstrFromCy [OLEAUT32.113] |
| * |
| * Convert a VT_CY to a VT_BSTR. |
| * |
| * PARAMS |
| * cyIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) |
| { |
| WCHAR buff[256]; |
| double dblVal; |
| |
| if (!pbstrOut) |
| return E_INVALIDARG; |
| |
| VarR8FromCy(cyIn, &dblVal); |
| sprintfW(buff, szDoubleFormatW, dblVal); |
| |
| if (dwFlags & LOCALE_USE_NLS) |
| { |
| WCHAR cybuff[256]; |
| |
| /* Format the currency for the locale */ |
| cybuff[0] = '\0'; |
| GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, |
| buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR)); |
| *pbstrOut = SysAllocString(cybuff); |
| } |
| else |
| *pbstrOut = SysAllocString(buff); |
| |
| return *pbstrOut ? S_OK : E_OUTOFMEMORY; |
| } |
| |
| /****************************************************************************** |
| * VarBstrFromDate [OLEAUT32.114] |
| * |
| * Convert a VT_DATE to a VT_BSTR. |
| * |
| * PARAMS |
| * dateIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| SYSTEMTIME st; |
| DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE; |
| WCHAR date[128], *time; |
| |
| TRACE("(%g,0x%08lx,0x%08lx,%p)\n", dateIn, lcid, dwFlags, pbstrOut); |
| |
| if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st)) |
| return E_INVALIDARG; |
| |
| *pbstrOut = NULL; |
| |
| if (dwFlags & VAR_CALENDAR_THAI) |
| st.wYear += 553; /* Use the Thai buddhist calendar year */ |
| else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN)) |
| FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n"); |
| |
| if (dwFlags & LOCALE_USE_NLS) |
| dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY); |
| else |
| { |
| double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn); |
| double partial = dateIn - whole; |
| |
| if (whole == 0.0) |
| dwFlags |= VAR_TIMEVALUEONLY; |
| else if (partial < 1e-12) |
| dwFlags |= VAR_DATEVALUEONLY; |
| } |
| |
| if (dwFlags & VAR_TIMEVALUEONLY) |
| date[0] = '\0'; |
| else |
| if (!GetDateFormatW(lcid, dwFormatFlags|DATE_SHORTDATE, &st, NULL, date, |
| sizeof(date)/sizeof(WCHAR))) |
| return E_INVALIDARG; |
| |
| if (!(dwFlags & VAR_DATEVALUEONLY)) |
| { |
| time = date + strlenW(date); |
| if (time != date) |
| *time++ = ' '; |
| if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time, |
| sizeof(date)/sizeof(WCHAR)-(time-date))) |
| return E_INVALIDARG; |
| } |
| |
| *pbstrOut = SysAllocString(date); |
| if (*pbstrOut) |
| TRACE("returning %s\n", debugstr_w(*pbstrOut)); |
| return *pbstrOut ? S_OK : E_OUTOFMEMORY; |
| } |
| |
| /****************************************************************************** |
| * VarBstrFromBool (OLEAUT32.116) |
| * |
| * Convert a VT_BOOL to a VT_BSTR. |
| * |
| * PARAMS |
| * boolIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| * |
| * NOTES |
| * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the |
| * localised text of "True" or "False". To convert a bool into a |
| * numeric string of "0" or "-1", use VariantChangeTypeTypeEx(). |
| */ |
| HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| WCHAR szBuff[64]; |
| DWORD dwResId = IDS_TRUE; |
| LANGID langId; |
| |
| TRACE("%d,0x%08lx,0x%08lx,%p\n", boolIn, lcid, dwFlags, pbstrOut); |
| |
| if (!pbstrOut) |
| return E_INVALIDARG; |
| |
| /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used |
| * for variant formatting */ |
| switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO)) |
| { |
| case VAR_BOOLONOFF: |
| dwResId = IDS_ON; |
| break; |
| case VAR_BOOLYESNO: |
| dwResId = IDS_YES; |
| break; |
| case VAR_LOCALBOOL: |
| break; |
| default: |
| lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT); |
| } |
| |
| lcid = ConvertDefaultLocale(lcid); |
| langId = LANGIDFROMLCID(lcid); |
| if (PRIMARYLANGID(langId) == LANG_NEUTRAL) |
| langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); |
| |
| if (boolIn == VARIANT_FALSE) |
| dwResId++; /* Use negative form */ |
| |
| VarBstrFromBool_GetLocalised: |
| if (VARIANT_GetLocalisedText(langId, dwResId, szBuff)) |
| { |
| *pbstrOut = SysAllocString(szBuff); |
| return *pbstrOut ? S_OK : E_OUTOFMEMORY; |
| } |
| |
| if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) |
| { |
| langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); |
| goto VarBstrFromBool_GetLocalised; |
| } |
| |
| /* Should never get here */ |
| WARN("Failed to load bool text!\n"); |
| return E_OUTOFMEMORY; |
| } |
| |
| /****************************************************************************** |
| * VarBstrFromI1 (OLEAUT32.229) |
| * |
| * Convert a VT_I1 to a VT_BSTR. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| ULONG64 ul64 = cIn; |
| |
| if (cIn < 0) |
| { |
| ul64 = -cIn; |
| dwFlags |= VAR_NEGATIVE; |
| } |
| return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); |
| } |
| |
| /****************************************************************************** |
| * VarBstrFromUI2 (OLEAUT32.230) |
| * |
| * Convert a VT_UI2 to a VT_BSTR. |
| * |
| * PARAMS |
| * usIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut); |
| } |
| |
| /****************************************************************************** |
| * VarBstrFromUI4 (OLEAUT32.231) |
| * |
| * Convert a VT_UI4 to a VT_BSTR. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut); |
| } |
| |
| /****************************************************************************** |
| * VarBstrFromDec (OLEAUT32.232) |
| * |
| * Convert a VT_DECIMAL to a VT_BSTR. |
| * |
| * PARAMS |
| * pDecIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| WCHAR buff[256]; |
| VARIANT_DI temp; |
| |
| if (!pbstrOut) |
| return E_INVALIDARG; |
| |
| VARIANT_DIFromDec(pDecIn, &temp); |
| VARIANT_DI_tostringW(&temp, buff, 256); |
| |
| if (dwFlags & LOCALE_USE_NLS) |
| { |
| WCHAR numbuff[256]; |
| |
| /* Format the number for the locale */ |
| numbuff[0] = '\0'; |
| GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, |
| buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR)); |
| TRACE("created NLS string %s\n", debugstr_w(numbuff)); |
| *pbstrOut = SysAllocString(numbuff); |
| } |
| else |
| { |
| *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags); |
| } |
| |
| TRACE("returning %s\n", debugstr_w(*pbstrOut)); |
| return *pbstrOut ? S_OK : E_OUTOFMEMORY; |
| } |
| |
| /************************************************************************ |
| * VarBstrFromI8 (OLEAUT32.370) |
| * |
| * Convert a VT_I8 to a VT_BSTR. |
| * |
| * PARAMS |
| * llIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| ULONG64 ul64 = llIn; |
| |
| if (llIn < 0) |
| { |
| ul64 = -llIn; |
| dwFlags |= VAR_NEGATIVE; |
| } |
| return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); |
| } |
| |
| /************************************************************************ |
| * VarBstrFromUI8 (OLEAUT32.371) |
| * |
| * Convert a VT_UI8 to a VT_BSTR. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * lcid [I] LCID for the conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut); |
| } |
| |
| /************************************************************************ |
| * VarBstrFromDisp (OLEAUT32.115) |
| * |
| * Convert a VT_DISPATCH to a BSTR. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags); |
| } |
| |
| /********************************************************************** |
| * VarBstrCat (OLEAUT32.313) |
| * |
| * Concatenate two BSTR values. |
| * |
| * PARAMS |
| * pbstrLeft [I] Source |
| * pbstrRight [I] Value to concatenate |
| * pbstrOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if pbstrOut is invalid. |
| * E_OUTOFMEMORY, if memory allocation fails. |
| */ |
| HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut) |
| { |
| unsigned int len; |
| |
| if (!pbstrOut) |
| return E_INVALIDARG; |
| |
| len = pbstrLeft ? strlenW(pbstrLeft) : 0; |
| if (pbstrRight) |
| len += strlenW(pbstrRight); |
| |
| *pbstrOut = SysAllocStringLen(NULL, len); |
| if (!*pbstrOut) |
| return E_OUTOFMEMORY; |
| |
| (*pbstrOut)[0] = '\0'; |
| |
| if (pbstrLeft) |
| strcpyW(*pbstrOut, pbstrLeft); |
| |
| if (pbstrRight) |
| strcatW(*pbstrOut, pbstrRight); |
| |
| return S_OK; |
| } |
| |
| /********************************************************************** |
| * VarBstrCmp (OLEAUT32.314) |
| * |
| * Compare two BSTR values. |
| * |
| * PARAMS |
| * pbstrLeft [I] Source |
| * pbstrRight [I] Value to compare |
| * lcid [I] LCID for the comparison |
| * dwFlags [I] Flags to pass directly to CompareStringW(). |
| * |
| * RETURNS |
| * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less |
| * than, equal to or greater than pbstrRight respectively. |
| * |
| * NOTES |
| * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN |
| * states. A NULL BSTR pointer is equivalent to an empty string. |
| */ |
| HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags) |
| { |
| if (!pbstrLeft || !*pbstrLeft) |
| { |
| if (!pbstrRight || !*pbstrRight) |
| return VARCMP_EQ; |
| return VARCMP_LT; |
| } |
| else if (!pbstrRight || !*pbstrRight) |
| return VARCMP_GT; |
| |
| return CompareStringW(lcid, dwFlags, pbstrLeft, -1, pbstrRight, -1) - 1; |
| } |
| |
| /* |
| * DATE |
| */ |
| |
| /****************************************************************************** |
| * VarDateFromUI1 (OLEAUT32.88) |
| * |
| * Convert a VT_UI1 to a VT_DATE. |
| * |
| * PARAMS |
| * bIn [I] Source |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut) |
| { |
| return VarR8FromUI1(bIn, pdateOut); |
| } |
| |
| /****************************************************************************** |
| * VarDateFromI2 (OLEAUT32.89) |
| * |
| * Convert a VT_I2 to a VT_DATE. |
| * |
| * PARAMS |
| * sIn [I] Source |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut) |
| { |
| return VarR8FromI2(sIn, pdateOut); |
| } |
| |
| /****************************************************************************** |
| * VarDateFromI4 (OLEAUT32.90) |
| * |
| * Convert a VT_I4 to a VT_DATE. |
| * |
| * PARAMS |
| * lIn [I] Source |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut) |
| { |
| return VarDateFromR8(lIn, pdateOut); |
| } |
| |
| /****************************************************************************** |
| * VarDateFromR4 (OLEAUT32.91) |
| * |
| * Convert a VT_R4 to a VT_DATE. |
| * |
| * PARAMS |
| * fltIn [I] Source |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut) |
| { |
| return VarR8FromR4(fltIn, pdateOut); |
| } |
| |
| /****************************************************************************** |
| * VarDateFromR8 (OLEAUT32.92) |
| * |
| * Convert a VT_R8 to a VT_DATE. |
| * |
| * PARAMS |
| * dblIn [I] Source |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut) |
| { |
| if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW; |
| *pdateOut = (DATE)dblIn; |
| return S_OK; |
| } |
| |
| /********************************************************************** |
| * VarDateFromDisp (OLEAUT32.95) |
| * |
| * Convert a VT_DISPATCH to a VT_DATE. |
| * |
| * PARAMS |
| * pdispIn [I] Source |
| * lcid [I] LCID for conversion |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: E_INVALIDARG, if the source value is invalid |
| * DISP_E_OVERFLOW, if the value will not fit in the destination |
| * DISP_E_TYPEMISMATCH, if the type cannot be converted |
| */ |
| HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut) |
| { |
| return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0); |
| } |
| |
| /****************************************************************************** |
| * VarDateFromBool (OLEAUT32.96) |
| * |
| * Convert a VT_BOOL to a VT_DATE. |
| * |
| * PARAMS |
| * boolIn [I] Source |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut) |
| { |
| return VarR8FromBool(boolIn, pdateOut); |
| } |
| |
| /********************************************************************** |
| * VarDateFromCy (OLEAUT32.93) |
| * |
| * Convert a VT_CY to a VT_DATE. |
| * |
| * PARAMS |
| * lIn [I] Source |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) |
| { |
| return VarR8FromCy(cyIn, pdateOut); |
| } |
| |
| /* Date string parsing */ |
| #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */ |
| #define DP_DATESEP 0x02 /* Date separator */ |
| #define DP_MONTH 0x04 /* Month name */ |
| #define DP_AM 0x08 /* AM */ |
| #define DP_PM 0x10 /* PM */ |
| |
| typedef struct tagDATEPARSE |
| { |
| DWORD dwCount; /* Number of fields found so far (maximum 6) */ |
| DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */ |
| DWORD dwFlags[6]; /* Flags for each field */ |
| DWORD dwValues[6]; /* Value of each field */ |
| } DATEPARSE; |
| |
| #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i) |
| |
| #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0))) |
| |
| /* Determine if a day is valid in a given month of a given year */ |
| static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year) |
| { |
| static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
| |
| if (day && month && month < 13) |
| { |
| if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year))) |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| /* Possible orders for 3 numbers making up a date */ |
| #define ORDER_MDY 0x01 |
| #define ORDER_YMD 0x02 |
| #define ORDER_YDM 0x04 |
| #define ORDER_DMY 0x08 |
| #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */ |
| |
| /* Determine a date for a particular locale, from 3 numbers */ |
| static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate, |
| DWORD offset, SYSTEMTIME *st) |
| { |
| DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3; |
| |
| if (!dp->dwCount) |
| { |
| v1 = 30; /* Default to (Variant) 0 date part */ |
| v2 = 12; |
| v3 = 1899; |
| goto VARIANT_MakeDate_OK; |
| } |
| |
| v1 = dp->dwValues[offset + 0]; |
| v2 = dp->dwValues[offset + 1]; |
| if (dp->dwCount == 2) |
| { |
| SYSTEMTIME current; |
| GetSystemTime(¤t); |
| v3 = current.wYear; |
| } |
| else |
| v3 = dp->dwValues[offset + 2]; |
| |
| TRACE("(%ld,%ld,%ld,%ld,%ld)\n", v1, v2, v3, iDate, offset); |
| |
| /* If one number must be a month (Because a month name was given), then only |
| * consider orders with the month in that position. |
| * If we took the current year as 'v3', then only allow a year in that position. |
| */ |
| if (dp->dwFlags[offset + 0] & DP_MONTH) |
| { |
| dwAllOrders = ORDER_MDY; |
| } |
| else if (dp->dwFlags[offset + 1] & DP_MONTH) |
| { |
| dwAllOrders = ORDER_DMY; |
| if (dp->dwCount > 2) |
| dwAllOrders |= ORDER_YMD; |
| } |
| else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH) |
| { |
| dwAllOrders = ORDER_YDM; |
| } |
| else |
| { |
| dwAllOrders = ORDER_MDY|ORDER_DMY; |
| if (dp->dwCount > 2) |
| dwAllOrders |= (ORDER_YMD|ORDER_YDM); |
| } |
| |
| VARIANT_MakeDate_Start: |
| TRACE("dwAllOrders is 0x%08lx\n", dwAllOrders); |
| |
| while (dwAllOrders) |
| { |
| DWORD dwTemp; |
| |
| if (dwCount == 0) |
| { |
| /* First: Try the order given by iDate */ |
| switch (iDate) |
| { |
| case 0: dwTry = dwAllOrders & ORDER_MDY; break; |
| case 1: dwTry = dwAllOrders & ORDER_DMY; break; |
| default: dwTry = dwAllOrders & ORDER_YMD; break; |
| } |
| } |
| else if (dwCount == 1) |
| { |
| /* Second: Try all the orders compatible with iDate */ |
| switch (iDate) |
| { |
| case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break; |
| case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break; |
| default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break; |
| } |
| } |
| else |
| { |
| /* Finally: Try any remaining orders */ |
| dwTry = dwAllOrders; |
| } |
| |
| TRACE("Attempt %ld, dwTry is 0x%08lx\n", dwCount, dwTry); |
| |
| dwCount++; |
| if (!dwTry) |
| continue; |
| |
| #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0) |
| |
| if (dwTry & ORDER_MDY) |
| { |
| if (VARIANT_IsValidMonthDay(v2,v1,v3)) |
| { |
| DATE_SWAP(v1,v2); |
| goto VARIANT_MakeDate_OK; |
| } |
| dwAllOrders &= ~ORDER_MDY; |
| } |
| if (dwTry & ORDER_YMD) |
| { |
| if (VARIANT_IsValidMonthDay(v3,v2,v1)) |
| { |
| DATE_SWAP(v1,v3); |
| goto VARIANT_MakeDate_OK; |
| } |
| dwAllOrders &= ~ORDER_YMD; |
| } |
| if (dwTry & ORDER_YDM) |
| { |
| if (VARIANT_IsValidMonthDay(v2,v3,v1)) |
| { |
| DATE_SWAP(v1,v2); |
| DATE_SWAP(v2,v3); |
| goto VARIANT_MakeDate_OK; |
| } |
| dwAllOrders &= ~ORDER_YDM; |
| } |
| if (dwTry & ORDER_DMY) |
| { |
| if (VARIANT_IsValidMonthDay(v1,v2,v3)) |
| goto VARIANT_MakeDate_OK; |
| dwAllOrders &= ~ORDER_DMY; |
| } |
| if (dwTry & ORDER_MYD) |
| { |
| /* Only occurs if we are trying a 2 year date as M/Y not D/M */ |
| if (VARIANT_IsValidMonthDay(v3,v1,v2)) |
| { |
| DATE_SWAP(v1,v3); |
| DATE_SWAP(v2,v3); |
| goto VARIANT_MakeDate_OK; |
| } |
| dwAllOrders &= ~ORDER_MYD; |
| } |
| } |
| |
| if (dp->dwCount == 2) |
| { |
| /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */ |
| v3 = 1; /* 1st of the month */ |
| dwAllOrders = ORDER_YMD|ORDER_MYD; |
| dp->dwCount = 0; /* Don't return to this code path again */ |
| dwCount = 0; |
| goto VARIANT_MakeDate_Start; |
| } |
| |
| /* No valid dates were able to be constructed */ |
| return DISP_E_TYPEMISMATCH; |
| |
| VARIANT_MakeDate_OK: |
| |
| /* Check that the time part is ok */ |
| if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59) |
| return DISP_E_TYPEMISMATCH; |
| |
| TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond); |
| if (st->wHour < 12 && (dp->dwParseFlags & DP_PM)) |
| st->wHour += 12; |
| else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM)) |
| st->wHour = 0; |
| TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond); |
| |
| st->wDay = v1; |
| st->wMonth = v2; |
| /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may |
| * be retrieved from: |
| * HKCU\Control Panel\International\Calendars\TwoDigitYearMax |
| * But Wine doesn't have/use that key as at the time of writing. |
| */ |
| st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3; |
| TRACE("Returning date %ld/%ld/%d\n", v1, v2, st->wYear); |
| return S_OK; |
| } |
| |
| /****************************************************************************** |
| * VarDateFromStr [OLEAUT32.94] |
| * |
| * Convert a VT_BSTR to at VT_DATE. |
| * |
| * PARAMS |
| * strIn [I] String to convert |
| * lcid [I] Locale identifier for the conversion |
| * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h") |
| * pdateOut [O] Destination for the converted value |
| * |
| * RETURNS |
| * Success: S_OK. pdateOut contains the converted value. |
| * FAILURE: An HRESULT error code indicating the prolem. |
| * |
| * NOTES |
| * Any date format that can be created using the date formats from lcid |
| * (Either from kernel Nls functions, variant conversion or formatting) is a |
| * valid input to this function. In addition, a few more esoteric formats are |
| * also supported for compatibility with the native version. The date is |
| * interpreted according to the date settings in the control panel, unless |
| * the date is invalid in that format, in which the most compatible format |
| * that produces a valid date will be used. |
| */ |
| HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut) |
| { |
| static const USHORT ParseDateTokens[] = |
| { |
| LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4, |
| LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, |
| LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12, |
| LOCALE_SMONTHNAME13, |
| LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, |
| LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, |
| LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, |
| LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12, |
| LOCALE_SABBREVMONTHNAME13, |
| LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, |
| LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7, |
| LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, |
| LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6, |
| LOCALE_SABBREVDAYNAME7, |
| LOCALE_S1159, LOCALE_S2359 |
| }; |
| static const BYTE ParseDateMonths[] = |
| { |
| 1,2,3,4,5,6,7,8,9,10,11,12,13, |
| 1,2,3,4,5,6,7,8,9,10,11,12,13 |
| }; |
| size_t i; |
| BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])]; |
| DATEPARSE dp; |
| DWORD dwDateSeps = 0, iDate = 0; |
| HRESULT hRet = S_OK; |
| |
| if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) == |
| (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) |
| return E_INVALIDARG; |
| |
| if (!strIn) |
| return DISP_E_TYPEMISMATCH; |
| |
| *pdateOut = 0.0; |
| |
| TRACE("(%s,0x%08lx,0x%08lx,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut); |
| |
| memset(&dp, 0, sizeof(dp)); |
| |
| GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE), |
| (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR)); |
| TRACE("iDate is %ld\n", iDate); |
| |
| /* Get the month/day/am/pm tokens for this locale */ |
| for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) |
| { |
| WCHAR buff[128]; |
| LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE); |
| |
| /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or |
| * GetAltMonthNames(). We should really cache these strings too. |
| */ |
| buff[0] = '\0'; |
| GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR)); |
| tokens[i] = SysAllocString(buff); |
| TRACE("token %d is %s\n", i, debugstr_w(tokens[i])); |
| } |
| |
| /* Parse the string into our structure */ |
| while (*strIn) |
| { |
| if (dp.dwCount > 6) |
| break; |
| |
| if (isdigitW(*strIn)) |
| { |
| dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10); |
| dp.dwCount++; |
| strIn--; |
| } |
| else if (isalpha(*strIn)) |
| { |
| BOOL bFound = FALSE; |
| |
| for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) |
| { |
| DWORD dwLen = strlenW(tokens[i]); |
| if (dwLen && !strncmpiW(strIn, tokens[i], dwLen)) |
| { |
| if (i <= 25) |
| { |
| dp.dwValues[dp.dwCount] = ParseDateMonths[i]; |
| dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP); |
| dp.dwCount++; |
| } |
| else if (i > 39) |
| { |
| if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM)) |
| hRet = DISP_E_TYPEMISMATCH; |
| else |
| { |
| dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM); |
| dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM); |
| } |
| } |
| strIn += (dwLen - 1); |
| bFound = TRUE; |
| break; |
| } |
| } |
| |
| if (!bFound) |
| { |
| if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') && |
| (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM)))) |
| { |
| /* Special case - 'a' and 'p' are recognised as short for am/pm */ |
| if (*strIn == 'a' || *strIn == 'A') |
| { |
| dp.dwFlags[dp.dwCount - 1] |= DP_AM; |
| dp.dwParseFlags |= DP_AM; |
| } |
| else |
| { |
| dp.dwFlags[dp.dwCount - 1] |= DP_PM; |
| dp.dwParseFlags |= DP_PM; |
| } |
| strIn++; |
| } |
| else |
| { |
| TRACE("No matching token for %s\n", debugstr_w(strIn)); |
| hRet = DISP_E_TYPEMISMATCH; |
| break; |
| } |
| } |
| } |
| else if (*strIn == ':' || *strIn == '.') |
| { |
| if (!dp.dwCount || !strIn[1]) |
| hRet = DISP_E_TYPEMISMATCH; |
| else |
| dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP; |
| } |
| else if (*strIn == '-' || *strIn == '/') |
| { |
| dwDateSeps++; |
| if (dwDateSeps > 2 || !dp.dwCount || !strIn[1]) |
| hRet = DISP_E_TYPEMISMATCH; |
| else |
| dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP; |
| } |
| else if (*strIn == ',' || isspaceW(*strIn)) |
| { |
| if (*strIn == ',' && !strIn[1]) |
| hRet = DISP_E_TYPEMISMATCH; |
| } |
| else |
| { |
| hRet = DISP_E_TYPEMISMATCH; |
| } |
| strIn++; |
| } |
| |
| if (!dp.dwCount || dp.dwCount > 6 || |
| (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM)))) |
| hRet = DISP_E_TYPEMISMATCH; |
| |
| if (SUCCEEDED(hRet)) |
| { |
| SYSTEMTIME st; |
| DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */ |
| |
| st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0; |
| |
| /* Figure out which numbers correspond to which fields. |
| * |
| * This switch statement works based on the fact that native interprets any |
| * fields that are not joined with a time separator ('.' or ':') as date |
| * fields. Thus we construct a value from 0-32 where each set bit indicates |
| * a time field. This encapsulates the hundreds of permutations of 2-6 fields. |
| * For valid permutations, we set dwOffset to point to the first date field |
| * and shorten dp.dwCount by the number of time fields found. The real |
| * magic here occurs in VARIANT_MakeDate() above, where we determine what |
| * each date number must represent in the context of iDate. |
| */ |
| TRACE("0x%08lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4)); |
| |
| switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4)) |
| { |
| case 0x1: /* TT TTDD TTDDD */ |
| if (dp.dwCount > 3 && |
| ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) || |
| (dp.dwFlags[4] & (DP_AM|DP_PM)))) |
| hRet = DISP_E_TYPEMISMATCH; |
| else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5) |
| hRet = DISP_E_TYPEMISMATCH; |
| st.wHour = dp.dwValues[0]; |
| st.wMinute = dp.dwValues[1]; |
| dp.dwCount -= 2; |
| dwOffset = 2; |
| break; |
| |
| case 0x3: /* TTT TTTDD TTTDDD */ |
| if (dp.dwCount > 4 && |
| ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) || |
| (dp.dwFlags[5] & (DP_AM|DP_PM)))) |
| hRet = DISP_E_TYPEMISMATCH; |
| else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6) |
| hRet = DISP_E_TYPEMISMATCH; |
| st.wHour = dp.dwValues[0]; |
| st.wMinute = dp.dwValues[1]; |
| st.wSecond = dp.dwValues[2]; |
| dwOffset = 3; |
| dp.dwCount -= 3; |
| break; |
| |
| case 0x4: /* DDTT */ |
| if (dp.dwCount != 4 || |
| (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM))) |
| hRet = DISP_E_TYPEMISMATCH; |
| |
| st.wHour = dp.dwValues[2]; |
| st.wMinute = dp.dwValues[3]; |
| dp.dwCount -= 2; |
| break; |
| |
| case 0x0: /* T DD DDD TDDD TDDD */ |
| if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM))) |
| { |
| st.wHour = dp.dwValues[0]; /* T */ |
| dp.dwCount = 0; |
| break; |
| } |
| else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM))) |
| { |
| hRet = DISP_E_TYPEMISMATCH; |
| } |
| else if (dp.dwCount == 3) |
| { |
| if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */ |
| { |
| dp.dwCount = 2; |
| st.wHour = dp.dwValues[0]; |
| dwOffset = 1; |
| break; |
| } |
| if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */ |
| { |
| dp.dwCount = 2; |
| st.wHour = dp.dwValues[2]; |
| break; |
| } |
| else if (dp.dwParseFlags & (DP_AM|DP_PM)) |
| hRet = DISP_E_TYPEMISMATCH; |
| } |
| else if (dp.dwCount == 4) |
| { |
| dp.dwCount = 3; |
| if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */ |
| { |
| st.wHour = dp.dwValues[0]; |
| dwOffset = 1; |
| } |
| else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */ |
| { |
| st.wHour = dp.dwValues[3]; |
| } |
| else |
| hRet = DISP_E_TYPEMISMATCH; |
| break; |
| } |
| /* .. fall through .. */ |
| |
| case 0x8: /* DDDTT */ |
| if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) || |
| (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) || |
| (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) || |
| dp.dwCount == 4 || dp.dwCount == 6) |
| hRet = DISP_E_TYPEMISMATCH; |
| st.wHour = dp.dwValues[3]; |
| st.wMinute = dp.dwValues[4]; |
| if (dp.dwCount == 5) |
| dp.dwCount -= 2; |
| break; |
| |
| case 0xC: /* DDTTT */ |
| if (dp.dwCount != 5 || |
| (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM))) |
| hRet = DISP_E_TYPEMISMATCH; |
| st.wHour = dp.dwValues[2]; |
| st.wMinute = dp.dwValues[3]; |
| st.wSecond = dp.dwValues[4]; |
| dp.dwCount -= 3; |
| break; |
| |
| case 0x18: /* DDDTTT */ |
| if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) || |
| (dp.dwFlags[2] & (DP_AM|DP_PM))) |
| hRet = DISP_E_TYPEMISMATCH; |
| st.wHour = dp.dwValues[3]; |
| st.wMinute = dp.dwValues[4]; |
| st.wSecond = dp.dwValues[5]; |
| dp.dwCount -= 3; |
| break; |
| |
| default: |
| hRet = DISP_E_TYPEMISMATCH; |
| break; |
| } |
| |
| if (SUCCEEDED(hRet)) |
| { |
| hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st); |
| |
| if (dwFlags & VAR_TIMEVALUEONLY) |
| { |
| st.wYear = 1899; |
| st.wMonth = 12; |
| st.wDay = 30; |
| } |
| else if (dwFlags & VAR_DATEVALUEONLY) |
| st.wHour = st.wMinute = st.wSecond = 0; |
| |
| /* Finally, convert the value to a VT_DATE */ |
| if (SUCCEEDED(hRet)) |
| hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH; |
| } |
| } |
| |
| for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) |
| SysFreeString(tokens[i]); |
| return hRet; |
| } |
| |
| /****************************************************************************** |
| * VarDateFromI1 (OLEAUT32.221) |
| * |
| * Convert a VT_I1 to a VT_DATE. |
| * |
| * PARAMS |
| * cIn [I] Source |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut) |
| { |
| return VarR8FromI1(cIn, pdateOut); |
| } |
| |
| /****************************************************************************** |
| * VarDateFromUI2 (OLEAUT32.222) |
| * |
| * Convert a VT_UI2 to a VT_DATE. |
| * |
| * PARAMS |
| * uiIn [I] Source |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut) |
| { |
| return VarR8FromUI2(uiIn, pdateOut); |
| } |
| |
| /****************************************************************************** |
| * VarDateFromUI4 (OLEAUT32.223) |
| * |
| * Convert a VT_UI4 to a VT_DATE. |
| * |
| * PARAMS |
| * ulIn [I] Source |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut) |
| { |
| return VarDateFromR8(ulIn, pdateOut); |
| } |
| |
| /********************************************************************** |
| * VarDateFromDec (OLEAUT32.224) |
| * |
| * Convert a VT_DECIMAL to a VT_DATE. |
| * |
| * PARAMS |
| * pdecIn [I] Source |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * S_OK. |
| */ |
| HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut) |
| { |
| return VarR8FromDec(pdecIn, pdateOut); |
| } |
| |
| /****************************************************************************** |
| * VarDateFromI8 (OLEAUT32.364) |
| * |
| * Convert a VT_I8 to a VT_DATE. |
| * |
| * PARAMS |
| * llIn [I] Source |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut) |
| { |
| if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW; |
| *pdateOut = (DATE)llIn; |
| return S_OK; |
| } |
| |
| /****************************************************************************** |
| * VarDateFromUI8 (OLEAUT32.365) |
| * |
| * Convert a VT_UI8 to a VT_DATE. |
| * |
| * PARAMS |
| * ullIn [I] Source |
| * pdateOut [O] Destination |
| * |
| * RETURNS |
| * Success: S_OK. |
| * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination |
| */ |
| HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut) |
| { |
| if (ullIn > DATE_MAX) return DISP_E_OVERFLOW; |
| *pdateOut = (DATE)ullIn; |
| return S_OK; |
| } |