Sweden-Number/dlls/oleaut32/vartype.c

6783 lines
171 KiB
C

/*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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)
{
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, 0, 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);
}
/************************************************************************
* 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);
}
/************************************************************************
* 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);
}
/************************************************************************
* 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);
}
/************************************************************************
* 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);
}
/************************************************************************
* 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);
}
/************************************************************************
* 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);
}
/************************************************************************
* 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);
}
/************************************************************************
* 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);
}
/************************************************************************
* 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 *= 1.0e64;
}
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);
}
/************************************************************************
* 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 *= 1.0e64;
}
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);
}
/************************************************************************
* 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);
}
/************************************************************************
* 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;
}
/************************************************************************
* 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)
{
FIXME("(%p,%p,%p)-stub!\n",pDecLeft,pDecRight,pDecOut);
return DISP_E_OVERFLOW;
}
/************************************************************************
* 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)
{
/* FIXME: This only allows multiplying by a fixed integer <= 0xffffffff */
if (!DEC_SCALE(pDecLeft) || !DEC_SCALE(pDecRight))
{
/* At least one term is an integer */
const DECIMAL* pDecInteger = DEC_SCALE(pDecLeft) ? pDecRight : pDecLeft;
const DECIMAL* pDecOperand = DEC_SCALE(pDecLeft) ? pDecLeft : pDecRight;
HRESULT hRet = S_OK;
unsigned int multiplier = DEC_LO32(pDecInteger);
ULONG overflow = 0;
if (DEC_HI32(pDecInteger) || DEC_MID32(pDecInteger))
{
FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut);
return DISP_E_OVERFLOW;
}
DEC_LO32(pDecOut) = VARIANT_Mul(DEC_LO32(pDecOperand), multiplier, &overflow);
DEC_MID32(pDecOut) = VARIANT_Mul(DEC_MID32(pDecOperand), multiplier, &overflow);
DEC_HI32(pDecOut) = VARIANT_Mul(DEC_HI32(pDecOperand), multiplier, &overflow);
if (overflow)
hRet = DISP_E_OVERFLOW;
else
{
BYTE sign = DECIMAL_POS;
if (DEC_SIGN(pDecLeft) != DEC_SIGN(pDecRight))
sign = DECIMAL_NEG; /* pos * neg => negative */
DEC_SIGN(pDecOut) = sign;
DEC_SCALE(pDecOut) = DEC_SCALE(pDecOperand);
}
return hRet;
}
FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut);
return DISP_E_OVERFLOW;
}
/************************************************************************
* 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);
}
/************************************************************************
* 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 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
{
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 */
*pbstrOut = 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");
*pbstrOut = SysAllocString(buff);
}
else
{
TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
*pbstrOut = SysAllocString(numbuff);
}
}
}
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)
{
if (!pbstrOut)
return E_INVALIDARG;
if (!DEC_SCALE(pDecIn) && !DEC_HI32(pDecIn))
{
WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
/* Create the basic number string */
*szOut-- = '\0';
szOut = VARIANT_WriteNumber(DEC_LO64(pDecIn), szOut);
if (DEC_SIGN(pDecIn))
dwFlags |= VAR_NEGATIVE;
*pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
TRACE("returning %s\n", debugstr_w(*pbstrOut));
return *pbstrOut ? S_OK : E_OUTOFMEMORY;
}
FIXME("semi-stub\n");
return E_INVALIDARG;
}
/************************************************************************
* 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);
}
/**********************************************************************
* 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.
* VARCMP_NULL is returned if either string is NULL, unless both are NULL
* in which case VARCMP_EQ is returned.
*/
HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
{
if (!pbstrLeft)
{
if (!pbstrRight || !*pbstrRight)
return VARCMP_EQ;
return VARCMP_NULL;
}
else if (!pbstrRight)
{
if (!*pbstrLeft)
return VARCMP_EQ;
return VARCMP_NULL;
}
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);
}
/******************************************************************************
* 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(&current);
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;
}