mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
b440573d2a
Signed-off-by: Robert Wilhelm <robert.wilhelm@gmx.net> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
8089 lines
215 KiB
C
8089 lines
215 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#define COBJMACROS
|
|
#define NONAMELESSUNION
|
|
#define NONAMELESSSTRUCT
|
|
|
|
#include "wine/debug.h"
|
|
#include "winbase.h"
|
|
#include "winuser.h"
|
|
#include "winnt.h"
|
|
#include "variant.h"
|
|
#include "resource.h"
|
|
|
|
#include "locale.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(variant);
|
|
|
|
extern HMODULE hProxyDll DECLSPEC_HIDDEN;
|
|
|
|
#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)
|
|
|
|
/* 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;
|
|
case VT_BSTR: memcpy(pOut, &V_BSTR(srcVar), sizeof(BSTR)); 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(const 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 = ARRAY_SIZE(rgb);
|
|
np.dwInFlags = NUMPRS_STD;
|
|
|
|
hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
|
|
|
|
if (SUCCEEDED(hRet))
|
|
{
|
|
/* 1 << vt gives us the VTBIT constant for the destination number type */
|
|
hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
|
|
if (SUCCEEDED(hRet))
|
|
VARIANT_CopyData(&dstVar, vt, pOut);
|
|
}
|
|
return hRet;
|
|
}
|
|
|
|
/* Coerce VT_DISPATCH to another type */
|
|
static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut,
|
|
VARTYPE vt, DWORD dwFlags)
|
|
{
|
|
static 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 */
|
|
VariantInit(&srcVar);
|
|
hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
|
|
&emptyParams, &srcVar, NULL, NULL);
|
|
|
|
if (SUCCEEDED(hRet))
|
|
{
|
|
/* Convert the property to the requested type */
|
|
VariantInit(&dstVar);
|
|
hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt);
|
|
VariantClear(&srcVar);
|
|
|
|
if (SUCCEEDED(hRet))
|
|
VARIANT_CopyData(&dstVar, vt, pOut);
|
|
}
|
|
else
|
|
hRet = DISP_E_TYPEMISMATCH;
|
|
return hRet;
|
|
}
|
|
|
|
/* Inline return type */
|
|
#define RETTYP static inline 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 < 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, 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)
|
|
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 < I1_MIN - 0.5 || dblIn >= I1_MAX + 0.5)
|
|
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(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
|
|
{
|
|
return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI1FromDisp (OLEAUT32.252)
|
|
*
|
|
* Convert a VT_DISPATCH to a VT_I1.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* pcOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI1FromBool (OLEAUT32.253)
|
|
*
|
|
* Convert a VT_BOOL to a VT_I1.
|
|
*
|
|
* PARAMS
|
|
* boolIn [I] Source
|
|
* pcOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
|
|
{
|
|
return _VarI1FromBool(boolIn, pcOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI1FromUI2 (OLEAUT32.254)
|
|
*
|
|
* Convert a VT_UI2 to a VT_I1.
|
|
*
|
|
* PARAMS
|
|
* usIn [I] Source
|
|
* pcOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
|
|
{
|
|
return _VarI1FromUI2(usIn, pcOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI1FromUI4 (OLEAUT32.255)
|
|
*
|
|
* Convert a VT_UI4 to a VT_I1.
|
|
*
|
|
* PARAMS
|
|
* ulIn [I] Source
|
|
* pcOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
|
|
{
|
|
return _VarI1FromUI4(ulIn, pcOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI1FromDec (OLEAUT32.256)
|
|
*
|
|
* Convert a VT_DECIMAL to a VT_I1.
|
|
*
|
|
* PARAMS
|
|
* pDecIn [I] Source
|
|
* pcOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarI1FromDec(const 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 >= UI1_MAX + 0.5)
|
|
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(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
|
|
{
|
|
return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI1FromDisp (OLEAUT32.137)
|
|
*
|
|
* Convert a VT_DISPATCH to a VT_UI1.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* pbOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI1FromBool (OLEAUT32.138)
|
|
*
|
|
* Convert a VT_BOOL to a VT_UI1.
|
|
*
|
|
* PARAMS
|
|
* boolIn [I] Source
|
|
* pbOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
|
|
{
|
|
return _VarUI1FromBool(boolIn, pbOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI1FromI1 (OLEAUT32.237)
|
|
*
|
|
* Convert a VT_I1 to a VT_UI1.
|
|
*
|
|
* PARAMS
|
|
* cIn [I] Source
|
|
* pbOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
|
|
{
|
|
return _VarUI1FromI1(cIn, pbOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI1FromUI2 (OLEAUT32.238)
|
|
*
|
|
* Convert a VT_UI2 to a VT_UI1.
|
|
*
|
|
* PARAMS
|
|
* usIn [I] Source
|
|
* pbOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
|
|
{
|
|
return _VarUI1FromUI2(usIn, pbOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI1FromUI4 (OLEAUT32.239)
|
|
*
|
|
* Convert a VT_UI4 to a VT_UI1.
|
|
*
|
|
* PARAMS
|
|
* ulIn [I] Source
|
|
* pbOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
|
|
{
|
|
return _VarUI1FromUI4(ulIn, pbOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI1FromDec (OLEAUT32.240)
|
|
*
|
|
* Convert a VT_DECIMAL to a VT_UI1.
|
|
*
|
|
* PARAMS
|
|
* pDecIn [I] Source
|
|
* pbOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarUI1FromDec(const 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 < I2_MIN - 0.5 || dblIn >= I2_MAX + 0.5)
|
|
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(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
|
|
{
|
|
return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI2FromDisp (OLEAUT32.55)
|
|
*
|
|
* Convert a VT_DISPATCH to a VT_I2.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* psOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if pdispIn is invalid,
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination,
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI2FromBool (OLEAUT32.56)
|
|
*
|
|
* Convert a VT_BOOL to a VT_I2.
|
|
*
|
|
* PARAMS
|
|
* boolIn [I] Source
|
|
* psOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
|
|
{
|
|
return _VarI2FromBool(boolIn, psOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI2FromI1 (OLEAUT32.205)
|
|
*
|
|
* Convert a VT_I1 to a VT_I2.
|
|
*
|
|
* PARAMS
|
|
* cIn [I] Source
|
|
* psOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
|
|
{
|
|
return _VarI2FromI1(cIn, psOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI2FromUI2 (OLEAUT32.206)
|
|
*
|
|
* Convert a VT_UI2 to a VT_I2.
|
|
*
|
|
* PARAMS
|
|
* usIn [I] Source
|
|
* psOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
|
|
{
|
|
return _VarI2FromUI2(usIn, psOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI2FromUI4 (OLEAUT32.207)
|
|
*
|
|
* Convert a VT_UI4 to a VT_I2.
|
|
*
|
|
* PARAMS
|
|
* ulIn [I] Source
|
|
* psOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
|
|
{
|
|
return _VarI2FromUI4(ulIn, psOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI2FromDec (OLEAUT32.208)
|
|
*
|
|
* Convert a VT_DECIMAL to a VT_I2.
|
|
*
|
|
* PARAMS
|
|
* pDecIn [I] Source
|
|
* psOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarI2FromDec(const 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 >= UI2_MAX + 0.5)
|
|
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(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
|
|
{
|
|
return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI2FromDisp (OLEAUT32.265)
|
|
*
|
|
* Convert a VT_DISPATCH to a VT_UI2.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* pusOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI2FromBool (OLEAUT32.266)
|
|
*
|
|
* Convert a VT_BOOL to a VT_UI2.
|
|
*
|
|
* PARAMS
|
|
* boolIn [I] Source
|
|
* pusOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
|
|
{
|
|
return _VarUI2FromBool(boolIn, pusOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI2FromI1 (OLEAUT32.267)
|
|
*
|
|
* Convert a VT_I1 to a VT_UI2.
|
|
*
|
|
* PARAMS
|
|
* cIn [I] Source
|
|
* pusOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
|
|
{
|
|
return _VarUI2FromI1(cIn, pusOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI2FromUI4 (OLEAUT32.268)
|
|
*
|
|
* Convert a VT_UI4 to a VT_UI2.
|
|
*
|
|
* PARAMS
|
|
* ulIn [I] Source
|
|
* pusOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
|
|
{
|
|
return _VarUI2FromUI4(ulIn, pusOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI2FromDec (OLEAUT32.269)
|
|
*
|
|
* Convert a VT_DECIMAL to a VT_UI2.
|
|
*
|
|
* PARAMS
|
|
* pDecIn [I] Source
|
|
* pusOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarUI2FromDec(const 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 < I4_MIN - 0.5 || dblIn >= I4_MAX + 0.5)
|
|
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(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
|
|
{
|
|
return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI4FromDisp (OLEAUT32.65)
|
|
*
|
|
* Convert a VT_DISPATCH to a VT_I4.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* piOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI4FromBool (OLEAUT32.66)
|
|
*
|
|
* Convert a VT_BOOL to a VT_I4.
|
|
*
|
|
* PARAMS
|
|
* boolIn [I] Source
|
|
* piOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
|
|
{
|
|
return _VarI4FromBool(boolIn, piOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI4FromI1 (OLEAUT32.209)
|
|
*
|
|
* Convert a VT_I1 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(const 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 >= UI4_MAX + 0.5)
|
|
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(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
|
|
{
|
|
return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI4FromDisp (OLEAUT32.278)
|
|
*
|
|
* Convert a VT_DISPATCH to a VT_UI4.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* pulOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI4FromBool (OLEAUT32.279)
|
|
*
|
|
* Convert a VT_BOOL to a VT_UI4.
|
|
*
|
|
* PARAMS
|
|
* boolIn [I] Source
|
|
* pulOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
|
|
{
|
|
return _VarUI4FromBool(boolIn, pulOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI4FromI1 (OLEAUT32.280)
|
|
*
|
|
* Convert a VT_I1 to a VT_UI4.
|
|
*
|
|
* PARAMS
|
|
* cIn [I] Source
|
|
* pulOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
|
|
{
|
|
return _VarUI4FromI1(cIn, pulOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI4FromUI2 (OLEAUT32.281)
|
|
*
|
|
* Convert a VT_UI2 to a VT_UI4.
|
|
*
|
|
* PARAMS
|
|
* usIn [I] Source
|
|
* pulOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
|
|
{
|
|
return _VarUI4FromUI2(usIn, pulOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI4FromDec (OLEAUT32.282)
|
|
*
|
|
* Convert a VT_DECIMAL to a VT_UI4.
|
|
*
|
|
* PARAMS
|
|
* pDecIn [I] Source
|
|
* pulOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if pdecIn is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarUI4FromDec(const 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(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
|
|
{
|
|
return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI8FromDisp (OLEAUT32.340)
|
|
*
|
|
* Convert a VT_DISPATCH to a VT_I8.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* pi64Out [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI8FromBool (OLEAUT32.341)
|
|
*
|
|
* Convert a VT_BOOL to a VT_I8.
|
|
*
|
|
* PARAMS
|
|
* boolIn [I] Source
|
|
* pi64Out [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
|
|
{
|
|
return VarI8FromI2(boolIn, pi64Out);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI8FromI1 (OLEAUT32.342)
|
|
*
|
|
* Convert a VT_I1 to a VT_I8.
|
|
*
|
|
* PARAMS
|
|
* cIn [I] Source
|
|
* pi64Out [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
|
|
{
|
|
return _VarI8FromI1(cIn, pi64Out);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI8FromUI2 (OLEAUT32.343)
|
|
*
|
|
* Convert a VT_UI2 to a VT_I8.
|
|
*
|
|
* PARAMS
|
|
* usIn [I] Source
|
|
* pi64Out [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
|
|
{
|
|
return _VarI8FromUI2(usIn, pi64Out);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI8FromUI4 (OLEAUT32.344)
|
|
*
|
|
* Convert a VT_UI4 to a VT_I8.
|
|
*
|
|
* PARAMS
|
|
* ulIn [I] Source
|
|
* pi64Out [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
|
|
{
|
|
return _VarI8FromUI4(ulIn, pi64Out);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarI8FromDec (OLEAUT32.345)
|
|
*
|
|
* Convert a VT_DECIMAL to a VT_I8.
|
|
*
|
|
* PARAMS
|
|
* pDecIn [I] Source
|
|
* pi64Out [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarI8FromDec(const 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(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
|
|
{
|
|
return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI8FromDisp (OLEAUT32.436)
|
|
*
|
|
* Convert a VT_DISPATCH to a VT_UI8.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* pui64Out [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI8FromBool (OLEAUT32.437)
|
|
*
|
|
* Convert a VT_BOOL to a VT_UI8.
|
|
*
|
|
* PARAMS
|
|
* boolIn [I] Source
|
|
* pui64Out [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
|
|
{
|
|
return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
|
|
}
|
|
/************************************************************************
|
|
* VarUI8FromI1 (OLEAUT32.438)
|
|
*
|
|
* Convert a VT_I1 to a VT_UI8.
|
|
*
|
|
* PARAMS
|
|
* cIn [I] Source
|
|
* pui64Out [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
|
|
{
|
|
return _VarUI8FromI1(cIn, pui64Out);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI8FromUI2 (OLEAUT32.439)
|
|
*
|
|
* Convert a VT_UI2 to a VT_UI8.
|
|
*
|
|
* PARAMS
|
|
* usIn [I] Source
|
|
* pui64Out [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
|
|
{
|
|
return _VarUI8FromUI2(usIn, pui64Out);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI8FromUI4 (OLEAUT32.440)
|
|
*
|
|
* Convert a VT_UI4 to a VT_UI8.
|
|
*
|
|
* PARAMS
|
|
* ulIn [I] Source
|
|
* pui64Out [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
|
|
{
|
|
return _VarUI8FromUI4(ulIn, pui64Out);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarUI8FromDec (OLEAUT32.441)
|
|
*
|
|
* Convert a VT_DECIMAL to a VT_UI8.
|
|
*
|
|
* PARAMS
|
|
* pDecIn [I] Source
|
|
* pui64Out [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*
|
|
* NOTES
|
|
* Under native Win32, if the source value has a scale of 0, its sign is
|
|
* ignored, i.e. this function takes the absolute value rather than fail
|
|
* with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
|
|
* (use VarAbs() on pDecIn first if you really want this behaviour).
|
|
*/
|
|
HRESULT WINAPI VarUI8FromDec(const 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(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
|
|
{
|
|
return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR4FromDisp (OLEAUT32.75)
|
|
*
|
|
* Convert a VT_DISPATCH to a VT_R4.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* pFltOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR4FromBool (OLEAUT32.76)
|
|
*
|
|
* Convert a VT_BOOL to a VT_R4.
|
|
*
|
|
* PARAMS
|
|
* boolIn [I] Source
|
|
* pFltOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
|
|
{
|
|
return VarR4FromI2(boolIn, pFltOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR4FromI1 (OLEAUT32.213)
|
|
*
|
|
* Convert a VT_I1 to a VT_R4.
|
|
*
|
|
* PARAMS
|
|
* cIn [I] Source
|
|
* pFltOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
|
|
{
|
|
return _VarR4FromI1(cIn, pFltOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR4FromUI2 (OLEAUT32.214)
|
|
*
|
|
* Convert a VT_UI2 to a VT_R4.
|
|
*
|
|
* PARAMS
|
|
* usIn [I] Source
|
|
* pFltOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
|
|
{
|
|
return _VarR4FromUI2(usIn, pFltOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR4FromUI4 (OLEAUT32.215)
|
|
*
|
|
* Convert a VT_UI4 to a VT_R4.
|
|
*
|
|
* PARAMS
|
|
* ulIn [I] Source
|
|
* pFltOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
|
|
{
|
|
return _VarR4FromUI4(ulIn, pFltOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR4FromDec (OLEAUT32.216)
|
|
*
|
|
* Convert a VT_DECIMAL to a VT_R4.
|
|
*
|
|
* PARAMS
|
|
* pDecIn [I] Source
|
|
* pFltOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid.
|
|
*/
|
|
HRESULT WINAPI VarR4FromDec(const DECIMAL* pDecIn, float *pFltOut)
|
|
{
|
|
BYTE scale = DEC_SCALE(pDecIn);
|
|
double divisor = 1.0;
|
|
double highPart;
|
|
|
|
if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
|
|
return E_INVALIDARG;
|
|
|
|
while (scale--)
|
|
divisor *= 10.0;
|
|
|
|
if (DEC_SIGN(pDecIn))
|
|
divisor = -divisor;
|
|
|
|
if (DEC_HI32(pDecIn))
|
|
{
|
|
highPart = (double)DEC_HI32(pDecIn) / divisor;
|
|
highPart *= 4294967296.0F;
|
|
highPart *= 4294967296.0F;
|
|
}
|
|
else
|
|
highPart = 0.0;
|
|
|
|
*pFltOut = (double)DEC_LO64(pDecIn) / 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(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
|
|
{
|
|
return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR8FromDisp (OLEAUT32.85)
|
|
*
|
|
* Convert a VT_DISPATCH to a VT_R8.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* pDblOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR8FromBool (OLEAUT32.86)
|
|
*
|
|
* Convert a VT_BOOL to a VT_R8.
|
|
*
|
|
* PARAMS
|
|
* boolIn [I] Source
|
|
* pDblOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
|
|
{
|
|
return VarR8FromI2(boolIn, pDblOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR8FromI1 (OLEAUT32.217)
|
|
*
|
|
* Convert a VT_I1 to a VT_R8.
|
|
*
|
|
* PARAMS
|
|
* cIn [I] Source
|
|
* pDblOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
|
|
{
|
|
return _VarR8FromI1(cIn, pDblOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR8FromUI2 (OLEAUT32.218)
|
|
*
|
|
* Convert a VT_UI2 to a VT_R8.
|
|
*
|
|
* PARAMS
|
|
* usIn [I] Source
|
|
* pDblOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
|
|
{
|
|
return _VarR8FromUI2(usIn, pDblOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR8FromUI4 (OLEAUT32.219)
|
|
*
|
|
* Convert a VT_UI4 to a VT_R8.
|
|
*
|
|
* PARAMS
|
|
* ulIn [I] Source
|
|
* pDblOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
|
|
{
|
|
return _VarR8FromUI4(ulIn, pDblOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR8FromDec (OLEAUT32.220)
|
|
*
|
|
* Convert a VT_DECIMAL to a VT_R8.
|
|
*
|
|
* PARAMS
|
|
* pDecIn [I] Source
|
|
* pDblOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid.
|
|
*/
|
|
HRESULT WINAPI VarR8FromDec(const DECIMAL* pDecIn, double *pDblOut)
|
|
{
|
|
BYTE scale = DEC_SCALE(pDecIn);
|
|
double divisor = 1.0, highPart;
|
|
|
|
if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
|
|
return E_INVALIDARG;
|
|
|
|
while (scale--)
|
|
divisor *= 10;
|
|
|
|
if (DEC_SIGN(pDecIn))
|
|
divisor = -divisor;
|
|
|
|
if (DEC_HI32(pDecIn))
|
|
{
|
|
highPart = (double)DEC_HI32(pDecIn) / divisor;
|
|
highPart *= 4294967296.0F;
|
|
highPart *= 4294967296.0F;
|
|
}
|
|
else
|
|
highPart = 0.0;
|
|
|
|
*pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR8FromI8 (OLEAUT32.362)
|
|
*
|
|
* Convert a VT_I8 to a VT_R8.
|
|
*
|
|
* PARAMS
|
|
* ullIn [I] Source
|
|
* pDblOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
|
|
{
|
|
return _VarR8FromI8(llIn, pDblOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR8FromUI8 (OLEAUT32.363)
|
|
*
|
|
* Convert a VT_UI8 to a VT_R8.
|
|
*
|
|
* PARAMS
|
|
* ullIn [I] Source
|
|
* pDblOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
|
|
{
|
|
return _VarR8FromUI8(ullIn, pDblOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR8Pow (OLEAUT32.315)
|
|
*
|
|
* Raise a VT_R8 to a power.
|
|
*
|
|
* PARAMS
|
|
* dblLeft [I] Source
|
|
* dblPow [I] Power to raise dblLeft by
|
|
* pDblOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK. pDblOut contains dblLeft to the power of dblRight.
|
|
*/
|
|
HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
|
|
{
|
|
*pDblOut = pow(dblLeft, dblPow);
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarR8Round (OLEAUT32.317)
|
|
*
|
|
* Round a VT_R8 to a given number of decimal points.
|
|
*
|
|
* PARAMS
|
|
* dblIn [I] Source
|
|
* nDig [I] Number of decimal points to round to
|
|
* pDblOut [O] Destination for rounded number
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK. pDblOut is rounded to nDig digits.
|
|
* Failure: E_INVALIDARG, if cDecimals is less than 0.
|
|
*
|
|
* NOTES
|
|
* The native version of this function rounds using the internal
|
|
* binary representation of the number. Wine uses the dutch rounding
|
|
* convention, so therefore small differences can occur in the value returned.
|
|
* MSDN says that you should use your own rounding function if you want
|
|
* rounding to be predictable in your application.
|
|
*/
|
|
HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
|
|
{
|
|
double scale, whole, fract;
|
|
|
|
if (nDig < 0)
|
|
return E_INVALIDARG;
|
|
|
|
scale = pow(10.0, nDig);
|
|
|
|
dblIn *= scale;
|
|
whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
|
|
fract = dblIn - whole;
|
|
|
|
if (fract > 0.5)
|
|
dblIn = whole + 1.0;
|
|
else if (fract == 0.5)
|
|
dblIn = whole + fmod(whole, 2.0);
|
|
else if (fract >= 0.0)
|
|
dblIn = whole;
|
|
else if (fract == -0.5)
|
|
dblIn = whole - fmod(whole, 2.0);
|
|
else if (fract > -0.5)
|
|
dblIn = whole;
|
|
else
|
|
dblIn = whole - 1.0;
|
|
|
|
*pDblOut = dblIn / scale;
|
|
return S_OK;
|
|
}
|
|
|
|
/* CY
|
|
*/
|
|
|
|
/* Powers of 10 from 0..4 D.P. */
|
|
static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
|
|
CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
|
|
|
|
/************************************************************************
|
|
* VarCyFromUI1 (OLEAUT32.98)
|
|
*
|
|
* Convert a VT_UI1 to a VT_CY.
|
|
*
|
|
* PARAMS
|
|
* bIn [I] Source
|
|
* pCyOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
|
|
{
|
|
pCyOut->int64 = (ULONG64)bIn * CY_MULTIPLIER;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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)
|
|
{
|
|
pCyOut->int64 = (LONG64)sIn * CY_MULTIPLIER;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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)
|
|
{
|
|
pCyOut->int64 = (LONG64)lIn * CY_MULTIPLIER;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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__) || defined(__x86_64__))
|
|
/* 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;
|
|
#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(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
|
|
{
|
|
return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarCyFromDisp (OLEAUT32.105)
|
|
*
|
|
* Convert a VT_DISPATCH to a VT_CY.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* pCyOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarCyFromBool (OLEAUT32.106)
|
|
*
|
|
* Convert a VT_BOOL to a VT_CY.
|
|
*
|
|
* PARAMS
|
|
* boolIn [I] Source
|
|
* pCyOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*
|
|
* NOTES
|
|
* While the sign of the boolean is stored in the currency, the value is
|
|
* converted to either 0 or 1.
|
|
*/
|
|
HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
|
|
{
|
|
pCyOut->int64 = (LONG64)boolIn * CY_MULTIPLIER;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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)
|
|
{
|
|
pCyOut->int64 = (LONG64)cIn * CY_MULTIPLIER;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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)
|
|
{
|
|
pCyOut->int64 = (ULONG64)usIn * CY_MULTIPLIER;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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)
|
|
{
|
|
pCyOut->int64 = (ULONG64)ulIn * CY_MULTIPLIER;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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(const 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)
|
|
{
|
|
if (ullIn > (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
|
|
pCyOut->int64 = ullIn * CY_MULTIPLIER;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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(CY cyLeft, 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(CY cyLeft, 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(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(CY cyLeft, 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(CY cyIn, CY* pCyOut)
|
|
{
|
|
if (cyIn.s.Hi == 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(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(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(CY cyIn, CY* pCyOut)
|
|
{
|
|
if (cyIn.s.Hi == 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(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(CY cyLeft, 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(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(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;
|
|
}
|
|
|
|
/* internal representation of the value stored in a DECIMAL. The bytes are
|
|
stored from LSB at index 0 to MSB at index 11
|
|
*/
|
|
typedef struct DECIMAL_internal
|
|
{
|
|
DWORD bitsnum[3]; /* 96 significant bits, unsigned */
|
|
unsigned char scale; /* number scaled * 10 ^ -(scale) */
|
|
unsigned int sign : 1; /* 0 - positive, 1 - negative */
|
|
} VARIANT_DI;
|
|
|
|
static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest);
|
|
static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest);
|
|
static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to);
|
|
static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to);
|
|
static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor);
|
|
static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n);
|
|
|
|
/************************************************************************
|
|
* 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)
|
|
{
|
|
VARIANT_DI di;
|
|
HRESULT hres;
|
|
|
|
hres = VARIANT_DI_FromR4(fltIn, &di);
|
|
if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
|
|
return hres;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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)
|
|
{
|
|
VARIANT_DI di;
|
|
HRESULT hres;
|
|
|
|
hres = VARIANT_DI_FromR8(dblIn, &di);
|
|
if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
|
|
return hres;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
|
|
{
|
|
return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarDecFromDisp (OLEAUT32.198)
|
|
*
|
|
* Convert a VT_DISPATCH to a DECIMAL.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* pDecOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarDecFromBool (OLEAUT32.199)
|
|
*
|
|
* Convert a VT_BOOL to a DECIMAL.
|
|
*
|
|
* PARAMS
|
|
* bIn [I] Source
|
|
* pDecOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*
|
|
* NOTES
|
|
* The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
|
|
*/
|
|
HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
|
|
{
|
|
DEC_HI32(pDecOut) = 0;
|
|
DEC_MID32(pDecOut) = 0;
|
|
if (bIn)
|
|
{
|
|
DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
|
|
DEC_LO32(pDecOut) = 1;
|
|
}
|
|
else
|
|
{
|
|
DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
|
|
DEC_LO32(pDecOut) = 0;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarDecFromI1 (OLEAUT32.241)
|
|
*
|
|
* Convert a VT_I1 to a DECIMAL.
|
|
*
|
|
* PARAMS
|
|
* cIn [I] Source
|
|
* pDecOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
|
|
{
|
|
return VarDecFromI4(cIn, pDecOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarDecFromUI2 (OLEAUT32.242)
|
|
*
|
|
* Convert a VT_UI2 to a DECIMAL.
|
|
*
|
|
* PARAMS
|
|
* usIn [I] Source
|
|
* pDecOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
|
|
{
|
|
return VarDecFromUI4(usIn, pDecOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarDecFromUI4 (OLEAUT32.243)
|
|
*
|
|
* Convert a VT_UI4 to a DECIMAL.
|
|
*
|
|
* PARAMS
|
|
* ulIn [I] Source
|
|
* pDecOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
|
|
{
|
|
DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
|
|
DEC_HI32(pDecOut) = 0;
|
|
DEC_MID32(pDecOut) = 0;
|
|
DEC_LO32(pDecOut) = ulIn;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarDecFromI8 (OLEAUT32.374)
|
|
*
|
|
* Convert a VT_I8 to a DECIMAL.
|
|
*
|
|
* PARAMS
|
|
* llIn [I] Source
|
|
* pDecOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
|
|
{
|
|
PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
|
|
|
|
DEC_HI32(pDecOut) = 0;
|
|
|
|
/* Note: This assumes 2s complement integer representation */
|
|
if (pLi->u.HighPart & 0x80000000)
|
|
{
|
|
DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
|
|
DEC_LO64(pDecOut) = -pLi->QuadPart;
|
|
}
|
|
else
|
|
{
|
|
DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
|
|
DEC_MID32(pDecOut) = pLi->u.HighPart;
|
|
DEC_LO32(pDecOut) = pLi->u.LowPart;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarDecFromUI8 (OLEAUT32.375)
|
|
*
|
|
* Convert a VT_UI8 to a DECIMAL.
|
|
*
|
|
* PARAMS
|
|
* ullIn [I] Source
|
|
* pDecOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
|
|
{
|
|
DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
|
|
DEC_HI32(pDecOut) = 0;
|
|
DEC_LO64(pDecOut) = ullIn;
|
|
return S_OK;
|
|
}
|
|
|
|
/* Make two DECIMALS the same scale; used by math functions below */
|
|
static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
|
|
const DECIMAL** ppDecRight,
|
|
DECIMAL pDecOut[2])
|
|
{
|
|
static DECIMAL scaleFactor;
|
|
unsigned char remainder;
|
|
DECIMAL decTemp;
|
|
VARIANT_DI di;
|
|
int scaleAmount, i;
|
|
|
|
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[0];
|
|
}
|
|
else
|
|
{
|
|
decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
|
|
*ppDecLeft = &pDecOut[0];
|
|
i = -scaleAmount;
|
|
}
|
|
|
|
/* Multiply up the value to be scaled by the correct amount (if possible) */
|
|
while (i > 0 && SUCCEEDED(VarDecMul(&decTemp, &scaleFactor, &pDecOut[0])))
|
|
{
|
|
decTemp = pDecOut[0];
|
|
i--;
|
|
}
|
|
|
|
if (!i)
|
|
{
|
|
DEC_SCALE(&pDecOut[0]) += (scaleAmount > 0) ? scaleAmount : (-scaleAmount);
|
|
return S_OK; /* Same scale */
|
|
}
|
|
|
|
/* Scaling further not possible, reduce accuracy of other argument */
|
|
pDecOut[0] = decTemp;
|
|
if (scaleAmount > 0)
|
|
{
|
|
DEC_SCALE(&pDecOut[0]) += scaleAmount - i;
|
|
VARIANT_DIFromDec(*ppDecLeft, &di);
|
|
*ppDecLeft = &pDecOut[1];
|
|
}
|
|
else
|
|
{
|
|
DEC_SCALE(&pDecOut[0]) += (-scaleAmount) - i;
|
|
VARIANT_DIFromDec(*ppDecRight, &di);
|
|
*ppDecRight = &pDecOut[1];
|
|
}
|
|
|
|
di.scale -= i;
|
|
remainder = 0;
|
|
while (i-- > 0 && !VARIANT_int_iszero(di.bitsnum, ARRAY_SIZE(di.bitsnum)))
|
|
{
|
|
remainder = VARIANT_int_divbychar(di.bitsnum, ARRAY_SIZE(di.bitsnum), 10);
|
|
if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
|
|
}
|
|
|
|
/* round up the result - native oleaut32 does this */
|
|
if (remainder >= 5) {
|
|
for (remainder = 1, i = 0; i < ARRAY_SIZE(di.bitsnum) && remainder; i++) {
|
|
ULONGLONG digit = di.bitsnum[i] + 1;
|
|
remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
|
|
di.bitsnum[i] = digit & 0xFFFFFFFF;
|
|
}
|
|
}
|
|
|
|
VARIANT_DecFromDI(&di, &pDecOut[1]);
|
|
return S_OK;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
BOOL invert = FALSE;
|
|
ULARGE_INTEGER ul64;
|
|
|
|
ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
|
|
if (ulLeft < ulRight)
|
|
invert = TRUE;
|
|
|
|
if (ul64.QuadPart > (ULONG64)*pulHigh)
|
|
ul64.QuadPart -= (ULONG64)*pulHigh;
|
|
else
|
|
{
|
|
ul64.QuadPart -= (ULONG64)*pulHigh;
|
|
invert = TRUE;
|
|
}
|
|
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[2];
|
|
|
|
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;
|
|
int cmp;
|
|
|
|
/* 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))
|
|
{
|
|
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))
|
|
{
|
|
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)
|
|
{
|
|
int i;
|
|
DWORD n[4];
|
|
unsigned char remainder;
|
|
|
|
if (!DEC_SCALE(pDecLeft))
|
|
return DISP_E_OVERFLOW;
|
|
|
|
DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft) - 1;
|
|
DEC_SIGN(pDecOut) = sign;
|
|
|
|
n[0] = DEC_LO32(pDecOut);
|
|
n[1] = DEC_MID32(pDecOut);
|
|
n[2] = DEC_HI32(pDecOut);
|
|
n[3] = overflow;
|
|
|
|
remainder = VARIANT_int_divbychar(n,4,10);
|
|
|
|
/* round up the result */
|
|
if (remainder >= 5)
|
|
{
|
|
for (remainder = 1, i = 0; i < ARRAY_SIZE(n) && remainder; i++)
|
|
{
|
|
ULONGLONG digit = n[i] + 1;
|
|
remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
|
|
n[i] = digit & 0xFFFFFFFF;
|
|
}
|
|
}
|
|
|
|
DEC_LO32(pDecOut) = n[0] ;
|
|
DEC_MID32(pDecOut) = n[1];
|
|
DEC_HI32(pDecOut) = n[2];
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
if (overflow)
|
|
return DISP_E_OVERFLOW; /* overflowed */
|
|
|
|
DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
|
|
DEC_SIGN(pDecOut) = sign;
|
|
}
|
|
return hRet;
|
|
}
|
|
|
|
/* translate from external DECIMAL format into an internal representation */
|
|
static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
|
|
{
|
|
to->scale = DEC_SCALE(from);
|
|
to->sign = DEC_SIGN(from) ? 1 : 0;
|
|
|
|
to->bitsnum[0] = DEC_LO32(from);
|
|
to->bitsnum[1] = DEC_MID32(from);
|
|
to->bitsnum[2] = DEC_HI32(from);
|
|
}
|
|
|
|
static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to)
|
|
{
|
|
if (from->sign) {
|
|
DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
|
|
} else {
|
|
DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
|
|
}
|
|
|
|
DEC_LO32(to) = from->bitsnum[0];
|
|
DEC_MID32(to) = from->bitsnum[1];
|
|
DEC_HI32(to) = from->bitsnum[2];
|
|
}
|
|
|
|
/* clear an internal representation of a DECIMAL */
|
|
static void VARIANT_DI_clear(VARIANT_DI * i)
|
|
{
|
|
memset(i, 0, sizeof(VARIANT_DI));
|
|
}
|
|
|
|
/* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
|
|
size is supported. The value in p is replaced by the quotient of the division, and
|
|
the remainder is returned as a result. This routine is most often used with a divisor
|
|
of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
|
|
*/
|
|
static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
|
|
{
|
|
if (divisor == 0) {
|
|
/* division by 0 */
|
|
return 0xFF;
|
|
} else if (divisor == 1) {
|
|
/* dividend remains unchanged */
|
|
return 0;
|
|
} else {
|
|
unsigned char remainder = 0;
|
|
ULONGLONG iTempDividend;
|
|
signed int i;
|
|
|
|
for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
|
|
for (; i >= 0; i--) {
|
|
iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
|
|
remainder = iTempDividend % divisor;
|
|
p[i] = iTempDividend / divisor;
|
|
}
|
|
|
|
return remainder;
|
|
}
|
|
}
|
|
|
|
/* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
|
|
static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n)
|
|
{
|
|
for (; n > 0; n--) if (*p++ != 0) return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
/* multiply two DECIMALS, without changing either one, and place result in third
|
|
parameter. Result is normalized when scale is > 0. Attempts to remove significant
|
|
digits when scale > 0 in order to fit an overflowing result. Final overflow
|
|
flag is returned.
|
|
*/
|
|
static int VARIANT_DI_mul(const VARIANT_DI * a, const VARIANT_DI * b, VARIANT_DI * result)
|
|
{
|
|
BOOL r_overflow = FALSE;
|
|
DWORD running[6];
|
|
signed int mulstart;
|
|
|
|
VARIANT_DI_clear(result);
|
|
result->sign = (a->sign ^ b->sign) ? 1 : 0;
|
|
|
|
/* Multiply 128-bit operands into a (max) 256-bit result. The scale
|
|
of the result is formed by adding the scales of the operands.
|
|
*/
|
|
result->scale = a->scale + b->scale;
|
|
memset(running, 0, sizeof(running));
|
|
|
|
/* count number of leading zero-bytes in operand A */
|
|
for (mulstart = ARRAY_SIZE(a->bitsnum) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
|
|
if (mulstart < 0) {
|
|
/* result is 0, because operand A is 0 */
|
|
result->scale = 0;
|
|
result->sign = 0;
|
|
} else {
|
|
unsigned char remainder = 0;
|
|
int iA;
|
|
|
|
/* perform actual multiplication */
|
|
for (iA = 0; iA <= mulstart; iA++) {
|
|
ULONG iOverflowMul;
|
|
int iB;
|
|
|
|
for (iOverflowMul = 0, iB = 0; iB < ARRAY_SIZE(b->bitsnum); iB++) {
|
|
ULONG iRV;
|
|
int iR;
|
|
|
|
iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
|
|
iR = iA + iB;
|
|
do {
|
|
running[iR] = VARIANT_Add(running[iR], 0, &iRV);
|
|
iR++;
|
|
} while (iRV);
|
|
}
|
|
}
|
|
|
|
/* Too bad - native oleaut does not do this, so we should not either */
|
|
#if 0
|
|
/* While the result is divisible by 10, and the scale > 0, divide by 10.
|
|
This operation should not lose significant digits, and gives an
|
|
opportunity to reduce the possibility of overflows in future
|
|
operations issued by the application.
|
|
*/
|
|
while (result->scale > 0) {
|
|
memcpy(quotient, running, sizeof(quotient));
|
|
remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
|
|
if (remainder > 0) break;
|
|
memcpy(running, quotient, sizeof(quotient));
|
|
result->scale--;
|
|
}
|
|
#endif
|
|
/* While the 256-bit result overflows, and the scale > 0, divide by 10.
|
|
This operation *will* lose significant digits of the result because
|
|
all the factors of 10 were consumed by the previous operation.
|
|
*/
|
|
while (result->scale > 0 && !VARIANT_int_iszero(running + ARRAY_SIZE(result->bitsnum),
|
|
ARRAY_SIZE(running) - ARRAY_SIZE(result->bitsnum))) {
|
|
|
|
remainder = VARIANT_int_divbychar(running, ARRAY_SIZE(running), 10);
|
|
if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
|
|
result->scale--;
|
|
}
|
|
|
|
/* round up the result - native oleaut32 does this */
|
|
if (remainder >= 5) {
|
|
unsigned int i;
|
|
for (remainder = 1, i = 0; i < ARRAY_SIZE(running) && remainder; i++) {
|
|
ULONGLONG digit = running[i] + 1;
|
|
remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
|
|
running[i] = digit & 0xFFFFFFFF;
|
|
}
|
|
}
|
|
|
|
/* Signal overflow if scale == 0 and 256-bit result still overflows,
|
|
and copy result bits into result structure
|
|
*/
|
|
r_overflow = !VARIANT_int_iszero(running + ARRAY_SIZE(result->bitsnum),
|
|
ARRAY_SIZE(running) - ARRAY_SIZE(result->bitsnum));
|
|
memcpy(result->bitsnum, running, sizeof(result->bitsnum));
|
|
}
|
|
return r_overflow;
|
|
}
|
|
|
|
/* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
|
|
hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
|
|
success, FALSE if insufficient space in output buffer.
|
|
*/
|
|
static BOOL VARIANT_DI_tostringW(const VARIANT_DI * a, WCHAR * s, unsigned int n)
|
|
{
|
|
BOOL overflow = FALSE;
|
|
DWORD quotient[3];
|
|
unsigned char remainder;
|
|
unsigned int i;
|
|
|
|
/* place negative sign */
|
|
if (!VARIANT_int_iszero(a->bitsnum, ARRAY_SIZE(a->bitsnum)) && a->sign) {
|
|
if (n > 0) {
|
|
*s++ = '-';
|
|
n--;
|
|
}
|
|
else overflow = TRUE;
|
|
}
|
|
|
|
/* prepare initial 0 */
|
|
if (!overflow) {
|
|
if (n >= 2) {
|
|
s[0] = '0';
|
|
s[1] = '\0';
|
|
} else overflow = TRUE;
|
|
}
|
|
|
|
i = 0;
|
|
memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
|
|
while (!overflow && !VARIANT_int_iszero(quotient, ARRAY_SIZE(quotient))) {
|
|
remainder = VARIANT_int_divbychar(quotient, ARRAY_SIZE(quotient), 10);
|
|
if (i + 2 > n) {
|
|
overflow = TRUE;
|
|
} else {
|
|
s[i++] = '0' + remainder;
|
|
s[i] = '\0';
|
|
}
|
|
}
|
|
|
|
if (!overflow && !VARIANT_int_iszero(a->bitsnum, ARRAY_SIZE(a->bitsnum))) {
|
|
|
|
/* reverse order of digits */
|
|
WCHAR * x = s; WCHAR * y = s + i - 1;
|
|
while (x < y) {
|
|
*x ^= *y;
|
|
*y ^= *x;
|
|
*x++ ^= *y--;
|
|
}
|
|
|
|
/* check for decimal point. "i" now has string length */
|
|
if (i <= a->scale) {
|
|
unsigned int numzeroes = a->scale + 1 - i;
|
|
if (i + 1 + numzeroes >= n) {
|
|
overflow = TRUE;
|
|
} else {
|
|
memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
|
|
i += numzeroes;
|
|
while (numzeroes > 0) {
|
|
s[--numzeroes] = '0';
|
|
}
|
|
}
|
|
}
|
|
|
|
/* place decimal point */
|
|
if (a->scale > 0) {
|
|
unsigned int periodpos = i - a->scale;
|
|
if (i + 2 >= n) {
|
|
overflow = TRUE;
|
|
} else {
|
|
memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
|
|
s[periodpos] = '.'; i++;
|
|
|
|
/* remove extra zeros at the end, if any */
|
|
while (s[i - 1] == '0') s[--i] = '\0';
|
|
if (s[i - 1] == '.') s[--i] = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
return !overflow;
|
|
}
|
|
|
|
/* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
|
|
static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
|
|
{
|
|
DWORD shifted;
|
|
unsigned int i;
|
|
|
|
/* shift whole DWORDs to the left */
|
|
while (shift >= 32)
|
|
{
|
|
memmove(p + 1, p, (n - 1) * sizeof(DWORD));
|
|
*p = 0; shift -= 32;
|
|
}
|
|
|
|
/* shift remainder (1..31 bits) */
|
|
shifted = 0;
|
|
if (shift > 0) for (i = 0; i < n; i++)
|
|
{
|
|
DWORD b;
|
|
b = p[i] >> (32 - shift);
|
|
p[i] = (p[i] << shift) | shifted;
|
|
shifted = b;
|
|
}
|
|
}
|
|
|
|
/* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
|
|
Value at v is incremented by the value at p. Any size is supported, provided
|
|
that v is not shorter than p. Any unapplied carry is returned as a result.
|
|
*/
|
|
static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, const DWORD * p,
|
|
unsigned int np)
|
|
{
|
|
unsigned char carry = 0;
|
|
|
|
if (nv >= np) {
|
|
ULONGLONG sum;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < np; i++) {
|
|
sum = (ULONGLONG)v[i]
|
|
+ (ULONGLONG)p[i]
|
|
+ (ULONGLONG)carry;
|
|
v[i] = sum & 0xffffffff;
|
|
carry = sum >> 32;
|
|
}
|
|
for (; i < nv && carry; i++) {
|
|
sum = (ULONGLONG)v[i]
|
|
+ (ULONGLONG)carry;
|
|
v[i] = sum & 0xffffffff;
|
|
carry = sum >> 32;
|
|
}
|
|
}
|
|
return carry;
|
|
}
|
|
|
|
/* perform integral division with operand p as dividend. Parameter n indicates
|
|
number of available DWORDs in divisor p, but available space in p must be
|
|
actually at least 2 * n DWORDs, because the remainder of the integral
|
|
division is built in the next n DWORDs past the start of the quotient. This
|
|
routine replaces the dividend in p with the quotient, and appends n
|
|
additional DWORDs for the remainder.
|
|
|
|
Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
|
|
C/C++ :-) where the "longhand binary division" algorithm was exposed for the
|
|
source code to the VLI (Very Large Integer) division operator. This algorithm
|
|
was then heavily modified by me (Alex Villacis Lasso) in order to handle
|
|
variably-scaled integers such as the MS DECIMAL representation.
|
|
*/
|
|
static void VARIANT_int_div(DWORD * p, unsigned int n, const DWORD * divisor,
|
|
unsigned int dn)
|
|
{
|
|
unsigned int i;
|
|
DWORD tempsub[8];
|
|
DWORD * negdivisor = tempsub + n;
|
|
|
|
/* build 2s-complement of divisor */
|
|
for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
|
|
p[n] = 1;
|
|
VARIANT_int_add(negdivisor, n, p + n, 1);
|
|
memset(p + n, 0, n * sizeof(DWORD));
|
|
|
|
/* skip all leading zero DWORDs in quotient */
|
|
for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
|
|
/* i is now number of DWORDs left to process */
|
|
for (i <<= 5; i < (n << 5); i++) {
|
|
VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
|
|
|
|
/* trial subtraction */
|
|
memcpy(tempsub, p + n, n * sizeof(DWORD));
|
|
VARIANT_int_add(tempsub, n, negdivisor, n);
|
|
|
|
/* check whether result of subtraction was negative */
|
|
if ((tempsub[n - 1] & 0x80000000) == 0) {
|
|
memcpy(p + n, tempsub, n * sizeof(DWORD));
|
|
p[0] |= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* perform integral multiplication by a byte operand. Used for scaling by 10 */
|
|
static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
|
|
{
|
|
unsigned int i;
|
|
ULONG iOverflowMul;
|
|
|
|
for (iOverflowMul = 0, i = 0; i < n; i++)
|
|
p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
|
|
return (unsigned char)iOverflowMul;
|
|
}
|
|
|
|
/* increment value in A by the value indicated in B, with scale adjusting.
|
|
Modifies parameters by adjusting scales. Returns 0 if addition was
|
|
successful, nonzero if a parameter underflowed before it could be
|
|
successfully used in the addition.
|
|
*/
|
|
static int VARIANT_int_addlossy(
|
|
DWORD * a, int * ascale, unsigned int an,
|
|
DWORD * b, int * bscale, unsigned int bn)
|
|
{
|
|
int underflow = 0;
|
|
|
|
if (VARIANT_int_iszero(a, an)) {
|
|
/* if A is zero, copy B into A, after removing digits */
|
|
while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
|
|
VARIANT_int_divbychar(b, bn, 10);
|
|
(*bscale)--;
|
|
}
|
|
memcpy(a, b, an * sizeof(DWORD));
|
|
*ascale = *bscale;
|
|
} else if (!VARIANT_int_iszero(b, bn)) {
|
|
unsigned int tn = an + 1;
|
|
DWORD t[5];
|
|
|
|
if (bn + 1 > tn) tn = bn + 1;
|
|
if (*ascale != *bscale) {
|
|
/* first (optimistic) try - try to scale down the one with the bigger
|
|
scale, while this number is divisible by 10 */
|
|
DWORD * digitchosen;
|
|
unsigned int nchosen;
|
|
int * scalechosen;
|
|
int targetscale;
|
|
|
|
if (*ascale < *bscale) {
|
|
targetscale = *ascale;
|
|
scalechosen = bscale;
|
|
digitchosen = b;
|
|
nchosen = bn;
|
|
} else {
|
|
targetscale = *bscale;
|
|
scalechosen = ascale;
|
|
digitchosen = a;
|
|
nchosen = an;
|
|
}
|
|
memset(t, 0, tn * sizeof(DWORD));
|
|
memcpy(t, digitchosen, nchosen * sizeof(DWORD));
|
|
|
|
/* divide by 10 until target scale is reached */
|
|
while (*scalechosen > targetscale) {
|
|
unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
|
|
if (!remainder) {
|
|
(*scalechosen)--;
|
|
memcpy(digitchosen, t, nchosen * sizeof(DWORD));
|
|
} else break;
|
|
}
|
|
}
|
|
|
|
if (*ascale != *bscale) {
|
|
DWORD * digitchosen;
|
|
unsigned int nchosen;
|
|
int * scalechosen;
|
|
int targetscale;
|
|
|
|
/* try to scale up the one with the smaller scale */
|
|
if (*ascale > *bscale) {
|
|
targetscale = *ascale;
|
|
scalechosen = bscale;
|
|
digitchosen = b;
|
|
nchosen = bn;
|
|
} else {
|
|
targetscale = *bscale;
|
|
scalechosen = ascale;
|
|
digitchosen = a;
|
|
nchosen = an;
|
|
}
|
|
memset(t, 0, tn * sizeof(DWORD));
|
|
memcpy(t, digitchosen, nchosen * sizeof(DWORD));
|
|
|
|
/* multiply by 10 until target scale is reached, or
|
|
significant bytes overflow the number
|
|
*/
|
|
while (*scalechosen < targetscale && t[nchosen] == 0) {
|
|
VARIANT_int_mulbychar(t, tn, 10);
|
|
if (t[nchosen] == 0) {
|
|
/* still does not overflow */
|
|
(*scalechosen)++;
|
|
memcpy(digitchosen, t, nchosen * sizeof(DWORD));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*ascale != *bscale) {
|
|
/* still different? try to scale down the one with the bigger scale
|
|
(this *will* lose significant digits) */
|
|
DWORD * digitchosen;
|
|
unsigned int nchosen;
|
|
int * scalechosen;
|
|
int targetscale;
|
|
|
|
if (*ascale < *bscale) {
|
|
targetscale = *ascale;
|
|
scalechosen = bscale;
|
|
digitchosen = b;
|
|
nchosen = bn;
|
|
} else {
|
|
targetscale = *bscale;
|
|
scalechosen = ascale;
|
|
digitchosen = a;
|
|
nchosen = an;
|
|
}
|
|
memset(t, 0, tn * sizeof(DWORD));
|
|
memcpy(t, digitchosen, nchosen * sizeof(DWORD));
|
|
|
|
/* divide by 10 until target scale is reached */
|
|
while (*scalechosen > targetscale) {
|
|
VARIANT_int_divbychar(t, tn, 10);
|
|
(*scalechosen)--;
|
|
memcpy(digitchosen, t, nchosen * sizeof(DWORD));
|
|
}
|
|
}
|
|
|
|
/* check whether any of the operands still has significant digits
|
|
(underflow case 1)
|
|
*/
|
|
if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
|
|
underflow = 1;
|
|
} else {
|
|
/* at this step, both numbers have the same scale and can be added
|
|
as integers. However, the result might not fit in A, so further
|
|
scaling down might be necessary.
|
|
*/
|
|
while (!underflow) {
|
|
memset(t, 0, tn * sizeof(DWORD));
|
|
memcpy(t, a, an * sizeof(DWORD));
|
|
|
|
VARIANT_int_add(t, tn, b, bn);
|
|
if (VARIANT_int_iszero(t + an, tn - an)) {
|
|
/* addition was successful */
|
|
memcpy(a, t, an * sizeof(DWORD));
|
|
break;
|
|
} else {
|
|
/* addition overflowed - remove significant digits
|
|
from both operands and try again */
|
|
VARIANT_int_divbychar(a, an, 10); (*ascale)--;
|
|
VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
|
|
/* check whether any operand keeps significant digits after
|
|
scaledown (underflow case 2)
|
|
*/
|
|
underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return underflow;
|
|
}
|
|
|
|
/* perform complete DECIMAL division in the internal representation. Returns
|
|
0 if the division was completed (even if quotient is set to 0), or nonzero
|
|
in case of quotient overflow.
|
|
*/
|
|
static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * divisor,
|
|
VARIANT_DI * quotient, BOOL round_remainder)
|
|
{
|
|
HRESULT r_overflow = S_OK;
|
|
|
|
if (VARIANT_int_iszero(divisor->bitsnum, ARRAY_SIZE(divisor->bitsnum))) {
|
|
/* division by 0 */
|
|
r_overflow = DISP_E_DIVBYZERO;
|
|
} else if (VARIANT_int_iszero(dividend->bitsnum, ARRAY_SIZE(dividend->bitsnum))) {
|
|
VARIANT_DI_clear(quotient);
|
|
} else {
|
|
int quotientscale, remainderscale, tempquotientscale;
|
|
DWORD remainderplusquotient[8];
|
|
int underflow;
|
|
|
|
quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
|
|
tempquotientscale = quotientscale;
|
|
VARIANT_DI_clear(quotient);
|
|
quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
|
|
|
|
/* The following strategy is used for division
|
|
1) if there was a nonzero remainder from previous iteration, use it as
|
|
dividend for this iteration, else (for first iteration) use intended
|
|
dividend
|
|
2) perform integer division in temporary buffer, develop quotient in
|
|
low-order part, remainder in high-order part
|
|
3) add quotient from step 2 to final result, with possible loss of
|
|
significant digits
|
|
4) multiply integer part of remainder by 10, while incrementing the
|
|
scale of the remainder. This operation preserves the intended value
|
|
of the remainder.
|
|
5) loop to step 1 until one of the following is true:
|
|
a) remainder is zero (exact division achieved)
|
|
b) addition in step 3 fails to modify bits in quotient (remainder underflow)
|
|
*/
|
|
memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
|
|
memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
|
|
do {
|
|
VARIANT_int_div(remainderplusquotient, 4, divisor->bitsnum, ARRAY_SIZE(divisor->bitsnum));
|
|
underflow = VARIANT_int_addlossy( quotient->bitsnum, "ientscale,
|
|
ARRAY_SIZE(quotient->bitsnum), remainderplusquotient, &tempquotientscale, 4);
|
|
if (round_remainder) {
|
|
if(remainderplusquotient[4] >= 5){
|
|
unsigned int i;
|
|
unsigned char remainder = 1;
|
|
for (i = 0; i < ARRAY_SIZE(quotient->bitsnum) && remainder; i++) {
|
|
ULONGLONG digit = quotient->bitsnum[i] + 1;
|
|
remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
|
|
quotient->bitsnum[i] = digit & 0xFFFFFFFF;
|
|
}
|
|
}
|
|
memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
|
|
} else {
|
|
VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
|
|
memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
|
|
}
|
|
tempquotientscale = ++remainderscale;
|
|
} while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
|
|
|
|
/* quotient scale might now be negative (extremely big number). If, so, try
|
|
to multiply quotient by 10 (without overflowing), while adjusting the scale,
|
|
until scale is 0. If this cannot be done, it is a real overflow.
|
|
*/
|
|
while (r_overflow == S_OK && quotientscale < 0) {
|
|
memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
|
|
memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
|
|
VARIANT_int_mulbychar(remainderplusquotient, ARRAY_SIZE(remainderplusquotient), 10);
|
|
if (VARIANT_int_iszero(remainderplusquotient + ARRAY_SIZE(quotient->bitsnum),
|
|
ARRAY_SIZE(remainderplusquotient) - ARRAY_SIZE(quotient->bitsnum))) {
|
|
quotientscale++;
|
|
memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
|
|
} else r_overflow = DISP_E_OVERFLOW;
|
|
}
|
|
if (r_overflow == S_OK) {
|
|
if (quotientscale <= 255) quotient->scale = quotientscale;
|
|
else VARIANT_DI_clear(quotient);
|
|
}
|
|
}
|
|
return r_overflow;
|
|
}
|
|
|
|
/* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
|
|
with an undefined scale, which will be assigned to (if possible). It also
|
|
receives an exponent of 2. This procedure will then manipulate the mantissa
|
|
and calculate a corresponding scale, so that the exponent2 value is assimilated
|
|
into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
|
|
successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
|
|
a DECIMAL. */
|
|
static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, BOOL isDouble)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
int exponent5, exponent10;
|
|
|
|
/* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
|
|
thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
|
|
exponent10 might be used to set the VARIANT_DI scale directly. However,
|
|
the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
|
|
exponent5 = -exponent2;
|
|
exponent10 = exponent2;
|
|
|
|
/* Handle exponent5 > 0 */
|
|
while (exponent5 > 0) {
|
|
char bPrevCarryBit;
|
|
char bCurrCarryBit;
|
|
|
|
/* In order to multiply the value represented by the VARIANT_DI by 5, it
|
|
is best to multiply by 10/2. Therefore, exponent10 is incremented, and
|
|
somehow the mantissa should be divided by 2. */
|
|
if ((val->bitsnum[0] & 1) == 0) {
|
|
/* The mantissa is divisible by 2. Therefore the division can be done
|
|
without losing significant digits. */
|
|
exponent10++; exponent5--;
|
|
|
|
/* Shift right */
|
|
bPrevCarryBit = val->bitsnum[2] & 1;
|
|
val->bitsnum[2] >>= 1;
|
|
bCurrCarryBit = val->bitsnum[1] & 1;
|
|
val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
|
|
val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
|
|
} else {
|
|
/* The mantissa is NOT divisible by 2. Therefore the mantissa should
|
|
be multiplied by 5, unless the multiplication overflows. */
|
|
DWORD temp_bitsnum[3];
|
|
|
|
exponent5--;
|
|
|
|
memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
|
|
if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) {
|
|
/* Multiplication succeeded without overflow, so copy result back
|
|
into VARIANT_DI */
|
|
memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
|
|
|
|
/* Mask out 3 extraneous bits introduced by the multiply */
|
|
} else {
|
|
/* Multiplication by 5 overflows. The mantissa should be divided
|
|
by 2, and therefore will lose significant digits. */
|
|
exponent10++;
|
|
|
|
/* Shift right */
|
|
bPrevCarryBit = val->bitsnum[2] & 1;
|
|
val->bitsnum[2] >>= 1;
|
|
bCurrCarryBit = val->bitsnum[1] & 1;
|
|
val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
|
|
val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Handle exponent5 < 0 */
|
|
while (exponent5 < 0) {
|
|
/* In order to divide the value represented by the VARIANT_DI by 5, it
|
|
is best to multiply by 2/10. Therefore, exponent10 is decremented,
|
|
and the mantissa should be multiplied by 2 */
|
|
if ((val->bitsnum[2] & 0x80000000) == 0) {
|
|
/* The mantissa can withstand a shift-left without overflowing */
|
|
exponent10--; exponent5++;
|
|
VARIANT_int_shiftleft(val->bitsnum, 3, 1);
|
|
} else {
|
|
/* The mantissa would overflow if shifted. Therefore it should be
|
|
directly divided by 5. This will lose significant digits, unless
|
|
by chance the mantissa happens to be divisible by 5 */
|
|
exponent5++;
|
|
VARIANT_int_divbychar(val->bitsnum, 3, 5);
|
|
}
|
|
}
|
|
|
|
/* At this point, the mantissa has assimilated the exponent5, but the
|
|
exponent10 might not be suitable for assignment. The exponent10 must be
|
|
in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
|
|
down appropriately. */
|
|
while (hres == S_OK && exponent10 > 0) {
|
|
/* In order to bring exponent10 down to 0, the mantissa should be
|
|
multiplied by 10 to compensate. If the exponent10 is too big, this
|
|
will cause the mantissa to overflow. */
|
|
if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) {
|
|
exponent10--;
|
|
} else {
|
|
hres = DISP_E_OVERFLOW;
|
|
}
|
|
}
|
|
while (exponent10 < -DEC_MAX_SCALE) {
|
|
int rem10;
|
|
/* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
|
|
be divided by 10 to compensate. If the exponent10 is too small, this
|
|
will cause the mantissa to underflow and become 0 */
|
|
rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
|
|
exponent10++;
|
|
if (VARIANT_int_iszero(val->bitsnum, 3)) {
|
|
/* Underflow, unable to keep dividing */
|
|
exponent10 = 0;
|
|
} else if (rem10 >= 5) {
|
|
DWORD x = 1;
|
|
VARIANT_int_add(val->bitsnum, 3, &x, 1);
|
|
}
|
|
}
|
|
/* This step is required in order to remove excess bits of precision from the
|
|
end of the bit representation, down to the precision guaranteed by the
|
|
floating point number. */
|
|
if (isDouble) {
|
|
while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[1] & 0xFFE00000) != 0)) {
|
|
int rem10;
|
|
|
|
rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
|
|
exponent10++;
|
|
if (rem10 >= 5) {
|
|
DWORD x = 1;
|
|
VARIANT_int_add(val->bitsnum, 3, &x, 1);
|
|
}
|
|
}
|
|
} else {
|
|
while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 ||
|
|
(val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) {
|
|
int rem10;
|
|
|
|
rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
|
|
exponent10++;
|
|
if (rem10 >= 5) {
|
|
DWORD x = 1;
|
|
VARIANT_int_add(val->bitsnum, 3, &x, 1);
|
|
}
|
|
}
|
|
}
|
|
/* Remove multiples of 10 from the representation */
|
|
while (exponent10 < 0) {
|
|
DWORD temp_bitsnum[3];
|
|
|
|
memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
|
|
if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) {
|
|
exponent10++;
|
|
memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
|
|
} else break;
|
|
}
|
|
|
|
/* Scale assignment */
|
|
if (hres == S_OK) val->scale = -exponent10;
|
|
|
|
return hres;
|
|
}
|
|
|
|
typedef union
|
|
{
|
|
struct
|
|
{
|
|
unsigned int m : 23;
|
|
unsigned int exp_bias : 8;
|
|
unsigned int sign : 1;
|
|
} i;
|
|
float f;
|
|
} R4_FIELDS;
|
|
|
|
/* Convert a 32-bit floating point number into a DECIMAL, without using an
|
|
intermediate string step. */
|
|
static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
R4_FIELDS fx;
|
|
|
|
fx.f = source;
|
|
|
|
/* Detect special cases */
|
|
if (fx.i.m == 0 && fx.i.exp_bias == 0) {
|
|
/* Floating-point zero */
|
|
VARIANT_DI_clear(dest);
|
|
} else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) {
|
|
/* Floating-point infinity */
|
|
hres = DISP_E_OVERFLOW;
|
|
} else if (fx.i.exp_bias == 0xFF) {
|
|
/* Floating-point NaN */
|
|
hres = DISP_E_BADVARTYPE;
|
|
} else {
|
|
int exponent2;
|
|
VARIANT_DI_clear(dest);
|
|
|
|
exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */
|
|
dest->sign = fx.i.sign; /* Sign is simply copied */
|
|
|
|
/* Copy significant bits to VARIANT_DI mantissa */
|
|
dest->bitsnum[0] = fx.i.m;
|
|
dest->bitsnum[0] &= 0x007FFFFF;
|
|
if (fx.i.exp_bias == 0) {
|
|
/* Denormalized number - correct exponent */
|
|
exponent2++;
|
|
} else {
|
|
/* Add hidden bit to mantissa */
|
|
dest->bitsnum[0] |= 0x00800000;
|
|
}
|
|
|
|
/* The act of copying a FP mantissa as integer bits is equivalent to
|
|
shifting left the mantissa 23 bits. The exponent2 is reduced to
|
|
compensate. */
|
|
exponent2 -= 23;
|
|
|
|
hres = VARIANT_DI_normalize(dest, exponent2, FALSE);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
typedef union
|
|
{
|
|
struct
|
|
{
|
|
unsigned int m_lo : 32; /* 52 bits of precision */
|
|
unsigned int m_hi : 20;
|
|
unsigned int exp_bias : 11; /* bias == 1023 */
|
|
unsigned int sign : 1;
|
|
} i;
|
|
double d;
|
|
} R8_FIELDS;
|
|
|
|
/* Convert a 64-bit floating point number into a DECIMAL, without using an
|
|
intermediate string step. */
|
|
static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
R8_FIELDS fx;
|
|
|
|
fx.d = source;
|
|
|
|
/* Detect special cases */
|
|
if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) {
|
|
/* Floating-point zero */
|
|
VARIANT_DI_clear(dest);
|
|
} else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) {
|
|
/* Floating-point infinity */
|
|
hres = DISP_E_OVERFLOW;
|
|
} else if (fx.i.exp_bias == 0x7FF) {
|
|
/* Floating-point NaN */
|
|
hres = DISP_E_BADVARTYPE;
|
|
} else {
|
|
int exponent2;
|
|
VARIANT_DI_clear(dest);
|
|
|
|
exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */
|
|
dest->sign = fx.i.sign; /* Sign is simply copied */
|
|
|
|
/* Copy significant bits to VARIANT_DI mantissa */
|
|
dest->bitsnum[0] = fx.i.m_lo;
|
|
dest->bitsnum[1] = fx.i.m_hi;
|
|
dest->bitsnum[1] &= 0x000FFFFF;
|
|
if (fx.i.exp_bias == 0) {
|
|
/* Denormalized number - correct exponent */
|
|
exponent2++;
|
|
} else {
|
|
/* Add hidden bit to mantissa */
|
|
dest->bitsnum[1] |= 0x00100000;
|
|
}
|
|
|
|
/* The act of copying a FP mantissa as integer bits is equivalent to
|
|
shifting left the mantissa 52 bits. The exponent2 is reduced to
|
|
compensate. */
|
|
exponent2 -= 52;
|
|
|
|
hres = VARIANT_DI_normalize(dest, exponent2, TRUE);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
static HRESULT VARIANT_do_division(const DECIMAL *pDecLeft, const DECIMAL *pDecRight, DECIMAL *pDecOut,
|
|
BOOL round)
|
|
{
|
|
HRESULT hRet = S_OK;
|
|
VARIANT_DI di_left, di_right, di_result;
|
|
HRESULT divresult;
|
|
|
|
VARIANT_DIFromDec(pDecLeft, &di_left);
|
|
VARIANT_DIFromDec(pDecRight, &di_right);
|
|
divresult = VARIANT_DI_div(&di_left, &di_right, &di_result, round);
|
|
if (divresult != S_OK)
|
|
{
|
|
/* division actually overflowed */
|
|
hRet = divresult;
|
|
}
|
|
else
|
|
{
|
|
hRet = S_OK;
|
|
|
|
if (di_result.scale > DEC_MAX_SCALE)
|
|
{
|
|
unsigned char remainder = 0;
|
|
|
|
/* division underflowed. In order to comply with the MSDN
|
|
specifications for DECIMAL ranges, some significant digits
|
|
must be removed
|
|
*/
|
|
WARN("result scale is %u, scaling (with loss of significant digits)...\n",
|
|
di_result.scale);
|
|
while (di_result.scale > DEC_MAX_SCALE &&
|
|
!VARIANT_int_iszero(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum)))
|
|
{
|
|
remainder = VARIANT_int_divbychar(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum), 10);
|
|
di_result.scale--;
|
|
}
|
|
if (di_result.scale > DEC_MAX_SCALE)
|
|
{
|
|
WARN("result underflowed, setting to 0\n");
|
|
di_result.scale = 0;
|
|
di_result.sign = 0;
|
|
}
|
|
else if (remainder >= 5) /* round up result - native oleaut32 does this */
|
|
{
|
|
unsigned int i;
|
|
for (remainder = 1, i = 0; i < ARRAY_SIZE(di_result.bitsnum) && remainder; i++) {
|
|
ULONGLONG digit = di_result.bitsnum[i] + 1;
|
|
remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
|
|
di_result.bitsnum[i] = digit & 0xFFFFFFFF;
|
|
}
|
|
}
|
|
}
|
|
VARIANT_DecFromDI(&di_result, pDecOut);
|
|
}
|
|
return hRet;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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)
|
|
{
|
|
if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
|
|
|
|
return VARIANT_do_division(pDecLeft, pDecRight, pDecOut, FALSE);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarDecMul (OLEAUT32.179)
|
|
*
|
|
* Multiply one DECIMAL by another.
|
|
*
|
|
* PARAMS
|
|
* pDecLeft [I] Source
|
|
* pDecRight [I] Value to multiply by
|
|
* pDecOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
|
|
{
|
|
HRESULT hRet = S_OK;
|
|
VARIANT_DI di_left, di_right, di_result;
|
|
int mulresult;
|
|
|
|
VARIANT_DIFromDec(pDecLeft, &di_left);
|
|
VARIANT_DIFromDec(pDecRight, &di_right);
|
|
mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
|
|
if (mulresult)
|
|
{
|
|
/* multiplication actually overflowed */
|
|
hRet = DISP_E_OVERFLOW;
|
|
}
|
|
else
|
|
{
|
|
if (di_result.scale > DEC_MAX_SCALE)
|
|
{
|
|
/* multiplication underflowed. In order to comply with the MSDN
|
|
specifications for DECIMAL ranges, some significant digits
|
|
must be removed
|
|
*/
|
|
WARN("result scale is %u, scaling (with loss of significant digits)...\n",
|
|
di_result.scale);
|
|
while (di_result.scale > DEC_MAX_SCALE &&
|
|
!VARIANT_int_iszero(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum)))
|
|
{
|
|
VARIANT_int_divbychar(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum), 10);
|
|
di_result.scale--;
|
|
}
|
|
if (di_result.scale > DEC_MAX_SCALE)
|
|
{
|
|
WARN("result underflowed, setting to 0\n");
|
|
di_result.scale = 0;
|
|
di_result.sign = 0;
|
|
}
|
|
}
|
|
VARIANT_DecFromDI(&di_result, pDecOut);
|
|
}
|
|
return hRet;
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarDecSub (OLEAUT32.181)
|
|
*
|
|
* Subtract one DECIMAL from another.
|
|
*
|
|
* PARAMS
|
|
* pDecLeft [I] Source
|
|
* pDecRight [I] DECIMAL to subtract from pDecLeft
|
|
* pDecOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*/
|
|
HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
|
|
{
|
|
DECIMAL decRight;
|
|
|
|
/* Implement as addition of the negative */
|
|
VarDecNeg(pDecRight, &decRight);
|
|
return VarDecAdd(pDecLeft, &decRight, pDecOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarDecAbs (OLEAUT32.182)
|
|
*
|
|
* Convert a DECIMAL into its absolute value.
|
|
*
|
|
* PARAMS
|
|
* pDecIn [I] Source
|
|
* pDecOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK. This function does not fail.
|
|
*/
|
|
HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
|
|
{
|
|
*pDecOut = *pDecIn;
|
|
DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarDecFix (OLEAUT32.187)
|
|
*
|
|
* Return the integer portion of a DECIMAL.
|
|
*
|
|
* PARAMS
|
|
* pDecIn [I] Source
|
|
* pDecOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
*
|
|
* NOTES
|
|
* - The difference between this function and VarDecInt() is that VarDecInt() rounds
|
|
* negative numbers away from 0, while this function rounds them towards zero.
|
|
*/
|
|
HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
|
|
{
|
|
double dbl;
|
|
HRESULT hr;
|
|
|
|
if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
|
|
return E_INVALIDARG;
|
|
|
|
if (!DEC_SCALE(pDecIn))
|
|
{
|
|
*pDecOut = *pDecIn; /* Already an integer */
|
|
return S_OK;
|
|
}
|
|
|
|
hr = VarR8FromDec(pDecIn, &dbl);
|
|
if (SUCCEEDED(hr)) {
|
|
LONGLONG rounded = dbl;
|
|
|
|
hr = VarDecFromI8(rounded, pDecOut);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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)
|
|
{
|
|
double dbl;
|
|
HRESULT hr;
|
|
|
|
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 */
|
|
|
|
hr = VarR8FromDec(pDecIn, &dbl);
|
|
if (SUCCEEDED(hr)) {
|
|
LONGLONG rounded = dbl >= 0.0 ? dbl + 0.5 : dbl - 0.5;
|
|
|
|
hr = VarDecFromI8(rounded, pDecOut);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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)
|
|
{
|
|
DECIMAL divisor, tmp;
|
|
HRESULT hr;
|
|
unsigned int i;
|
|
|
|
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;
|
|
}
|
|
|
|
/* truncate significant digits and rescale */
|
|
memset(&divisor, 0, sizeof(divisor));
|
|
DEC_LO64(&divisor) = 1;
|
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
DEC_LO64(&tmp) = 10;
|
|
for (i = 0; i < DEC_SCALE(pDecIn) - cDecimals; ++i)
|
|
{
|
|
hr = VarDecMul(&divisor, &tmp, &divisor);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
|
|
hr = VARIANT_do_division(pDecIn, &divisor, pDecOut, TRUE);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
DEC_SCALE(pDecOut) = cDecimals;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* 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;
|
|
|
|
if (!pDecLeft || !pDecRight)
|
|
return VARCMP_NULL;
|
|
|
|
if ((!(DEC_SIGN(pDecLeft) & DECIMAL_NEG)) && (DEC_SIGN(pDecRight) & DECIMAL_NEG) &&
|
|
(DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
|
|
return VARCMP_GT;
|
|
else if ((DEC_SIGN(pDecLeft) & DECIMAL_NEG) && (!(DEC_SIGN(pDecRight) & DECIMAL_NEG)) &&
|
|
(DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
|
|
return VARCMP_LT;
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/************************************************************************
|
|
* VARIANT_GetLocalisedText [internal]
|
|
*
|
|
* Get a localized string from the resources
|
|
*
|
|
*/
|
|
static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
|
|
{
|
|
HRSRC hrsrc;
|
|
|
|
hrsrc = FindResourceExW( hProxyDll, (LPWSTR)RT_STRING,
|
|
MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
|
|
if (hrsrc)
|
|
{
|
|
HGLOBAL hmem = LoadResource( hProxyDll, 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(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
|
|
{
|
|
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 (!wcsicmp(strIn, szBuff))
|
|
{
|
|
*pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
|
|
return hRes;
|
|
}
|
|
VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
|
|
if (!wcsicmp(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 (!wcscmp(strIn, L"#FALSE#"))
|
|
*pBoolOut = VARIANT_FALSE;
|
|
else if (!wcscmp(strIn, L"#TRUE#"))
|
|
*pBoolOut = VARIANT_TRUE;
|
|
else
|
|
{
|
|
double d;
|
|
|
|
/* If this string is a number, convert it as one */
|
|
hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
|
|
if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
|
|
}
|
|
return hRes;
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarBoolFromDisp (OLEAUT32.126)
|
|
*
|
|
* Convert a VT_DISPATCH to a VT_BOOL.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* pBoolOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarBoolFromI1 (OLEAUT32.233)
|
|
*
|
|
* Convert a VT_I1 to a VT_BOOL.
|
|
*
|
|
* PARAMS
|
|
* cIn [I] Source
|
|
* pBoolOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
|
|
{
|
|
*pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarBoolFromUI2 (OLEAUT32.234)
|
|
*
|
|
* Convert a VT_UI2 to a VT_BOOL.
|
|
*
|
|
* PARAMS
|
|
* usIn [I] Source
|
|
* pBoolOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
|
|
{
|
|
*pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarBoolFromUI4 (OLEAUT32.235)
|
|
*
|
|
* Convert a VT_UI4 to a VT_BOOL.
|
|
*
|
|
* PARAMS
|
|
* ulIn [I] Source
|
|
* pBoolOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
|
|
{
|
|
*pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarBoolFromDec (OLEAUT32.236)
|
|
*
|
|
* Convert a VT_DECIMAL to a VT_BOOL.
|
|
*
|
|
* PARAMS
|
|
* pDecIn [I] Source
|
|
* pBoolOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if pDecIn is invalid.
|
|
*/
|
|
HRESULT WINAPI VarBoolFromDec(const 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, ARRAY_SIZE(szConverted));
|
|
szOut = szConverted;
|
|
}
|
|
return SysAllocStringByteLen((LPCSTR)szOut, lstrlenW(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 + ARRAY_SIZE(szBuff) - 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 = -(LONG64)lIn;
|
|
dwFlags |= VAR_NEGATIVE;
|
|
}
|
|
return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
|
|
}
|
|
|
|
static BSTR VARIANT_BstrReplaceDecimal(const WCHAR * buff, LCID lcid, ULONG dwFlags)
|
|
{
|
|
BSTR bstrOut;
|
|
WCHAR lpDecimalSep[16];
|
|
|
|
/* Native oleaut32 uses the locale-specific decimal separator even in the
|
|
absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
|
|
American locales will see "one thousand and one tenth" as "1000,1"
|
|
instead of "1000.1" (notice the comma). The following code checks for
|
|
the need to replace the decimal separator, and if so, will prepare an
|
|
appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
|
|
*/
|
|
GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE),
|
|
lpDecimalSep, ARRAY_SIZE(lpDecimalSep));
|
|
if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
|
|
{
|
|
/* locale is compatible with English - return original string */
|
|
bstrOut = SysAllocString(buff);
|
|
}
|
|
else
|
|
{
|
|
WCHAR *p;
|
|
WCHAR numbuff[256];
|
|
WCHAR empty[] = L"";
|
|
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 = wcschr( buff, '.' );
|
|
if (p) minFormat.NumDigits = lstrlenW(p + 1);
|
|
|
|
numbuff[0] = '\0';
|
|
if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, ARRAY_SIZE(numbuff)))
|
|
{
|
|
WARN("GetNumberFormatW() failed, returning raw number string instead\n");
|
|
bstrOut = SysAllocString(buff);
|
|
}
|
|
else
|
|
{
|
|
TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
|
|
bstrOut = SysAllocString(numbuff);
|
|
}
|
|
}
|
|
return bstrOut;
|
|
}
|
|
|
|
static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
|
|
BSTR* pbstrOut, LPCWSTR lpszFormat)
|
|
{
|
|
_locale_t locale;
|
|
WCHAR buff[256];
|
|
|
|
if (!pbstrOut)
|
|
return E_INVALIDARG;
|
|
|
|
if (!(locale = _create_locale(LC_ALL, "C"))) return E_OUTOFMEMORY;
|
|
_swprintf_l(buff, ARRAY_SIZE(buff), lpszFormat, locale, dblIn);
|
|
_free_locale(locale);
|
|
|
|
/* 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] == '-')
|
|
{
|
|
if (lstrlenW(buff + 1) == wcsspn(buff + 1, L"0."))
|
|
{ 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, ARRAY_SIZE(numbuff));
|
|
TRACE("created NLS string %s\n", debugstr_w(numbuff));
|
|
*pbstrOut = SysAllocString(numbuff);
|
|
}
|
|
else
|
|
{
|
|
*pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
|
|
}
|
|
return *pbstrOut ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* VarBstrFromR4 (OLEAUT32.111)
|
|
*
|
|
* Convert a VT_R4 to a VT_BSTR.
|
|
*
|
|
* PARAMS
|
|
* fltIn [I] Source
|
|
* lcid [I] LCID for the conversion
|
|
* dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
|
|
* pbstrOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if pbstrOut is invalid.
|
|
* E_OUTOFMEMORY, if memory allocation fails.
|
|
*/
|
|
HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
|
|
{
|
|
return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, L"%.7G");
|
|
}
|
|
|
|
/******************************************************************************
|
|
* 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, L"%.15G");
|
|
}
|
|
|
|
/******************************************************************************
|
|
* 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];
|
|
VARIANT_DI decVal;
|
|
|
|
if (!pbstrOut)
|
|
return E_INVALIDARG;
|
|
|
|
decVal.scale = 4;
|
|
decVal.sign = 0;
|
|
decVal.bitsnum[0] = cyIn.s.Lo;
|
|
decVal.bitsnum[1] = cyIn.s.Hi;
|
|
if (cyIn.s.Hi & 0x80000000UL) {
|
|
DWORD one = 1;
|
|
|
|
/* Negative number! */
|
|
decVal.sign = 1;
|
|
decVal.bitsnum[0] = ~decVal.bitsnum[0];
|
|
decVal.bitsnum[1] = ~decVal.bitsnum[1];
|
|
VARIANT_int_add(decVal.bitsnum, 3, &one, 1);
|
|
}
|
|
decVal.bitsnum[2] = 0;
|
|
VARIANT_DI_tostringW(&decVal, buff, ARRAY_SIZE(buff));
|
|
|
|
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, ARRAY_SIZE(cybuff));
|
|
*pbstrOut = SysAllocString(cybuff);
|
|
}
|
|
else
|
|
*pbstrOut = VARIANT_BstrReplaceDecimal(buff,lcid,dwFlags);
|
|
|
|
return *pbstrOut ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
static inline int output_int_len(int o, int min_len, WCHAR *date, int date_len)
|
|
{
|
|
int len, tmp;
|
|
|
|
if(min_len >= date_len)
|
|
return -1;
|
|
|
|
for(len=0, tmp=o; tmp; tmp/=10) len++;
|
|
if(!len) len++;
|
|
if(len >= date_len)
|
|
return -1;
|
|
|
|
for(tmp=min_len-len; tmp>0; tmp--)
|
|
*date++ = '0';
|
|
for(tmp=len; tmp>0; tmp--, o/=10)
|
|
date[tmp-1] = '0' + o%10;
|
|
return min_len>len ? min_len : len;
|
|
}
|
|
|
|
/* format date string, similar to GetDateFormatW function but works on bigger range of dates */
|
|
BOOL get_date_format(LCID lcid, DWORD flags, const SYSTEMTIME *st,
|
|
const WCHAR *fmt, WCHAR *date, int date_len)
|
|
{
|
|
static const LCTYPE dayname[] = {
|
|
LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
|
|
LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6
|
|
};
|
|
static const LCTYPE sdayname[] = {
|
|
LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
|
|
LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
|
|
LOCALE_SABBREVDAYNAME6
|
|
};
|
|
static const LCTYPE monthname[] = {
|
|
LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
|
|
LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
|
|
LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12
|
|
};
|
|
static const LCTYPE smonthname[] = {
|
|
LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
|
|
LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
|
|
LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
|
|
LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12
|
|
};
|
|
|
|
if(flags & ~(LOCALE_NOUSEROVERRIDE|VAR_DATEVALUEONLY))
|
|
FIXME("ignoring flags %x\n", flags);
|
|
flags &= LOCALE_NOUSEROVERRIDE;
|
|
|
|
while(*fmt && date_len) {
|
|
int count = 1;
|
|
|
|
switch(*fmt) {
|
|
case 'd':
|
|
case 'M':
|
|
case 'y':
|
|
case 'g':
|
|
while(*fmt == *(fmt+count))
|
|
count++;
|
|
fmt += count-1;
|
|
}
|
|
|
|
switch(*fmt) {
|
|
case 'd':
|
|
if(count >= 4)
|
|
count = GetLocaleInfoW(lcid, dayname[st->wDayOfWeek] | flags, date, date_len)-1;
|
|
else if(count == 3)
|
|
count = GetLocaleInfoW(lcid, sdayname[st->wDayOfWeek] | flags, date, date_len)-1;
|
|
else
|
|
count = output_int_len(st->wDay, count, date, date_len);
|
|
break;
|
|
case 'M':
|
|
if(count >= 4)
|
|
count = GetLocaleInfoW(lcid, monthname[st->wMonth-1] | flags, date, date_len)-1;
|
|
else if(count == 3)
|
|
count = GetLocaleInfoW(lcid, smonthname[st->wMonth-1] | flags, date, date_len)-1;
|
|
else
|
|
count = output_int_len(st->wMonth, count, date, date_len);
|
|
break;
|
|
case 'y':
|
|
if(count >= 3)
|
|
count = output_int_len(st->wYear, 0, date, date_len);
|
|
else
|
|
count = output_int_len(st->wYear%100, count, date, date_len);
|
|
break;
|
|
case 'g':
|
|
if(count == 2) {
|
|
FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
|
|
|
|
*date++ = 'A';
|
|
date_len--;
|
|
if(date_len)
|
|
*date = 'D';
|
|
else
|
|
count = -1;
|
|
break;
|
|
}
|
|
/* fall through */
|
|
default:
|
|
*date = *fmt;
|
|
}
|
|
|
|
if(count < 0)
|
|
break;
|
|
fmt++;
|
|
date += count;
|
|
date_len -= count;
|
|
}
|
|
|
|
if(!date_len)
|
|
return FALSE;
|
|
*date++ = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* 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], fmt_buff[80], *time;
|
|
|
|
TRACE("(%g,0x%08x,0x%08x,%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 && partial < 1e-12)
|
|
dwFlags |= VAR_DATEVALUEONLY;
|
|
}
|
|
|
|
if (dwFlags & VAR_TIMEVALUEONLY)
|
|
date[0] = '\0';
|
|
else
|
|
if (!GetLocaleInfoW(lcid, LOCALE_SSHORTDATE, fmt_buff, ARRAY_SIZE(fmt_buff)) ||
|
|
!get_date_format(lcid, dwFlags, &st, fmt_buff, date, ARRAY_SIZE(date)))
|
|
return E_INVALIDARG;
|
|
|
|
if (!(dwFlags & VAR_DATEVALUEONLY))
|
|
{
|
|
time = date + lstrlenW(date);
|
|
if (time != date)
|
|
*time++ = ' ';
|
|
if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time, ARRAY_SIZE(date)-(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%08x,0x%08x,%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(const DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
|
|
{
|
|
WCHAR buff[256];
|
|
VARIANT_DI temp;
|
|
|
|
if (!pbstrOut)
|
|
return E_INVALIDARG;
|
|
|
|
VARIANT_DIFromDec(pDecIn, &temp);
|
|
VARIANT_DI_tostringW(&temp, buff, 256);
|
|
|
|
if (dwFlags & LOCALE_USE_NLS)
|
|
{
|
|
WCHAR numbuff[256];
|
|
|
|
/* Format the number for the locale */
|
|
numbuff[0] = '\0';
|
|
GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
|
|
buff, NULL, numbuff, ARRAY_SIZE(numbuff));
|
|
TRACE("created NLS string %s\n", debugstr_w(numbuff));
|
|
*pbstrOut = SysAllocString(numbuff);
|
|
}
|
|
else
|
|
{
|
|
*pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
|
|
}
|
|
|
|
TRACE("returning %s\n", debugstr_w(*pbstrOut));
|
|
return *pbstrOut ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarBstrFromI8 (OLEAUT32.370)
|
|
*
|
|
* Convert a VT_I8 to a VT_BSTR.
|
|
*
|
|
* PARAMS
|
|
* llIn [I] Source
|
|
* lcid [I] LCID for the conversion
|
|
* dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
|
|
* pbstrOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if pbstrOut is invalid.
|
|
* E_OUTOFMEMORY, if memory allocation fails.
|
|
*/
|
|
HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
|
|
{
|
|
ULONG64 ul64 = llIn;
|
|
|
|
if (llIn < 0)
|
|
{
|
|
ul64 = -llIn;
|
|
dwFlags |= VAR_NEGATIVE;
|
|
}
|
|
return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarBstrFromUI8 (OLEAUT32.371)
|
|
*
|
|
* Convert a VT_UI8 to a VT_BSTR.
|
|
*
|
|
* PARAMS
|
|
* ullIn [I] Source
|
|
* lcid [I] LCID for the conversion
|
|
* dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
|
|
* pbstrOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if pbstrOut is invalid.
|
|
* E_OUTOFMEMORY, if memory allocation fails.
|
|
*/
|
|
HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
|
|
{
|
|
return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
|
|
}
|
|
|
|
/************************************************************************
|
|
* VarBstrFromDisp (OLEAUT32.115)
|
|
*
|
|
* Convert a VT_DISPATCH to a BSTR.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
|
|
* pbstrOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* VarBstrCat (OLEAUT32.313)
|
|
*
|
|
* Concatenate two BSTR values.
|
|
*
|
|
* PARAMS
|
|
* pbstrLeft [I] Source
|
|
* pbstrRight [I] Value to concatenate
|
|
* pbstrOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if pbstrOut is invalid.
|
|
* E_OUTOFMEMORY, if memory allocation fails.
|
|
*/
|
|
HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
|
|
{
|
|
unsigned int lenLeft, lenRight;
|
|
|
|
TRACE("%s,%s,%p\n",
|
|
debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
|
|
debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
|
|
|
|
if (!pbstrOut)
|
|
return E_INVALIDARG;
|
|
|
|
/* use byte length here to properly handle ansi-allocated BSTRs */
|
|
lenLeft = pbstrLeft ? SysStringByteLen(pbstrLeft) : 0;
|
|
lenRight = pbstrRight ? SysStringByteLen(pbstrRight) : 0;
|
|
|
|
*pbstrOut = SysAllocStringByteLen(NULL, lenLeft + lenRight);
|
|
if (!*pbstrOut)
|
|
return E_OUTOFMEMORY;
|
|
|
|
(*pbstrOut)[0] = '\0';
|
|
|
|
if (pbstrLeft)
|
|
memcpy(*pbstrOut, pbstrLeft, lenLeft);
|
|
|
|
if (pbstrRight)
|
|
memcpy((CHAR*)*pbstrOut + lenLeft, pbstrRight, lenRight);
|
|
|
|
TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
|
|
return S_OK;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* VarBstrCmp (OLEAUT32.314)
|
|
*
|
|
* Compare two BSTR values.
|
|
*
|
|
* PARAMS
|
|
* pbstrLeft [I] Source
|
|
* pbstrRight [I] Value to compare
|
|
* lcid [I] LCID for the comparison
|
|
* dwFlags [I] Flags to pass directly to CompareStringW().
|
|
*
|
|
* RETURNS
|
|
* VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
|
|
* than, equal to or greater than pbstrRight respectively.
|
|
*
|
|
* NOTES
|
|
* VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
|
|
* states. A NULL BSTR pointer is equivalent to an empty string.
|
|
* If LCID is equal to 0, a byte by byte comparison is performed.
|
|
*/
|
|
HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
|
|
{
|
|
HRESULT hres;
|
|
int ret;
|
|
|
|
TRACE("%s,%s,%d,%08x\n",
|
|
debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
|
|
debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
|
|
|
|
if (!pbstrLeft || !*pbstrLeft)
|
|
{
|
|
if (pbstrRight && *pbstrRight)
|
|
return VARCMP_LT;
|
|
}
|
|
else if (!pbstrRight || !*pbstrRight)
|
|
return VARCMP_GT;
|
|
|
|
if (lcid == 0)
|
|
{
|
|
unsigned int lenLeft = SysStringByteLen(pbstrLeft);
|
|
unsigned int lenRight = SysStringByteLen(pbstrRight);
|
|
ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight));
|
|
if (ret < 0)
|
|
return VARCMP_LT;
|
|
if (ret > 0)
|
|
return VARCMP_GT;
|
|
if (lenLeft < lenRight)
|
|
return VARCMP_LT;
|
|
if (lenLeft > lenRight)
|
|
return VARCMP_GT;
|
|
return VARCMP_EQ;
|
|
}
|
|
else
|
|
{
|
|
unsigned int lenLeft = SysStringLen(pbstrLeft);
|
|
unsigned int lenRight = SysStringLen(pbstrRight);
|
|
|
|
if (lenLeft == 0 || lenRight == 0)
|
|
{
|
|
if (lenLeft == 0 && lenRight == 0) return VARCMP_EQ;
|
|
return lenLeft < lenRight ? VARCMP_LT : VARCMP_GT;
|
|
}
|
|
|
|
hres = CompareStringW(lcid, dwFlags, pbstrLeft, lenLeft,
|
|
pbstrRight, lenRight) - CSTR_LESS_THAN;
|
|
TRACE("%d\n", hres);
|
|
return hres;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* DATE
|
|
*/
|
|
|
|
/******************************************************************************
|
|
* VarDateFromUI1 (OLEAUT32.88)
|
|
*
|
|
* Convert a VT_UI1 to a VT_DATE.
|
|
*
|
|
* PARAMS
|
|
* bIn [I] Source
|
|
* pdateOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
|
|
{
|
|
return VarR8FromUI1(bIn, pdateOut);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* VarDateFromI2 (OLEAUT32.89)
|
|
*
|
|
* Convert a VT_I2 to a VT_DATE.
|
|
*
|
|
* PARAMS
|
|
* sIn [I] Source
|
|
* pdateOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
|
|
{
|
|
return VarR8FromI2(sIn, pdateOut);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* VarDateFromI4 (OLEAUT32.90)
|
|
*
|
|
* Convert a VT_I4 to a VT_DATE.
|
|
*
|
|
* PARAMS
|
|
* lIn [I] Source
|
|
* pdateOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
|
|
{
|
|
return VarDateFromR8(lIn, pdateOut);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* VarDateFromR4 (OLEAUT32.91)
|
|
*
|
|
* Convert a VT_R4 to a VT_DATE.
|
|
*
|
|
* PARAMS
|
|
* fltIn [I] Source
|
|
* pdateOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
|
|
{
|
|
return VarR8FromR4(fltIn, pdateOut);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* VarDateFromR8 (OLEAUT32.92)
|
|
*
|
|
* Convert a VT_R8 to a VT_DATE.
|
|
*
|
|
* PARAMS
|
|
* dblIn [I] Source
|
|
* pdateOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
|
|
{
|
|
if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
|
|
*pdateOut = (DATE)dblIn;
|
|
return S_OK;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* VarDateFromDisp (OLEAUT32.95)
|
|
*
|
|
* Convert a VT_DISPATCH to a VT_DATE.
|
|
*
|
|
* PARAMS
|
|
* pdispIn [I] Source
|
|
* lcid [I] LCID for conversion
|
|
* pdateOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK.
|
|
* Failure: E_INVALIDARG, if the source value is invalid
|
|
* DISP_E_OVERFLOW, if the value will not fit in the destination
|
|
* DISP_E_TYPEMISMATCH, if the type cannot be converted
|
|
*/
|
|
HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
|
|
{
|
|
return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* VarDateFromBool (OLEAUT32.96)
|
|
*
|
|
* Convert a VT_BOOL to a VT_DATE.
|
|
*
|
|
* PARAMS
|
|
* boolIn [I] Source
|
|
* pdateOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
|
|
{
|
|
return VarR8FromBool(boolIn, pdateOut);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* VarDateFromCy (OLEAUT32.93)
|
|
*
|
|
* Convert a VT_CY to a VT_DATE.
|
|
*
|
|
* PARAMS
|
|
* lIn [I] Source
|
|
* pdateOut [O] Destination
|
|
*
|
|
* RETURNS
|
|
* S_OK.
|
|
*/
|
|
HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
|
|
{
|
|
return VarR8FromCy(cyIn, pdateOut);
|
|
}
|
|
|
|
/* Date string parsing */
|
|
#define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
|
|
#define DP_DATESEP 0x02 /* Date separator */
|
|
#define DP_MONTH 0x04 /* Month name */
|
|
#define DP_AM 0x08 /* AM */
|
|
#define DP_PM 0x10 /* PM */
|
|
|
|
typedef struct tagDATEPARSE
|
|
{
|
|
DWORD dwCount; /* Number of fields found so far (maximum 6) */
|
|
DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
|
|
DWORD dwFlags[6]; /* Flags for each field */
|
|
DWORD dwValues[6]; /* Value of each field */
|
|
} DATEPARSE;
|
|
|
|
#define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
|
|
|
|
#define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
|
|
|
|
/* Determine if a day is valid in a given month of a given year */
|
|
static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
|
|
{
|
|
static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
|
|
|
if (day && month && month < 13)
|
|
{
|
|
if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/* Possible orders for 3 numbers making up a date */
|
|
#define ORDER_MDY 0x01
|
|
#define ORDER_YMD 0x02
|
|
#define ORDER_YDM 0x04
|
|
#define ORDER_DMY 0x08
|
|
#define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
|
|
|
|
/* Determine a date for a particular locale, from 3 numbers */
|
|
static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
|
|
DWORD offset, SYSTEMTIME *st)
|
|
{
|
|
DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
|
|
|
|
if (!dp->dwCount)
|
|
{
|
|
v1 = 30; /* Default to (Variant) 0 date part */
|
|
v2 = 12;
|
|
v3 = 1899;
|
|
goto VARIANT_MakeDate_OK;
|
|
}
|
|
|
|
v1 = dp->dwValues[offset + 0];
|
|
v2 = dp->dwValues[offset + 1];
|
|
if (dp->dwCount == 2)
|
|
{
|
|
SYSTEMTIME current;
|
|
GetSystemTime(¤t);
|
|
v3 = current.wYear;
|
|
}
|
|
else
|
|
v3 = dp->dwValues[offset + 2];
|
|
|
|
TRACE("(%d,%d,%d,%d,%d)\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%08x\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_YDM|ORDER_MYD); break;
|
|
default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Finally: Try any remaining orders */
|
|
dwTry = dwAllOrders;
|
|
}
|
|
|
|
TRACE("Attempt %d, dwTry is 0x%08x\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 old versions of Windows used 29 but
|
|
* Windows 10 1903 and greater use 49. This cutoff may also be modified by
|
|
* setting the value as a string for the relevant calendar id in the
|
|
* registry.
|
|
*
|
|
* For instance to emulate old Windows versions:
|
|
* [HKCU\Control Panel\International\Calendars\TwoDigitYearMax]
|
|
* "1"="29"
|
|
* (also 2, 9, 10, 11 and 12 for the other Gregorian calendars)
|
|
*
|
|
* But Wine doesn't have/use that key at the time of writing.
|
|
*/
|
|
st->wYear = v3 <= 49 ? 2000 + v3 : v3 <= 99 ? 1900 + v3 : v3;
|
|
TRACE("Returning date %d/%d/%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 problem.
|
|
*
|
|
* 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(const 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,
|
|
LOCALE_SDATE
|
|
};
|
|
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
|
|
};
|
|
unsigned int i;
|
|
BSTR tokens[ARRAY_SIZE(ParseDateTokens)];
|
|
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%08x,0x%08x,%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 %d\n", iDate);
|
|
|
|
/* Get the month/day/am/pm tokens for this locale */
|
|
for (i = 0; i < ARRAY_SIZE(tokens); 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, ARRAY_SIZE(buff));
|
|
tokens[i] = SysAllocString(buff);
|
|
TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
|
|
}
|
|
|
|
/* Parse the string into our structure */
|
|
while (*strIn)
|
|
{
|
|
if ('0' <= *strIn && *strIn <= '9')
|
|
{
|
|
OLECHAR* end;
|
|
if (dp.dwCount >= 6)
|
|
{
|
|
hRet = DISP_E_TYPEMISMATCH;
|
|
break;
|
|
}
|
|
dp.dwValues[dp.dwCount] = wcstoul(strIn, &end, 10);
|
|
dp.dwCount++;
|
|
strIn = end - 1;
|
|
}
|
|
else if (iswalpha(*strIn))
|
|
{
|
|
BOOL bFound = FALSE;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(tokens); i++)
|
|
{
|
|
DWORD dwLen = lstrlenW(tokens[i]);
|
|
if (dwLen && !wcsnicmp(strIn, tokens[i], dwLen))
|
|
{
|
|
if (i <= 25)
|
|
{
|
|
if (dp.dwCount >= 6)
|
|
hRet = DISP_E_TYPEMISMATCH;
|
|
else
|
|
{
|
|
dp.dwValues[dp.dwCount] = ParseDateMonths[i];
|
|
dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
|
|
dp.dwCount++;
|
|
}
|
|
}
|
|
else if (i > 39 && i < 42)
|
|
{
|
|
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
|
|
if (tokens[42][0] == *strIn)
|
|
{
|
|
dwDateSeps++;
|
|
if (dwDateSeps > 2)
|
|
hRet = DISP_E_TYPEMISMATCH;
|
|
else
|
|
dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
|
|
}
|
|
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 == ',' || iswspace(*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%08x\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 < ARRAY_SIZE(tokens); 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(const 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;
|
|
}
|