2 * Low level variant functions
4 * Copyright 2003 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
25 #include "wine/debug.h"
26 #include "wine/unicode.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(variant
);
35 extern HMODULE hProxyDll DECLSPEC_HIDDEN
;
37 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
38 #define CY_MULTIPLIER_F 10000.0
39 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
40 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
42 static const WCHAR szFloatFormatW
[] = { '%','.','7','G','\0' };
43 static const WCHAR szDoubleFormatW
[] = { '%','.','1','5','G','\0' };
45 /* Copy data from one variant to another. */
46 static inline void VARIANT_CopyData(const VARIANT
*srcVar
, VARTYPE vt
, void *pOut
)
51 case VT_UI1
: memcpy(pOut
, &V_UI1(srcVar
), sizeof(BYTE
)); break;
54 case VT_UI2
: memcpy(pOut
, &V_UI2(srcVar
), sizeof(SHORT
)); break;
59 case VT_UI4
: memcpy(pOut
, &V_UI4(srcVar
), sizeof (LONG
)); break;
64 case VT_UI8
: memcpy(pOut
, &V_UI8(srcVar
), sizeof (LONG64
)); break;
65 case VT_INT_PTR
: memcpy(pOut
, &V_INT_PTR(srcVar
), sizeof (INT_PTR
)); break;
66 case VT_DECIMAL
: memcpy(pOut
, &V_DECIMAL(srcVar
), sizeof (DECIMAL
)); break;
67 case VT_BSTR
: memcpy(pOut
, &V_BSTR(srcVar
), sizeof(BSTR
)); break;
69 FIXME("VT_ type %d unhandled, please report!\n", vt
);
73 /* Macro to inline conversion from a float or double to any integer type,
74 * rounding according to the 'dutch' convention.
76 #define VARIANT_DutchRound(typ, value, res) do { \
77 double whole = value < 0 ? ceil(value) : floor(value); \
78 double fract = value - whole; \
79 if (fract > 0.5) res = (typ)whole + (typ)1; \
80 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
81 else if (fract >= 0.0) res = (typ)whole; \
82 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
83 else if (fract > -0.5) res = (typ)whole; \
84 else res = (typ)whole - (typ)1; \
88 /* Coerce VT_BSTR to a numeric type */
89 static HRESULT
VARIANT_NumberFromBstr(OLECHAR
* pStrIn
, LCID lcid
, ULONG ulFlags
,
90 void* pOut
, VARTYPE vt
)
97 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
98 np
.cDig
= sizeof(rgb
) / sizeof(BYTE
);
99 np
.dwInFlags
= NUMPRS_STD
;
101 hRet
= VarParseNumFromStr(pStrIn
, lcid
, ulFlags
, &np
, rgb
);
105 /* 1 << vt gives us the VTBIT constant for the destination number type */
106 hRet
= VarNumFromParseNum(&np
, rgb
, 1 << vt
, &dstVar
);
108 VARIANT_CopyData(&dstVar
, vt
, pOut
);
113 /* Coerce VT_DISPATCH to another type */
114 static HRESULT
VARIANT_FromDisp(IDispatch
* pdispIn
, LCID lcid
, void* pOut
,
115 VARTYPE vt
, DWORD dwFlags
)
117 static DISPPARAMS emptyParams
= { NULL
, NULL
, 0, 0 };
118 VARIANTARG srcVar
, dstVar
;
122 return DISP_E_BADVARTYPE
;
124 /* Get the default 'value' property from the IDispatch */
125 VariantInit(&srcVar
);
126 hRet
= IDispatch_Invoke(pdispIn
, DISPID_VALUE
, &IID_NULL
, lcid
, DISPATCH_PROPERTYGET
,
127 &emptyParams
, &srcVar
, NULL
, NULL
);
131 /* Convert the property to the requested type */
132 VariantInit(&dstVar
);
133 hRet
= VariantChangeTypeEx(&dstVar
, &srcVar
, lcid
, dwFlags
, vt
);
134 VariantClear(&srcVar
);
137 VARIANT_CopyData(&dstVar
, vt
, pOut
);
140 hRet
= DISP_E_TYPEMISMATCH
;
144 /* Inline return type */
145 #define RETTYP static inline HRESULT
148 /* Simple compiler cast from one type to another */
149 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
150 *out = in; return S_OK; }
152 /* Compiler cast where input cannot be negative */
153 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
154 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
156 /* Compiler cast where input cannot be > some number */
157 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
158 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
160 /* Compiler cast where input cannot be < some number or >= some other number */
161 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
162 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
165 POSTST(signed char, BYTE
, VarI1FromUI1
, I1_MAX
)
166 BOTHTST(signed char, SHORT
, VarI1FromI2
, I1_MIN
, I1_MAX
)
167 BOTHTST(signed char, LONG
, VarI1FromI4
, I1_MIN
, I1_MAX
)
168 SIMPLE(signed char, VARIANT_BOOL
, VarI1FromBool
)
169 POSTST(signed char, USHORT
, VarI1FromUI2
, I1_MAX
)
170 POSTST(signed char, ULONG
, VarI1FromUI4
, I1_MAX
)
171 BOTHTST(signed char, LONG64
, VarI1FromI8
, I1_MIN
, I1_MAX
)
172 POSTST(signed char, ULONG64
, VarI1FromUI8
, I1_MAX
)
175 BOTHTST(BYTE
, SHORT
, VarUI1FromI2
, UI1_MIN
, UI1_MAX
)
176 SIMPLE(BYTE
, VARIANT_BOOL
, VarUI1FromBool
)
177 NEGTST(BYTE
, signed char, VarUI1FromI1
)
178 POSTST(BYTE
, USHORT
, VarUI1FromUI2
, UI1_MAX
)
179 BOTHTST(BYTE
, LONG
, VarUI1FromI4
, UI1_MIN
, UI1_MAX
)
180 POSTST(BYTE
, ULONG
, VarUI1FromUI4
, UI1_MAX
)
181 BOTHTST(BYTE
, LONG64
, VarUI1FromI8
, UI1_MIN
, UI1_MAX
)
182 POSTST(BYTE
, ULONG64
, VarUI1FromUI8
, UI1_MAX
)
185 SIMPLE(SHORT
, BYTE
, VarI2FromUI1
)
186 BOTHTST(SHORT
, LONG
, VarI2FromI4
, I2_MIN
, I2_MAX
)
187 SIMPLE(SHORT
, VARIANT_BOOL
, VarI2FromBool
)
188 SIMPLE(SHORT
, signed char, VarI2FromI1
)
189 POSTST(SHORT
, USHORT
, VarI2FromUI2
, I2_MAX
)
190 POSTST(SHORT
, ULONG
, VarI2FromUI4
, I2_MAX
)
191 BOTHTST(SHORT
, LONG64
, VarI2FromI8
, I2_MIN
, I2_MAX
)
192 POSTST(SHORT
, ULONG64
, VarI2FromUI8
, I2_MAX
)
195 SIMPLE(USHORT
, BYTE
, VarUI2FromUI1
)
196 NEGTST(USHORT
, SHORT
, VarUI2FromI2
)
197 BOTHTST(USHORT
, LONG
, VarUI2FromI4
, UI2_MIN
, UI2_MAX
)
198 SIMPLE(USHORT
, VARIANT_BOOL
, VarUI2FromBool
)
199 NEGTST(USHORT
, signed char, VarUI2FromI1
)
200 POSTST(USHORT
, ULONG
, VarUI2FromUI4
, UI2_MAX
)
201 BOTHTST(USHORT
, LONG64
, VarUI2FromI8
, UI2_MIN
, UI2_MAX
)
202 POSTST(USHORT
, ULONG64
, VarUI2FromUI8
, UI2_MAX
)
205 SIMPLE(LONG
, BYTE
, VarI4FromUI1
)
206 SIMPLE(LONG
, SHORT
, VarI4FromI2
)
207 SIMPLE(LONG
, VARIANT_BOOL
, VarI4FromBool
)
208 SIMPLE(LONG
, signed char, VarI4FromI1
)
209 SIMPLE(LONG
, USHORT
, VarI4FromUI2
)
210 POSTST(LONG
, ULONG
, VarI4FromUI4
, I4_MAX
)
211 BOTHTST(LONG
, LONG64
, VarI4FromI8
, I4_MIN
, I4_MAX
)
212 POSTST(LONG
, ULONG64
, VarI4FromUI8
, I4_MAX
)
215 SIMPLE(ULONG
, BYTE
, VarUI4FromUI1
)
216 NEGTST(ULONG
, SHORT
, VarUI4FromI2
)
217 NEGTST(ULONG
, LONG
, VarUI4FromI4
)
218 SIMPLE(ULONG
, VARIANT_BOOL
, VarUI4FromBool
)
219 NEGTST(ULONG
, signed char, VarUI4FromI1
)
220 SIMPLE(ULONG
, USHORT
, VarUI4FromUI2
)
221 BOTHTST(ULONG
, LONG64
, VarUI4FromI8
, UI4_MIN
, UI4_MAX
)
222 POSTST(ULONG
, ULONG64
, VarUI4FromUI8
, UI4_MAX
)
225 SIMPLE(LONG64
, BYTE
, VarI8FromUI1
)
226 SIMPLE(LONG64
, SHORT
, VarI8FromI2
)
227 SIMPLE(LONG64
, signed char, VarI8FromI1
)
228 SIMPLE(LONG64
, USHORT
, VarI8FromUI2
)
229 SIMPLE(LONG64
, ULONG
, VarI8FromUI4
)
230 POSTST(LONG64
, ULONG64
, VarI8FromUI8
, I8_MAX
)
233 SIMPLE(ULONG64
, BYTE
, VarUI8FromUI1
)
234 NEGTST(ULONG64
, SHORT
, VarUI8FromI2
)
235 NEGTST(ULONG64
, signed char, VarUI8FromI1
)
236 SIMPLE(ULONG64
, USHORT
, VarUI8FromUI2
)
237 SIMPLE(ULONG64
, ULONG
, VarUI8FromUI4
)
238 NEGTST(ULONG64
, LONG64
, VarUI8FromI8
)
241 SIMPLE(float, BYTE
, VarR4FromUI1
)
242 SIMPLE(float, SHORT
, VarR4FromI2
)
243 SIMPLE(float, signed char, VarR4FromI1
)
244 SIMPLE(float, USHORT
, VarR4FromUI2
)
245 SIMPLE(float, LONG
, VarR4FromI4
)
246 SIMPLE(float, ULONG
, VarR4FromUI4
)
247 SIMPLE(float, LONG64
, VarR4FromI8
)
248 SIMPLE(float, ULONG64
, VarR4FromUI8
)
251 SIMPLE(double, BYTE
, VarR8FromUI1
)
252 SIMPLE(double, SHORT
, VarR8FromI2
)
253 SIMPLE(double, float, VarR8FromR4
)
254 RETTYP
_VarR8FromCy(CY i
, double* o
) { *o
= (double)i
.int64
/ CY_MULTIPLIER_F
; return S_OK
; }
255 SIMPLE(double, DATE
, VarR8FromDate
)
256 SIMPLE(double, signed char, VarR8FromI1
)
257 SIMPLE(double, USHORT
, VarR8FromUI2
)
258 SIMPLE(double, LONG
, VarR8FromI4
)
259 SIMPLE(double, ULONG
, VarR8FromUI4
)
260 SIMPLE(double, LONG64
, VarR8FromI8
)
261 SIMPLE(double, ULONG64
, VarR8FromUI8
)
267 /************************************************************************
268 * VarI1FromUI1 (OLEAUT32.244)
270 * Convert a VT_UI1 to a VT_I1.
274 * pcOut [O] Destination
278 * Failure: E_INVALIDARG, if the source value is invalid
279 * DISP_E_OVERFLOW, if the value will not fit in the destination
281 HRESULT WINAPI
VarI1FromUI1(BYTE bIn
, signed char* pcOut
)
283 return _VarI1FromUI1(bIn
, pcOut
);
286 /************************************************************************
287 * VarI1FromI2 (OLEAUT32.245)
289 * Convert a VT_I2 to a VT_I1.
293 * pcOut [O] Destination
297 * Failure: E_INVALIDARG, if the source value is invalid
298 * DISP_E_OVERFLOW, if the value will not fit in the destination
300 HRESULT WINAPI
VarI1FromI2(SHORT sIn
, signed char* pcOut
)
302 return _VarI1FromI2(sIn
, pcOut
);
305 /************************************************************************
306 * VarI1FromI4 (OLEAUT32.246)
308 * Convert a VT_I4 to a VT_I1.
312 * pcOut [O] Destination
316 * Failure: E_INVALIDARG, if the source value is invalid
317 * DISP_E_OVERFLOW, if the value will not fit in the destination
319 HRESULT WINAPI
VarI1FromI4(LONG iIn
, signed char* pcOut
)
321 return _VarI1FromI4(iIn
, pcOut
);
324 /************************************************************************
325 * VarI1FromR4 (OLEAUT32.247)
327 * Convert a VT_R4 to a VT_I1.
331 * pcOut [O] Destination
335 * Failure: E_INVALIDARG, if the source value is invalid
336 * DISP_E_OVERFLOW, if the value will not fit in the destination
338 HRESULT WINAPI
VarI1FromR4(FLOAT fltIn
, signed char* pcOut
)
340 return VarI1FromR8(fltIn
, pcOut
);
343 /************************************************************************
344 * VarI1FromR8 (OLEAUT32.248)
346 * Convert a VT_R8 to a VT_I1.
350 * pcOut [O] Destination
354 * Failure: E_INVALIDARG, if the source value is invalid
355 * DISP_E_OVERFLOW, if the value will not fit in the destination
358 * See VarI8FromR8() for details concerning rounding.
360 HRESULT WINAPI
VarI1FromR8(double dblIn
, signed char* pcOut
)
362 if (dblIn
< I1_MIN
- 0.5 || dblIn
>= I1_MAX
+ 0.5)
363 return DISP_E_OVERFLOW
;
364 VARIANT_DutchRound(CHAR
, dblIn
, *pcOut
);
368 /************************************************************************
369 * VarI1FromDate (OLEAUT32.249)
371 * Convert a VT_DATE to a VT_I1.
375 * pcOut [O] Destination
379 * Failure: E_INVALIDARG, if the source value is invalid
380 * DISP_E_OVERFLOW, if the value will not fit in the destination
382 HRESULT WINAPI
VarI1FromDate(DATE dateIn
, signed char* pcOut
)
384 return VarI1FromR8(dateIn
, pcOut
);
387 /************************************************************************
388 * VarI1FromCy (OLEAUT32.250)
390 * Convert a VT_CY to a VT_I1.
394 * pcOut [O] Destination
398 * Failure: E_INVALIDARG, if the source value is invalid
399 * DISP_E_OVERFLOW, if the value will not fit in the destination
401 HRESULT WINAPI
VarI1FromCy(CY cyIn
, signed char* pcOut
)
405 VarI4FromCy(cyIn
, &i
);
406 return _VarI1FromI4(i
, pcOut
);
409 /************************************************************************
410 * VarI1FromStr (OLEAUT32.251)
412 * Convert a VT_BSTR to a VT_I1.
416 * lcid [I] LCID for the conversion
417 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
418 * pcOut [O] Destination
422 * Failure: E_INVALIDARG, if the source value is invalid
423 * DISP_E_OVERFLOW, if the value will not fit in the destination
424 * DISP_E_TYPEMISMATCH, if the type cannot be converted
426 HRESULT WINAPI
VarI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, signed char* pcOut
)
428 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pcOut
, VT_I1
);
431 /************************************************************************
432 * VarI1FromDisp (OLEAUT32.252)
434 * Convert a VT_DISPATCH to a VT_I1.
438 * lcid [I] LCID for conversion
439 * pcOut [O] Destination
443 * Failure: E_INVALIDARG, if the source value is invalid
444 * DISP_E_OVERFLOW, if the value will not fit in the destination
445 * DISP_E_TYPEMISMATCH, if the type cannot be converted
447 HRESULT WINAPI
VarI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, signed char* pcOut
)
449 return VARIANT_FromDisp(pdispIn
, lcid
, pcOut
, VT_I1
, 0);
452 /************************************************************************
453 * VarI1FromBool (OLEAUT32.253)
455 * Convert a VT_BOOL to a VT_I1.
459 * pcOut [O] Destination
464 HRESULT WINAPI
VarI1FromBool(VARIANT_BOOL boolIn
, signed char* pcOut
)
466 return _VarI1FromBool(boolIn
, pcOut
);
469 /************************************************************************
470 * VarI1FromUI2 (OLEAUT32.254)
472 * Convert a VT_UI2 to a VT_I1.
476 * pcOut [O] Destination
480 * Failure: E_INVALIDARG, if the source value is invalid
481 * DISP_E_OVERFLOW, if the value will not fit in the destination
483 HRESULT WINAPI
VarI1FromUI2(USHORT usIn
, signed char* pcOut
)
485 return _VarI1FromUI2(usIn
, pcOut
);
488 /************************************************************************
489 * VarI1FromUI4 (OLEAUT32.255)
491 * Convert a VT_UI4 to a VT_I1.
495 * pcOut [O] Destination
499 * Failure: E_INVALIDARG, if the source value is invalid
500 * DISP_E_OVERFLOW, if the value will not fit in the destination
501 * DISP_E_TYPEMISMATCH, if the type cannot be converted
503 HRESULT WINAPI
VarI1FromUI4(ULONG ulIn
, signed char* pcOut
)
505 return _VarI1FromUI4(ulIn
, pcOut
);
508 /************************************************************************
509 * VarI1FromDec (OLEAUT32.256)
511 * Convert a VT_DECIMAL to a VT_I1.
515 * pcOut [O] Destination
519 * Failure: E_INVALIDARG, if the source value is invalid
520 * DISP_E_OVERFLOW, if the value will not fit in the destination
522 HRESULT WINAPI
VarI1FromDec(DECIMAL
*pdecIn
, signed char* pcOut
)
527 hRet
= VarI8FromDec(pdecIn
, &i64
);
530 hRet
= _VarI1FromI8(i64
, pcOut
);
534 /************************************************************************
535 * VarI1FromI8 (OLEAUT32.376)
537 * Convert a VT_I8 to a VT_I1.
541 * pcOut [O] Destination
545 * Failure: E_INVALIDARG, if the source value is invalid
546 * DISP_E_OVERFLOW, if the value will not fit in the destination
548 HRESULT WINAPI
VarI1FromI8(LONG64 llIn
, signed char* pcOut
)
550 return _VarI1FromI8(llIn
, pcOut
);
553 /************************************************************************
554 * VarI1FromUI8 (OLEAUT32.377)
556 * Convert a VT_UI8 to a VT_I1.
560 * pcOut [O] Destination
564 * Failure: E_INVALIDARG, if the source value is invalid
565 * DISP_E_OVERFLOW, if the value will not fit in the destination
567 HRESULT WINAPI
VarI1FromUI8(ULONG64 ullIn
, signed char* pcOut
)
569 return _VarI1FromUI8(ullIn
, pcOut
);
575 /************************************************************************
576 * VarUI1FromI2 (OLEAUT32.130)
578 * Convert a VT_I2 to a VT_UI1.
582 * pbOut [O] Destination
586 * Failure: E_INVALIDARG, if the source value is invalid
587 * DISP_E_OVERFLOW, if the value will not fit in the destination
589 HRESULT WINAPI
VarUI1FromI2(SHORT sIn
, BYTE
* pbOut
)
591 return _VarUI1FromI2(sIn
, pbOut
);
594 /************************************************************************
595 * VarUI1FromI4 (OLEAUT32.131)
597 * Convert a VT_I4 to a VT_UI1.
601 * pbOut [O] Destination
605 * Failure: E_INVALIDARG, if the source value is invalid
606 * DISP_E_OVERFLOW, if the value will not fit in the destination
608 HRESULT WINAPI
VarUI1FromI4(LONG iIn
, BYTE
* pbOut
)
610 return _VarUI1FromI4(iIn
, pbOut
);
613 /************************************************************************
614 * VarUI1FromR4 (OLEAUT32.132)
616 * Convert a VT_R4 to a VT_UI1.
620 * pbOut [O] Destination
624 * Failure: E_INVALIDARG, if the source value is invalid
625 * DISP_E_OVERFLOW, if the value will not fit in the destination
626 * DISP_E_TYPEMISMATCH, if the type cannot be converted
628 HRESULT WINAPI
VarUI1FromR4(FLOAT fltIn
, BYTE
* pbOut
)
630 return VarUI1FromR8(fltIn
, pbOut
);
633 /************************************************************************
634 * VarUI1FromR8 (OLEAUT32.133)
636 * Convert a VT_R8 to a VT_UI1.
640 * pbOut [O] Destination
644 * Failure: E_INVALIDARG, if the source value is invalid
645 * DISP_E_OVERFLOW, if the value will not fit in the destination
648 * See VarI8FromR8() for details concerning rounding.
650 HRESULT WINAPI
VarUI1FromR8(double dblIn
, BYTE
* pbOut
)
652 if (dblIn
< -0.5 || dblIn
>= UI1_MAX
+ 0.5)
653 return DISP_E_OVERFLOW
;
654 VARIANT_DutchRound(BYTE
, dblIn
, *pbOut
);
658 /************************************************************************
659 * VarUI1FromCy (OLEAUT32.134)
661 * Convert a VT_CY to a VT_UI1.
665 * pbOut [O] Destination
669 * Failure: E_INVALIDARG, if the source value is invalid
670 * DISP_E_OVERFLOW, if the value will not fit in the destination
673 * Negative values >= -5000 will be converted to 0.
675 HRESULT WINAPI
VarUI1FromCy(CY cyIn
, BYTE
* pbOut
)
677 ULONG i
= UI1_MAX
+ 1;
679 VarUI4FromCy(cyIn
, &i
);
680 return _VarUI1FromUI4(i
, pbOut
);
683 /************************************************************************
684 * VarUI1FromDate (OLEAUT32.135)
686 * Convert a VT_DATE to a VT_UI1.
690 * pbOut [O] Destination
694 * Failure: E_INVALIDARG, if the source value is invalid
695 * DISP_E_OVERFLOW, if the value will not fit in the destination
697 HRESULT WINAPI
VarUI1FromDate(DATE dateIn
, BYTE
* pbOut
)
699 return VarUI1FromR8(dateIn
, pbOut
);
702 /************************************************************************
703 * VarUI1FromStr (OLEAUT32.136)
705 * Convert a VT_BSTR to a VT_UI1.
709 * lcid [I] LCID for the conversion
710 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
711 * pbOut [O] Destination
715 * Failure: E_INVALIDARG, if the source value is invalid
716 * DISP_E_OVERFLOW, if the value will not fit in the destination
717 * DISP_E_TYPEMISMATCH, if the type cannot be converted
719 HRESULT WINAPI
VarUI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, BYTE
* pbOut
)
721 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pbOut
, VT_UI1
);
724 /************************************************************************
725 * VarUI1FromDisp (OLEAUT32.137)
727 * Convert a VT_DISPATCH to a VT_UI1.
731 * lcid [I] LCID for conversion
732 * pbOut [O] Destination
736 * Failure: E_INVALIDARG, if the source value is invalid
737 * DISP_E_OVERFLOW, if the value will not fit in the destination
738 * DISP_E_TYPEMISMATCH, if the type cannot be converted
740 HRESULT WINAPI
VarUI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, BYTE
* pbOut
)
742 return VARIANT_FromDisp(pdispIn
, lcid
, pbOut
, VT_UI1
, 0);
745 /************************************************************************
746 * VarUI1FromBool (OLEAUT32.138)
748 * Convert a VT_BOOL to a VT_UI1.
752 * pbOut [O] Destination
757 HRESULT WINAPI
VarUI1FromBool(VARIANT_BOOL boolIn
, BYTE
* pbOut
)
759 return _VarUI1FromBool(boolIn
, pbOut
);
762 /************************************************************************
763 * VarUI1FromI1 (OLEAUT32.237)
765 * Convert a VT_I1 to a VT_UI1.
769 * pbOut [O] Destination
773 * Failure: E_INVALIDARG, if the source value is invalid
774 * DISP_E_OVERFLOW, if the value will not fit in the destination
776 HRESULT WINAPI
VarUI1FromI1(signed char cIn
, BYTE
* pbOut
)
778 return _VarUI1FromI1(cIn
, pbOut
);
781 /************************************************************************
782 * VarUI1FromUI2 (OLEAUT32.238)
784 * Convert a VT_UI2 to a VT_UI1.
788 * pbOut [O] Destination
792 * Failure: E_INVALIDARG, if the source value is invalid
793 * DISP_E_OVERFLOW, if the value will not fit in the destination
795 HRESULT WINAPI
VarUI1FromUI2(USHORT usIn
, BYTE
* pbOut
)
797 return _VarUI1FromUI2(usIn
, pbOut
);
800 /************************************************************************
801 * VarUI1FromUI4 (OLEAUT32.239)
803 * Convert a VT_UI4 to a VT_UI1.
807 * pbOut [O] Destination
811 * Failure: E_INVALIDARG, if the source value is invalid
812 * DISP_E_OVERFLOW, if the value will not fit in the destination
814 HRESULT WINAPI
VarUI1FromUI4(ULONG ulIn
, BYTE
* pbOut
)
816 return _VarUI1FromUI4(ulIn
, pbOut
);
819 /************************************************************************
820 * VarUI1FromDec (OLEAUT32.240)
822 * Convert a VT_DECIMAL to a VT_UI1.
826 * pbOut [O] Destination
830 * Failure: E_INVALIDARG, if the source value is invalid
831 * DISP_E_OVERFLOW, if the value will not fit in the destination
833 HRESULT WINAPI
VarUI1FromDec(DECIMAL
*pdecIn
, BYTE
* pbOut
)
838 hRet
= VarI8FromDec(pdecIn
, &i64
);
841 hRet
= _VarUI1FromI8(i64
, pbOut
);
845 /************************************************************************
846 * VarUI1FromI8 (OLEAUT32.372)
848 * Convert a VT_I8 to a VT_UI1.
852 * pbOut [O] Destination
856 * Failure: E_INVALIDARG, if the source value is invalid
857 * DISP_E_OVERFLOW, if the value will not fit in the destination
859 HRESULT WINAPI
VarUI1FromI8(LONG64 llIn
, BYTE
* pbOut
)
861 return _VarUI1FromI8(llIn
, pbOut
);
864 /************************************************************************
865 * VarUI1FromUI8 (OLEAUT32.373)
867 * Convert a VT_UI8 to a VT_UI1.
871 * pbOut [O] Destination
875 * Failure: E_INVALIDARG, if the source value is invalid
876 * DISP_E_OVERFLOW, if the value will not fit in the destination
878 HRESULT WINAPI
VarUI1FromUI8(ULONG64 ullIn
, BYTE
* pbOut
)
880 return _VarUI1FromUI8(ullIn
, pbOut
);
887 /************************************************************************
888 * VarI2FromUI1 (OLEAUT32.48)
890 * Convert a VT_UI2 to a VT_I2.
894 * psOut [O] Destination
899 HRESULT WINAPI
VarI2FromUI1(BYTE bIn
, SHORT
* psOut
)
901 return _VarI2FromUI1(bIn
, psOut
);
904 /************************************************************************
905 * VarI2FromI4 (OLEAUT32.49)
907 * Convert a VT_I4 to a VT_I2.
911 * psOut [O] Destination
915 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
917 HRESULT WINAPI
VarI2FromI4(LONG iIn
, SHORT
* psOut
)
919 return _VarI2FromI4(iIn
, psOut
);
922 /************************************************************************
923 * VarI2FromR4 (OLEAUT32.50)
925 * Convert a VT_R4 to a VT_I2.
929 * psOut [O] Destination
933 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
935 HRESULT WINAPI
VarI2FromR4(FLOAT fltIn
, SHORT
* psOut
)
937 return VarI2FromR8(fltIn
, psOut
);
940 /************************************************************************
941 * VarI2FromR8 (OLEAUT32.51)
943 * Convert a VT_R8 to a VT_I2.
947 * psOut [O] Destination
951 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
954 * See VarI8FromR8() for details concerning rounding.
956 HRESULT WINAPI
VarI2FromR8(double dblIn
, SHORT
* psOut
)
958 if (dblIn
< I2_MIN
- 0.5 || dblIn
>= I2_MAX
+ 0.5)
959 return DISP_E_OVERFLOW
;
960 VARIANT_DutchRound(SHORT
, dblIn
, *psOut
);
964 /************************************************************************
965 * VarI2FromCy (OLEAUT32.52)
967 * Convert a VT_CY to a VT_I2.
971 * psOut [O] Destination
975 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
977 HRESULT WINAPI
VarI2FromCy(CY cyIn
, SHORT
* psOut
)
981 VarI4FromCy(cyIn
, &i
);
982 return _VarI2FromI4(i
, psOut
);
985 /************************************************************************
986 * VarI2FromDate (OLEAUT32.53)
988 * Convert a VT_DATE to a VT_I2.
992 * psOut [O] Destination
996 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
998 HRESULT WINAPI
VarI2FromDate(DATE dateIn
, SHORT
* psOut
)
1000 return VarI2FromR8(dateIn
, psOut
);
1003 /************************************************************************
1004 * VarI2FromStr (OLEAUT32.54)
1006 * Convert a VT_BSTR to a VT_I2.
1010 * lcid [I] LCID for the conversion
1011 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1012 * psOut [O] Destination
1016 * Failure: E_INVALIDARG, if any parameter is invalid
1017 * DISP_E_OVERFLOW, if the value will not fit in the destination
1018 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1020 HRESULT WINAPI
VarI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, SHORT
* psOut
)
1022 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, psOut
, VT_I2
);
1025 /************************************************************************
1026 * VarI2FromDisp (OLEAUT32.55)
1028 * Convert a VT_DISPATCH to a VT_I2.
1031 * pdispIn [I] Source
1032 * lcid [I] LCID for conversion
1033 * psOut [O] Destination
1037 * Failure: E_INVALIDARG, if pdispIn is invalid,
1038 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1039 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1041 HRESULT WINAPI
VarI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, SHORT
* psOut
)
1043 return VARIANT_FromDisp(pdispIn
, lcid
, psOut
, VT_I2
, 0);
1046 /************************************************************************
1047 * VarI2FromBool (OLEAUT32.56)
1049 * Convert a VT_BOOL to a VT_I2.
1053 * psOut [O] Destination
1058 HRESULT WINAPI
VarI2FromBool(VARIANT_BOOL boolIn
, SHORT
* psOut
)
1060 return _VarI2FromBool(boolIn
, psOut
);
1063 /************************************************************************
1064 * VarI2FromI1 (OLEAUT32.205)
1066 * Convert a VT_I1 to a VT_I2.
1070 * psOut [O] Destination
1075 HRESULT WINAPI
VarI2FromI1(signed char cIn
, SHORT
* psOut
)
1077 return _VarI2FromI1(cIn
, psOut
);
1080 /************************************************************************
1081 * VarI2FromUI2 (OLEAUT32.206)
1083 * Convert a VT_UI2 to a VT_I2.
1087 * psOut [O] Destination
1091 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1093 HRESULT WINAPI
VarI2FromUI2(USHORT usIn
, SHORT
* psOut
)
1095 return _VarI2FromUI2(usIn
, psOut
);
1098 /************************************************************************
1099 * VarI2FromUI4 (OLEAUT32.207)
1101 * Convert a VT_UI4 to a VT_I2.
1105 * psOut [O] Destination
1109 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1111 HRESULT WINAPI
VarI2FromUI4(ULONG ulIn
, SHORT
* psOut
)
1113 return _VarI2FromUI4(ulIn
, psOut
);
1116 /************************************************************************
1117 * VarI2FromDec (OLEAUT32.208)
1119 * Convert a VT_DECIMAL to a VT_I2.
1123 * psOut [O] Destination
1127 * Failure: E_INVALIDARG, if the source value is invalid
1128 * DISP_E_OVERFLOW, if the value will not fit in the destination
1130 HRESULT WINAPI
VarI2FromDec(DECIMAL
*pdecIn
, SHORT
* psOut
)
1135 hRet
= VarI8FromDec(pdecIn
, &i64
);
1137 if (SUCCEEDED(hRet
))
1138 hRet
= _VarI2FromI8(i64
, psOut
);
1142 /************************************************************************
1143 * VarI2FromI8 (OLEAUT32.346)
1145 * Convert a VT_I8 to a VT_I2.
1149 * psOut [O] Destination
1153 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1155 HRESULT WINAPI
VarI2FromI8(LONG64 llIn
, SHORT
* psOut
)
1157 return _VarI2FromI8(llIn
, psOut
);
1160 /************************************************************************
1161 * VarI2FromUI8 (OLEAUT32.347)
1163 * Convert a VT_UI8 to a VT_I2.
1167 * psOut [O] Destination
1171 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1173 HRESULT WINAPI
VarI2FromUI8(ULONG64 ullIn
, SHORT
* psOut
)
1175 return _VarI2FromUI8(ullIn
, psOut
);
1181 /************************************************************************
1182 * VarUI2FromUI1 (OLEAUT32.257)
1184 * Convert a VT_UI1 to a VT_UI2.
1188 * pusOut [O] Destination
1193 HRESULT WINAPI
VarUI2FromUI1(BYTE bIn
, USHORT
* pusOut
)
1195 return _VarUI2FromUI1(bIn
, pusOut
);
1198 /************************************************************************
1199 * VarUI2FromI2 (OLEAUT32.258)
1201 * Convert a VT_I2 to a VT_UI2.
1205 * pusOut [O] Destination
1209 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1211 HRESULT WINAPI
VarUI2FromI2(SHORT sIn
, USHORT
* pusOut
)
1213 return _VarUI2FromI2(sIn
, pusOut
);
1216 /************************************************************************
1217 * VarUI2FromI4 (OLEAUT32.259)
1219 * Convert a VT_I4 to a VT_UI2.
1223 * pusOut [O] Destination
1227 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1229 HRESULT WINAPI
VarUI2FromI4(LONG iIn
, USHORT
* pusOut
)
1231 return _VarUI2FromI4(iIn
, pusOut
);
1234 /************************************************************************
1235 * VarUI2FromR4 (OLEAUT32.260)
1237 * Convert a VT_R4 to a VT_UI2.
1241 * pusOut [O] Destination
1245 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1247 HRESULT WINAPI
VarUI2FromR4(FLOAT fltIn
, USHORT
* pusOut
)
1249 return VarUI2FromR8(fltIn
, pusOut
);
1252 /************************************************************************
1253 * VarUI2FromR8 (OLEAUT32.261)
1255 * Convert a VT_R8 to a VT_UI2.
1259 * pusOut [O] Destination
1263 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1266 * See VarI8FromR8() for details concerning rounding.
1268 HRESULT WINAPI
VarUI2FromR8(double dblIn
, USHORT
* pusOut
)
1270 if (dblIn
< -0.5 || dblIn
>= UI2_MAX
+ 0.5)
1271 return DISP_E_OVERFLOW
;
1272 VARIANT_DutchRound(USHORT
, dblIn
, *pusOut
);
1276 /************************************************************************
1277 * VarUI2FromDate (OLEAUT32.262)
1279 * Convert a VT_DATE to a VT_UI2.
1283 * pusOut [O] Destination
1287 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1289 HRESULT WINAPI
VarUI2FromDate(DATE dateIn
, USHORT
* pusOut
)
1291 return VarUI2FromR8(dateIn
, pusOut
);
1294 /************************************************************************
1295 * VarUI2FromCy (OLEAUT32.263)
1297 * Convert a VT_CY to a VT_UI2.
1301 * pusOut [O] Destination
1305 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1308 * Negative values >= -5000 will be converted to 0.
1310 HRESULT WINAPI
VarUI2FromCy(CY cyIn
, USHORT
* pusOut
)
1312 ULONG i
= UI2_MAX
+ 1;
1314 VarUI4FromCy(cyIn
, &i
);
1315 return _VarUI2FromUI4(i
, pusOut
);
1318 /************************************************************************
1319 * VarUI2FromStr (OLEAUT32.264)
1321 * Convert a VT_BSTR to a VT_UI2.
1325 * lcid [I] LCID for the conversion
1326 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1327 * pusOut [O] Destination
1331 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1332 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1334 HRESULT WINAPI
VarUI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, USHORT
* pusOut
)
1336 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pusOut
, VT_UI2
);
1339 /************************************************************************
1340 * VarUI2FromDisp (OLEAUT32.265)
1342 * Convert a VT_DISPATCH to a VT_UI2.
1345 * pdispIn [I] Source
1346 * lcid [I] LCID for conversion
1347 * pusOut [O] Destination
1351 * Failure: E_INVALIDARG, if the source value is invalid
1352 * DISP_E_OVERFLOW, if the value will not fit in the destination
1353 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1355 HRESULT WINAPI
VarUI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, USHORT
* pusOut
)
1357 return VARIANT_FromDisp(pdispIn
, lcid
, pusOut
, VT_UI2
, 0);
1360 /************************************************************************
1361 * VarUI2FromBool (OLEAUT32.266)
1363 * Convert a VT_BOOL to a VT_UI2.
1367 * pusOut [O] Destination
1372 HRESULT WINAPI
VarUI2FromBool(VARIANT_BOOL boolIn
, USHORT
* pusOut
)
1374 return _VarUI2FromBool(boolIn
, pusOut
);
1377 /************************************************************************
1378 * VarUI2FromI1 (OLEAUT32.267)
1380 * Convert a VT_I1 to a VT_UI2.
1384 * pusOut [O] Destination
1388 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1390 HRESULT WINAPI
VarUI2FromI1(signed char cIn
, USHORT
* pusOut
)
1392 return _VarUI2FromI1(cIn
, pusOut
);
1395 /************************************************************************
1396 * VarUI2FromUI4 (OLEAUT32.268)
1398 * Convert a VT_UI4 to a VT_UI2.
1402 * pusOut [O] Destination
1406 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1408 HRESULT WINAPI
VarUI2FromUI4(ULONG ulIn
, USHORT
* pusOut
)
1410 return _VarUI2FromUI4(ulIn
, pusOut
);
1413 /************************************************************************
1414 * VarUI2FromDec (OLEAUT32.269)
1416 * Convert a VT_DECIMAL to a VT_UI2.
1420 * pusOut [O] Destination
1424 * Failure: E_INVALIDARG, if the source value is invalid
1425 * DISP_E_OVERFLOW, if the value will not fit in the destination
1427 HRESULT WINAPI
VarUI2FromDec(DECIMAL
*pdecIn
, USHORT
* pusOut
)
1432 hRet
= VarI8FromDec(pdecIn
, &i64
);
1434 if (SUCCEEDED(hRet
))
1435 hRet
= _VarUI2FromI8(i64
, pusOut
);
1439 /************************************************************************
1440 * VarUI2FromI8 (OLEAUT32.378)
1442 * Convert a VT_I8 to a VT_UI2.
1446 * pusOut [O] Destination
1450 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1452 HRESULT WINAPI
VarUI2FromI8(LONG64 llIn
, USHORT
* pusOut
)
1454 return _VarUI2FromI8(llIn
, pusOut
);
1457 /************************************************************************
1458 * VarUI2FromUI8 (OLEAUT32.379)
1460 * Convert a VT_UI8 to a VT_UI2.
1464 * pusOut [O] Destination
1468 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1470 HRESULT WINAPI
VarUI2FromUI8(ULONG64 ullIn
, USHORT
* pusOut
)
1472 return _VarUI2FromUI8(ullIn
, pusOut
);
1478 /************************************************************************
1479 * VarI4FromUI1 (OLEAUT32.58)
1481 * Convert a VT_UI1 to a VT_I4.
1485 * piOut [O] Destination
1490 HRESULT WINAPI
VarI4FromUI1(BYTE bIn
, LONG
*piOut
)
1492 return _VarI4FromUI1(bIn
, piOut
);
1495 /************************************************************************
1496 * VarI4FromI2 (OLEAUT32.59)
1498 * Convert a VT_I2 to a VT_I4.
1502 * piOut [O] Destination
1506 * Failure: E_INVALIDARG, if the source value is invalid
1507 * DISP_E_OVERFLOW, if the value will not fit in the destination
1509 HRESULT WINAPI
VarI4FromI2(SHORT sIn
, LONG
*piOut
)
1511 return _VarI4FromI2(sIn
, piOut
);
1514 /************************************************************************
1515 * VarI4FromR4 (OLEAUT32.60)
1517 * Convert a VT_R4 to a VT_I4.
1521 * piOut [O] Destination
1525 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1527 HRESULT WINAPI
VarI4FromR4(FLOAT fltIn
, LONG
*piOut
)
1529 return VarI4FromR8(fltIn
, piOut
);
1532 /************************************************************************
1533 * VarI4FromR8 (OLEAUT32.61)
1535 * Convert a VT_R8 to a VT_I4.
1539 * piOut [O] Destination
1543 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1546 * See VarI8FromR8() for details concerning rounding.
1548 HRESULT WINAPI
VarI4FromR8(double dblIn
, LONG
*piOut
)
1550 if (dblIn
< I4_MIN
- 0.5 || dblIn
>= I4_MAX
+ 0.5)
1551 return DISP_E_OVERFLOW
;
1552 VARIANT_DutchRound(LONG
, dblIn
, *piOut
);
1556 /************************************************************************
1557 * VarI4FromCy (OLEAUT32.62)
1559 * Convert a VT_CY to a VT_I4.
1563 * piOut [O] Destination
1567 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1569 HRESULT WINAPI
VarI4FromCy(CY cyIn
, LONG
*piOut
)
1571 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1572 return VarI4FromR8(d
, piOut
);
1575 /************************************************************************
1576 * VarI4FromDate (OLEAUT32.63)
1578 * Convert a VT_DATE to a VT_I4.
1582 * piOut [O] Destination
1586 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1588 HRESULT WINAPI
VarI4FromDate(DATE dateIn
, LONG
*piOut
)
1590 return VarI4FromR8(dateIn
, piOut
);
1593 /************************************************************************
1594 * VarI4FromStr (OLEAUT32.64)
1596 * Convert a VT_BSTR to a VT_I4.
1600 * lcid [I] LCID for the conversion
1601 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1602 * piOut [O] Destination
1606 * Failure: E_INVALIDARG, if any parameter is invalid
1607 * DISP_E_OVERFLOW, if the value will not fit in the destination
1608 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1610 HRESULT WINAPI
VarI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG
*piOut
)
1612 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, piOut
, VT_I4
);
1615 /************************************************************************
1616 * VarI4FromDisp (OLEAUT32.65)
1618 * Convert a VT_DISPATCH to a VT_I4.
1621 * pdispIn [I] Source
1622 * lcid [I] LCID for conversion
1623 * piOut [O] Destination
1627 * Failure: E_INVALIDARG, if the source value is invalid
1628 * DISP_E_OVERFLOW, if the value will not fit in the destination
1629 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1631 HRESULT WINAPI
VarI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG
*piOut
)
1633 return VARIANT_FromDisp(pdispIn
, lcid
, piOut
, VT_I4
, 0);
1636 /************************************************************************
1637 * VarI4FromBool (OLEAUT32.66)
1639 * Convert a VT_BOOL to a VT_I4.
1643 * piOut [O] Destination
1648 HRESULT WINAPI
VarI4FromBool(VARIANT_BOOL boolIn
, LONG
*piOut
)
1650 return _VarI4FromBool(boolIn
, piOut
);
1653 /************************************************************************
1654 * VarI4FromI1 (OLEAUT32.209)
1656 * Convert a VT_I1 to a VT_I4.
1660 * piOut [O] Destination
1665 HRESULT WINAPI
VarI4FromI1(signed char cIn
, LONG
*piOut
)
1667 return _VarI4FromI1(cIn
, piOut
);
1670 /************************************************************************
1671 * VarI4FromUI2 (OLEAUT32.210)
1673 * Convert a VT_UI2 to a VT_I4.
1677 * piOut [O] Destination
1682 HRESULT WINAPI
VarI4FromUI2(USHORT usIn
, LONG
*piOut
)
1684 return _VarI4FromUI2(usIn
, piOut
);
1687 /************************************************************************
1688 * VarI4FromUI4 (OLEAUT32.211)
1690 * Convert a VT_UI4 to a VT_I4.
1694 * piOut [O] Destination
1698 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1700 HRESULT WINAPI
VarI4FromUI4(ULONG ulIn
, LONG
*piOut
)
1702 return _VarI4FromUI4(ulIn
, piOut
);
1705 /************************************************************************
1706 * VarI4FromDec (OLEAUT32.212)
1708 * Convert a VT_DECIMAL to a VT_I4.
1712 * piOut [O] Destination
1716 * Failure: E_INVALIDARG, if pdecIn is invalid
1717 * DISP_E_OVERFLOW, if the value will not fit in the destination
1719 HRESULT WINAPI
VarI4FromDec(DECIMAL
*pdecIn
, LONG
*piOut
)
1724 hRet
= VarI8FromDec(pdecIn
, &i64
);
1726 if (SUCCEEDED(hRet
))
1727 hRet
= _VarI4FromI8(i64
, piOut
);
1731 /************************************************************************
1732 * VarI4FromI8 (OLEAUT32.348)
1734 * Convert a VT_I8 to a VT_I4.
1738 * piOut [O] Destination
1742 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1744 HRESULT WINAPI
VarI4FromI8(LONG64 llIn
, LONG
*piOut
)
1746 return _VarI4FromI8(llIn
, piOut
);
1749 /************************************************************************
1750 * VarI4FromUI8 (OLEAUT32.349)
1752 * Convert a VT_UI8 to a VT_I4.
1756 * piOut [O] Destination
1760 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1762 HRESULT WINAPI
VarI4FromUI8(ULONG64 ullIn
, LONG
*piOut
)
1764 return _VarI4FromUI8(ullIn
, piOut
);
1770 /************************************************************************
1771 * VarUI4FromUI1 (OLEAUT32.270)
1773 * Convert a VT_UI1 to a VT_UI4.
1777 * pulOut [O] Destination
1782 HRESULT WINAPI
VarUI4FromUI1(BYTE bIn
, ULONG
*pulOut
)
1784 return _VarUI4FromUI1(bIn
, pulOut
);
1787 /************************************************************************
1788 * VarUI4FromI2 (OLEAUT32.271)
1790 * Convert a VT_I2 to a VT_UI4.
1794 * pulOut [O] Destination
1798 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1800 HRESULT WINAPI
VarUI4FromI2(SHORT sIn
, ULONG
*pulOut
)
1802 return _VarUI4FromI2(sIn
, pulOut
);
1805 /************************************************************************
1806 * VarUI4FromI4 (OLEAUT32.272)
1808 * Convert a VT_I4 to a VT_UI4.
1812 * pulOut [O] Destination
1816 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1818 HRESULT WINAPI
VarUI4FromI4(LONG iIn
, ULONG
*pulOut
)
1820 return _VarUI4FromI4(iIn
, pulOut
);
1823 /************************************************************************
1824 * VarUI4FromR4 (OLEAUT32.273)
1826 * Convert a VT_R4 to a VT_UI4.
1830 * pulOut [O] Destination
1834 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1836 HRESULT WINAPI
VarUI4FromR4(FLOAT fltIn
, ULONG
*pulOut
)
1838 return VarUI4FromR8(fltIn
, pulOut
);
1841 /************************************************************************
1842 * VarUI4FromR8 (OLEAUT32.274)
1844 * Convert a VT_R8 to a VT_UI4.
1848 * pulOut [O] Destination
1852 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1855 * See VarI8FromR8() for details concerning rounding.
1857 HRESULT WINAPI
VarUI4FromR8(double dblIn
, ULONG
*pulOut
)
1859 if (dblIn
< -0.5 || dblIn
>= UI4_MAX
+ 0.5)
1860 return DISP_E_OVERFLOW
;
1861 VARIANT_DutchRound(ULONG
, dblIn
, *pulOut
);
1865 /************************************************************************
1866 * VarUI4FromDate (OLEAUT32.275)
1868 * Convert a VT_DATE to a VT_UI4.
1872 * pulOut [O] Destination
1876 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1878 HRESULT WINAPI
VarUI4FromDate(DATE dateIn
, ULONG
*pulOut
)
1880 return VarUI4FromR8(dateIn
, pulOut
);
1883 /************************************************************************
1884 * VarUI4FromCy (OLEAUT32.276)
1886 * Convert a VT_CY to a VT_UI4.
1890 * pulOut [O] Destination
1894 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1896 HRESULT WINAPI
VarUI4FromCy(CY cyIn
, ULONG
*pulOut
)
1898 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1899 return VarUI4FromR8(d
, pulOut
);
1902 /************************************************************************
1903 * VarUI4FromStr (OLEAUT32.277)
1905 * Convert a VT_BSTR to a VT_UI4.
1909 * lcid [I] LCID for the conversion
1910 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1911 * pulOut [O] Destination
1915 * Failure: E_INVALIDARG, if any parameter is invalid
1916 * DISP_E_OVERFLOW, if the value will not fit in the destination
1917 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1919 HRESULT WINAPI
VarUI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG
*pulOut
)
1921 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pulOut
, VT_UI4
);
1924 /************************************************************************
1925 * VarUI4FromDisp (OLEAUT32.278)
1927 * Convert a VT_DISPATCH to a VT_UI4.
1930 * pdispIn [I] Source
1931 * lcid [I] LCID for conversion
1932 * pulOut [O] Destination
1936 * Failure: E_INVALIDARG, if the source value is invalid
1937 * DISP_E_OVERFLOW, if the value will not fit in the destination
1938 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1940 HRESULT WINAPI
VarUI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG
*pulOut
)
1942 return VARIANT_FromDisp(pdispIn
, lcid
, pulOut
, VT_UI4
, 0);
1945 /************************************************************************
1946 * VarUI4FromBool (OLEAUT32.279)
1948 * Convert a VT_BOOL to a VT_UI4.
1952 * pulOut [O] Destination
1957 HRESULT WINAPI
VarUI4FromBool(VARIANT_BOOL boolIn
, ULONG
*pulOut
)
1959 return _VarUI4FromBool(boolIn
, pulOut
);
1962 /************************************************************************
1963 * VarUI4FromI1 (OLEAUT32.280)
1965 * Convert a VT_I1 to a VT_UI4.
1969 * pulOut [O] Destination
1973 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1975 HRESULT WINAPI
VarUI4FromI1(signed char cIn
, ULONG
*pulOut
)
1977 return _VarUI4FromI1(cIn
, pulOut
);
1980 /************************************************************************
1981 * VarUI4FromUI2 (OLEAUT32.281)
1983 * Convert a VT_UI2 to a VT_UI4.
1987 * pulOut [O] Destination
1992 HRESULT WINAPI
VarUI4FromUI2(USHORT usIn
, ULONG
*pulOut
)
1994 return _VarUI4FromUI2(usIn
, pulOut
);
1997 /************************************************************************
1998 * VarUI4FromDec (OLEAUT32.282)
2000 * Convert a VT_DECIMAL to a VT_UI4.
2004 * pulOut [O] Destination
2008 * Failure: E_INVALIDARG, if pdecIn is invalid
2009 * DISP_E_OVERFLOW, if the value will not fit in the destination
2011 HRESULT WINAPI
VarUI4FromDec(DECIMAL
*pdecIn
, ULONG
*pulOut
)
2016 hRet
= VarI8FromDec(pdecIn
, &i64
);
2018 if (SUCCEEDED(hRet
))
2019 hRet
= _VarUI4FromI8(i64
, pulOut
);
2023 /************************************************************************
2024 * VarUI4FromI8 (OLEAUT32.425)
2026 * Convert a VT_I8 to a VT_UI4.
2030 * pulOut [O] Destination
2034 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2036 HRESULT WINAPI
VarUI4FromI8(LONG64 llIn
, ULONG
*pulOut
)
2038 return _VarUI4FromI8(llIn
, pulOut
);
2041 /************************************************************************
2042 * VarUI4FromUI8 (OLEAUT32.426)
2044 * Convert a VT_UI8 to a VT_UI4.
2048 * pulOut [O] Destination
2052 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2054 HRESULT WINAPI
VarUI4FromUI8(ULONG64 ullIn
, ULONG
*pulOut
)
2056 return _VarUI4FromUI8(ullIn
, pulOut
);
2062 /************************************************************************
2063 * VarI8FromUI1 (OLEAUT32.333)
2065 * Convert a VT_UI1 to a VT_I8.
2069 * pi64Out [O] Destination
2074 HRESULT WINAPI
VarI8FromUI1(BYTE bIn
, LONG64
* pi64Out
)
2076 return _VarI8FromUI1(bIn
, pi64Out
);
2080 /************************************************************************
2081 * VarI8FromI2 (OLEAUT32.334)
2083 * Convert a VT_I2 to a VT_I8.
2087 * pi64Out [O] Destination
2092 HRESULT WINAPI
VarI8FromI2(SHORT sIn
, LONG64
* pi64Out
)
2094 return _VarI8FromI2(sIn
, pi64Out
);
2097 /************************************************************************
2098 * VarI8FromR4 (OLEAUT32.335)
2100 * Convert a VT_R4 to a VT_I8.
2104 * pi64Out [O] Destination
2108 * Failure: E_INVALIDARG, if the source value is invalid
2109 * DISP_E_OVERFLOW, if the value will not fit in the destination
2111 HRESULT WINAPI
VarI8FromR4(FLOAT fltIn
, LONG64
* pi64Out
)
2113 return VarI8FromR8(fltIn
, pi64Out
);
2116 /************************************************************************
2117 * VarI8FromR8 (OLEAUT32.336)
2119 * Convert a VT_R8 to a VT_I8.
2123 * pi64Out [O] Destination
2127 * Failure: E_INVALIDARG, if the source value is invalid
2128 * DISP_E_OVERFLOW, if the value will not fit in the destination
2131 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2132 * very high or low values will not be accurately converted.
2134 * Numbers are rounded using Dutch rounding, as follows:
2136 *| Fractional Part Sign Direction Example
2137 *| --------------- ---- --------- -------
2138 *| < 0.5 + Down 0.4 -> 0.0
2139 *| < 0.5 - Up -0.4 -> 0.0
2140 *| > 0.5 + Up 0.6 -> 1.0
2141 *| < 0.5 - Up -0.6 -> -1.0
2142 *| = 0.5 + Up/Down Down if even, Up if odd
2143 *| = 0.5 - Up/Down Up if even, Down if odd
2145 * This system is often used in supermarkets.
2147 HRESULT WINAPI
VarI8FromR8(double dblIn
, LONG64
* pi64Out
)
2149 if ( dblIn
< -4611686018427387904.0 || dblIn
>= 4611686018427387904.0)
2150 return DISP_E_OVERFLOW
;
2151 VARIANT_DutchRound(LONG64
, dblIn
, *pi64Out
);
2155 /************************************************************************
2156 * VarI8FromCy (OLEAUT32.337)
2158 * Convert a VT_CY to a VT_I8.
2162 * pi64Out [O] Destination
2168 * All negative numbers are rounded down by 1, including those that are
2169 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2170 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2173 HRESULT WINAPI
VarI8FromCy(CY cyIn
, LONG64
* pi64Out
)
2175 *pi64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2178 (*pi64Out
)--; /* Mimic Win32 bug */
2181 cyIn
.int64
-= *pi64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2183 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pi64Out
& 0x1)))
2189 /************************************************************************
2190 * VarI8FromDate (OLEAUT32.338)
2192 * Convert a VT_DATE to a VT_I8.
2196 * pi64Out [O] Destination
2200 * Failure: E_INVALIDARG, if the source value is invalid
2201 * DISP_E_OVERFLOW, if the value will not fit in the destination
2202 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2204 HRESULT WINAPI
VarI8FromDate(DATE dateIn
, LONG64
* pi64Out
)
2206 return VarI8FromR8(dateIn
, pi64Out
);
2209 /************************************************************************
2210 * VarI8FromStr (OLEAUT32.339)
2212 * Convert a VT_BSTR to a VT_I8.
2216 * lcid [I] LCID for the conversion
2217 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2218 * pi64Out [O] Destination
2222 * Failure: E_INVALIDARG, if the source value is invalid
2223 * DISP_E_OVERFLOW, if the value will not fit in the destination
2224 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2226 HRESULT WINAPI
VarI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG64
* pi64Out
)
2228 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pi64Out
, VT_I8
);
2231 /************************************************************************
2232 * VarI8FromDisp (OLEAUT32.340)
2234 * Convert a VT_DISPATCH to a VT_I8.
2237 * pdispIn [I] Source
2238 * lcid [I] LCID for conversion
2239 * pi64Out [O] Destination
2243 * Failure: E_INVALIDARG, if the source value is invalid
2244 * DISP_E_OVERFLOW, if the value will not fit in the destination
2245 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2247 HRESULT WINAPI
VarI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG64
* pi64Out
)
2249 return VARIANT_FromDisp(pdispIn
, lcid
, pi64Out
, VT_I8
, 0);
2252 /************************************************************************
2253 * VarI8FromBool (OLEAUT32.341)
2255 * Convert a VT_BOOL to a VT_I8.
2259 * pi64Out [O] Destination
2264 HRESULT WINAPI
VarI8FromBool(VARIANT_BOOL boolIn
, LONG64
* pi64Out
)
2266 return VarI8FromI2(boolIn
, pi64Out
);
2269 /************************************************************************
2270 * VarI8FromI1 (OLEAUT32.342)
2272 * Convert a VT_I1 to a VT_I8.
2276 * pi64Out [O] Destination
2281 HRESULT WINAPI
VarI8FromI1(signed char cIn
, LONG64
* pi64Out
)
2283 return _VarI8FromI1(cIn
, pi64Out
);
2286 /************************************************************************
2287 * VarI8FromUI2 (OLEAUT32.343)
2289 * Convert a VT_UI2 to a VT_I8.
2293 * pi64Out [O] Destination
2298 HRESULT WINAPI
VarI8FromUI2(USHORT usIn
, LONG64
* pi64Out
)
2300 return _VarI8FromUI2(usIn
, pi64Out
);
2303 /************************************************************************
2304 * VarI8FromUI4 (OLEAUT32.344)
2306 * Convert a VT_UI4 to a VT_I8.
2310 * pi64Out [O] Destination
2315 HRESULT WINAPI
VarI8FromUI4(ULONG ulIn
, LONG64
* pi64Out
)
2317 return _VarI8FromUI4(ulIn
, pi64Out
);
2320 /************************************************************************
2321 * VarI8FromDec (OLEAUT32.345)
2323 * Convert a VT_DECIMAL to a VT_I8.
2327 * pi64Out [O] Destination
2331 * Failure: E_INVALIDARG, if the source value is invalid
2332 * DISP_E_OVERFLOW, if the value will not fit in the destination
2334 HRESULT WINAPI
VarI8FromDec(DECIMAL
*pdecIn
, LONG64
* pi64Out
)
2336 if (!DEC_SCALE(pdecIn
))
2338 /* This decimal is just a 96 bit integer */
2339 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2340 return E_INVALIDARG
;
2342 if (DEC_HI32(pdecIn
) || DEC_MID32(pdecIn
) & 0x80000000)
2343 return DISP_E_OVERFLOW
;
2345 if (DEC_SIGN(pdecIn
))
2346 *pi64Out
= -DEC_LO64(pdecIn
);
2348 *pi64Out
= DEC_LO64(pdecIn
);
2353 /* Decimal contains a floating point number */
2357 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2358 if (SUCCEEDED(hRet
))
2359 hRet
= VarI8FromR8(dbl
, pi64Out
);
2364 /************************************************************************
2365 * VarI8FromUI8 (OLEAUT32.427)
2367 * Convert a VT_UI8 to a VT_I8.
2371 * pi64Out [O] Destination
2375 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2377 HRESULT WINAPI
VarI8FromUI8(ULONG64 ullIn
, LONG64
* pi64Out
)
2379 return _VarI8FromUI8(ullIn
, pi64Out
);
2385 /************************************************************************
2386 * VarUI8FromI8 (OLEAUT32.428)
2388 * Convert a VT_I8 to a VT_UI8.
2392 * pui64Out [O] Destination
2396 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2398 HRESULT WINAPI
VarUI8FromI8(LONG64 llIn
, ULONG64
* pui64Out
)
2400 return _VarUI8FromI8(llIn
, pui64Out
);
2403 /************************************************************************
2404 * VarUI8FromUI1 (OLEAUT32.429)
2406 * Convert a VT_UI1 to a VT_UI8.
2410 * pui64Out [O] Destination
2415 HRESULT WINAPI
VarUI8FromUI1(BYTE bIn
, ULONG64
* pui64Out
)
2417 return _VarUI8FromUI1(bIn
, pui64Out
);
2420 /************************************************************************
2421 * VarUI8FromI2 (OLEAUT32.430)
2423 * Convert a VT_I2 to a VT_UI8.
2427 * pui64Out [O] Destination
2432 HRESULT WINAPI
VarUI8FromI2(SHORT sIn
, ULONG64
* pui64Out
)
2434 return _VarUI8FromI2(sIn
, pui64Out
);
2437 /************************************************************************
2438 * VarUI8FromR4 (OLEAUT32.431)
2440 * Convert a VT_R4 to a VT_UI8.
2444 * pui64Out [O] Destination
2448 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2450 HRESULT WINAPI
VarUI8FromR4(FLOAT fltIn
, ULONG64
* pui64Out
)
2452 return VarUI8FromR8(fltIn
, pui64Out
);
2455 /************************************************************************
2456 * VarUI8FromR8 (OLEAUT32.432)
2458 * Convert a VT_R8 to a VT_UI8.
2462 * pui64Out [O] Destination
2466 * Failure: E_INVALIDARG, if the source value is invalid
2467 * DISP_E_OVERFLOW, if the value will not fit in the destination
2470 * See VarI8FromR8() for details concerning rounding.
2472 HRESULT WINAPI
VarUI8FromR8(double dblIn
, ULONG64
* pui64Out
)
2474 if (dblIn
< -0.5 || dblIn
> 1.844674407370955e19
)
2475 return DISP_E_OVERFLOW
;
2476 VARIANT_DutchRound(ULONG64
, dblIn
, *pui64Out
);
2480 /************************************************************************
2481 * VarUI8FromCy (OLEAUT32.433)
2483 * Convert a VT_CY to a VT_UI8.
2487 * pui64Out [O] Destination
2491 * Failure: E_INVALIDARG, if the source value is invalid
2492 * DISP_E_OVERFLOW, if the value will not fit in the destination
2495 * Negative values >= -5000 will be converted to 0.
2497 HRESULT WINAPI
VarUI8FromCy(CY cyIn
, ULONG64
* pui64Out
)
2501 if (cyIn
.int64
< -CY_HALF
)
2502 return DISP_E_OVERFLOW
;
2507 *pui64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2509 cyIn
.int64
-= *pui64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2511 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pui64Out
& 0x1)))
2517 /************************************************************************
2518 * VarUI8FromDate (OLEAUT32.434)
2520 * Convert a VT_DATE to a VT_UI8.
2524 * pui64Out [O] Destination
2528 * Failure: E_INVALIDARG, if the source value is invalid
2529 * DISP_E_OVERFLOW, if the value will not fit in the destination
2530 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2532 HRESULT WINAPI
VarUI8FromDate(DATE dateIn
, ULONG64
* pui64Out
)
2534 return VarUI8FromR8(dateIn
, pui64Out
);
2537 /************************************************************************
2538 * VarUI8FromStr (OLEAUT32.435)
2540 * Convert a VT_BSTR to a VT_UI8.
2544 * lcid [I] LCID for the conversion
2545 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2546 * pui64Out [O] Destination
2550 * Failure: E_INVALIDARG, if the source value is invalid
2551 * DISP_E_OVERFLOW, if the value will not fit in the destination
2552 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2554 HRESULT WINAPI
VarUI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG64
* pui64Out
)
2556 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pui64Out
, VT_UI8
);
2559 /************************************************************************
2560 * VarUI8FromDisp (OLEAUT32.436)
2562 * Convert a VT_DISPATCH to a VT_UI8.
2565 * pdispIn [I] Source
2566 * lcid [I] LCID for conversion
2567 * pui64Out [O] Destination
2571 * Failure: E_INVALIDARG, if the source value is invalid
2572 * DISP_E_OVERFLOW, if the value will not fit in the destination
2573 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2575 HRESULT WINAPI
VarUI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG64
* pui64Out
)
2577 return VARIANT_FromDisp(pdispIn
, lcid
, pui64Out
, VT_UI8
, 0);
2580 /************************************************************************
2581 * VarUI8FromBool (OLEAUT32.437)
2583 * Convert a VT_BOOL to a VT_UI8.
2587 * pui64Out [O] Destination
2591 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2593 HRESULT WINAPI
VarUI8FromBool(VARIANT_BOOL boolIn
, ULONG64
* pui64Out
)
2595 return VarI8FromI2(boolIn
, (LONG64
*)pui64Out
);
2597 /************************************************************************
2598 * VarUI8FromI1 (OLEAUT32.438)
2600 * Convert a VT_I1 to a VT_UI8.
2604 * pui64Out [O] Destination
2608 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2610 HRESULT WINAPI
VarUI8FromI1(signed char cIn
, ULONG64
* pui64Out
)
2612 return _VarUI8FromI1(cIn
, pui64Out
);
2615 /************************************************************************
2616 * VarUI8FromUI2 (OLEAUT32.439)
2618 * Convert a VT_UI2 to a VT_UI8.
2622 * pui64Out [O] Destination
2627 HRESULT WINAPI
VarUI8FromUI2(USHORT usIn
, ULONG64
* pui64Out
)
2629 return _VarUI8FromUI2(usIn
, pui64Out
);
2632 /************************************************************************
2633 * VarUI8FromUI4 (OLEAUT32.440)
2635 * Convert a VT_UI4 to a VT_UI8.
2639 * pui64Out [O] Destination
2644 HRESULT WINAPI
VarUI8FromUI4(ULONG ulIn
, ULONG64
* pui64Out
)
2646 return _VarUI8FromUI4(ulIn
, pui64Out
);
2649 /************************************************************************
2650 * VarUI8FromDec (OLEAUT32.441)
2652 * Convert a VT_DECIMAL to a VT_UI8.
2656 * pui64Out [O] Destination
2660 * Failure: E_INVALIDARG, if the source value is invalid
2661 * DISP_E_OVERFLOW, if the value will not fit in the destination
2664 * Under native Win32, if the source value has a scale of 0, its sign is
2665 * ignored, i.e. this function takes the absolute value rather than fail
2666 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2667 * (use VarAbs() on pDecIn first if you really want this behaviour).
2669 HRESULT WINAPI
VarUI8FromDec(DECIMAL
*pdecIn
, ULONG64
* pui64Out
)
2671 if (!DEC_SCALE(pdecIn
))
2673 /* This decimal is just a 96 bit integer */
2674 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2675 return E_INVALIDARG
;
2677 if (DEC_HI32(pdecIn
))
2678 return DISP_E_OVERFLOW
;
2680 if (DEC_SIGN(pdecIn
))
2682 WARN("Sign would be ignored under Win32!\n");
2683 return DISP_E_OVERFLOW
;
2686 *pui64Out
= DEC_LO64(pdecIn
);
2691 /* Decimal contains a floating point number */
2695 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2696 if (SUCCEEDED(hRet
))
2697 hRet
= VarUI8FromR8(dbl
, pui64Out
);
2705 /************************************************************************
2706 * VarR4FromUI1 (OLEAUT32.68)
2708 * Convert a VT_UI1 to a VT_R4.
2712 * pFltOut [O] Destination
2717 HRESULT WINAPI
VarR4FromUI1(BYTE bIn
, float *pFltOut
)
2719 return _VarR4FromUI1(bIn
, pFltOut
);
2722 /************************************************************************
2723 * VarR4FromI2 (OLEAUT32.69)
2725 * Convert a VT_I2 to a VT_R4.
2729 * pFltOut [O] Destination
2734 HRESULT WINAPI
VarR4FromI2(SHORT sIn
, float *pFltOut
)
2736 return _VarR4FromI2(sIn
, pFltOut
);
2739 /************************************************************************
2740 * VarR4FromI4 (OLEAUT32.70)
2742 * Convert a VT_I4 to a VT_R4.
2746 * pFltOut [O] Destination
2751 HRESULT WINAPI
VarR4FromI4(LONG lIn
, float *pFltOut
)
2753 return _VarR4FromI4(lIn
, pFltOut
);
2756 /************************************************************************
2757 * VarR4FromR8 (OLEAUT32.71)
2759 * Convert a VT_R8 to a VT_R4.
2763 * pFltOut [O] Destination
2767 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2769 HRESULT WINAPI
VarR4FromR8(double dblIn
, float *pFltOut
)
2771 double d
= dblIn
< 0.0 ? -dblIn
: dblIn
;
2772 if (d
> R4_MAX
) return DISP_E_OVERFLOW
;
2777 /************************************************************************
2778 * VarR4FromCy (OLEAUT32.72)
2780 * Convert a VT_CY to a VT_R4.
2784 * pFltOut [O] Destination
2789 HRESULT WINAPI
VarR4FromCy(CY cyIn
, float *pFltOut
)
2791 *pFltOut
= (double)cyIn
.int64
/ CY_MULTIPLIER_F
;
2795 /************************************************************************
2796 * VarR4FromDate (OLEAUT32.73)
2798 * Convert a VT_DATE to a VT_R4.
2802 * pFltOut [O] Destination
2806 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2808 HRESULT WINAPI
VarR4FromDate(DATE dateIn
, float *pFltOut
)
2810 return VarR4FromR8(dateIn
, pFltOut
);
2813 /************************************************************************
2814 * VarR4FromStr (OLEAUT32.74)
2816 * Convert a VT_BSTR to a VT_R4.
2820 * lcid [I] LCID for the conversion
2821 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2822 * pFltOut [O] Destination
2826 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2827 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2829 HRESULT WINAPI
VarR4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, float *pFltOut
)
2831 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pFltOut
, VT_R4
);
2834 /************************************************************************
2835 * VarR4FromDisp (OLEAUT32.75)
2837 * Convert a VT_DISPATCH to a VT_R4.
2840 * pdispIn [I] Source
2841 * lcid [I] LCID for conversion
2842 * pFltOut [O] Destination
2846 * Failure: E_INVALIDARG, if the source value is invalid
2847 * DISP_E_OVERFLOW, if the value will not fit in the destination
2848 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2850 HRESULT WINAPI
VarR4FromDisp(IDispatch
* pdispIn
, LCID lcid
, float *pFltOut
)
2852 return VARIANT_FromDisp(pdispIn
, lcid
, pFltOut
, VT_R4
, 0);
2855 /************************************************************************
2856 * VarR4FromBool (OLEAUT32.76)
2858 * Convert a VT_BOOL to a VT_R4.
2862 * pFltOut [O] Destination
2867 HRESULT WINAPI
VarR4FromBool(VARIANT_BOOL boolIn
, float *pFltOut
)
2869 return VarR4FromI2(boolIn
, pFltOut
);
2872 /************************************************************************
2873 * VarR4FromI1 (OLEAUT32.213)
2875 * Convert a VT_I1 to a VT_R4.
2879 * pFltOut [O] Destination
2883 * Failure: E_INVALIDARG, if the source value is invalid
2884 * DISP_E_OVERFLOW, if the value will not fit in the destination
2885 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2887 HRESULT WINAPI
VarR4FromI1(signed char cIn
, float *pFltOut
)
2889 return _VarR4FromI1(cIn
, pFltOut
);
2892 /************************************************************************
2893 * VarR4FromUI2 (OLEAUT32.214)
2895 * Convert a VT_UI2 to a VT_R4.
2899 * pFltOut [O] Destination
2903 * Failure: E_INVALIDARG, if the source value is invalid
2904 * DISP_E_OVERFLOW, if the value will not fit in the destination
2905 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2907 HRESULT WINAPI
VarR4FromUI2(USHORT usIn
, float *pFltOut
)
2909 return _VarR4FromUI2(usIn
, pFltOut
);
2912 /************************************************************************
2913 * VarR4FromUI4 (OLEAUT32.215)
2915 * Convert a VT_UI4 to a VT_R4.
2919 * pFltOut [O] Destination
2923 * Failure: E_INVALIDARG, if the source value is invalid
2924 * DISP_E_OVERFLOW, if the value will not fit in the destination
2925 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2927 HRESULT WINAPI
VarR4FromUI4(ULONG ulIn
, float *pFltOut
)
2929 return _VarR4FromUI4(ulIn
, pFltOut
);
2932 /************************************************************************
2933 * VarR4FromDec (OLEAUT32.216)
2935 * Convert a VT_DECIMAL to a VT_R4.
2939 * pFltOut [O] Destination
2943 * Failure: E_INVALIDARG, if the source value is invalid.
2945 HRESULT WINAPI
VarR4FromDec(DECIMAL
* pDecIn
, float *pFltOut
)
2947 BYTE scale
= DEC_SCALE(pDecIn
);
2948 double divisor
= 1.0;
2951 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
2952 return E_INVALIDARG
;
2957 if (DEC_SIGN(pDecIn
))
2960 if (DEC_HI32(pDecIn
))
2962 highPart
= (double)DEC_HI32(pDecIn
) / divisor
;
2963 highPart
*= 4294967296.0F
;
2964 highPart
*= 4294967296.0F
;
2969 *pFltOut
= (double)DEC_LO64(pDecIn
) / divisor
+ highPart
;
2973 /************************************************************************
2974 * VarR4FromI8 (OLEAUT32.360)
2976 * Convert a VT_I8 to a VT_R4.
2980 * pFltOut [O] Destination
2985 HRESULT WINAPI
VarR4FromI8(LONG64 llIn
, float *pFltOut
)
2987 return _VarR4FromI8(llIn
, pFltOut
);
2990 /************************************************************************
2991 * VarR4FromUI8 (OLEAUT32.361)
2993 * Convert a VT_UI8 to a VT_R4.
2997 * pFltOut [O] Destination
3002 HRESULT WINAPI
VarR4FromUI8(ULONG64 ullIn
, float *pFltOut
)
3004 return _VarR4FromUI8(ullIn
, pFltOut
);
3007 /************************************************************************
3008 * VarR4CmpR8 (OLEAUT32.316)
3010 * Compare a VT_R4 to a VT_R8.
3013 * fltLeft [I] Source
3014 * dblRight [I] Value to compare
3017 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3018 * equal to or greater than dblRight respectively.
3020 HRESULT WINAPI
VarR4CmpR8(float fltLeft
, double dblRight
)
3022 if (fltLeft
< dblRight
)
3024 else if (fltLeft
> dblRight
)
3032 /************************************************************************
3033 * VarR8FromUI1 (OLEAUT32.78)
3035 * Convert a VT_UI1 to a VT_R8.
3039 * pDblOut [O] Destination
3044 HRESULT WINAPI
VarR8FromUI1(BYTE bIn
, double *pDblOut
)
3046 return _VarR8FromUI1(bIn
, pDblOut
);
3049 /************************************************************************
3050 * VarR8FromI2 (OLEAUT32.79)
3052 * Convert a VT_I2 to a VT_R8.
3056 * pDblOut [O] Destination
3061 HRESULT WINAPI
VarR8FromI2(SHORT sIn
, double *pDblOut
)
3063 return _VarR8FromI2(sIn
, pDblOut
);
3066 /************************************************************************
3067 * VarR8FromI4 (OLEAUT32.80)
3069 * Convert a VT_I4 to a VT_R8.
3073 * pDblOut [O] Destination
3078 HRESULT WINAPI
VarR8FromI4(LONG lIn
, double *pDblOut
)
3080 return _VarR8FromI4(lIn
, pDblOut
);
3083 /************************************************************************
3084 * VarR8FromR4 (OLEAUT32.81)
3086 * Convert a VT_R4 to a VT_R8.
3090 * pDblOut [O] Destination
3095 HRESULT WINAPI
VarR8FromR4(FLOAT fltIn
, double *pDblOut
)
3097 return _VarR8FromR4(fltIn
, pDblOut
);
3100 /************************************************************************
3101 * VarR8FromCy (OLEAUT32.82)
3103 * Convert a VT_CY to a VT_R8.
3107 * pDblOut [O] Destination
3112 HRESULT WINAPI
VarR8FromCy(CY cyIn
, double *pDblOut
)
3114 return _VarR8FromCy(cyIn
, pDblOut
);
3117 /************************************************************************
3118 * VarR8FromDate (OLEAUT32.83)
3120 * Convert a VT_DATE to a VT_R8.
3124 * pDblOut [O] Destination
3129 HRESULT WINAPI
VarR8FromDate(DATE dateIn
, double *pDblOut
)
3131 return _VarR8FromDate(dateIn
, pDblOut
);
3134 /************************************************************************
3135 * VarR8FromStr (OLEAUT32.84)
3137 * Convert a VT_BSTR to a VT_R8.
3141 * lcid [I] LCID for the conversion
3142 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3143 * pDblOut [O] Destination
3147 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3148 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3150 HRESULT WINAPI
VarR8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, double *pDblOut
)
3152 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDblOut
, VT_R8
);
3155 /************************************************************************
3156 * VarR8FromDisp (OLEAUT32.85)
3158 * Convert a VT_DISPATCH to a VT_R8.
3161 * pdispIn [I] Source
3162 * lcid [I] LCID for conversion
3163 * pDblOut [O] Destination
3167 * Failure: E_INVALIDARG, if the source value is invalid
3168 * DISP_E_OVERFLOW, if the value will not fit in the destination
3169 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3171 HRESULT WINAPI
VarR8FromDisp(IDispatch
* pdispIn
, LCID lcid
, double *pDblOut
)
3173 return VARIANT_FromDisp(pdispIn
, lcid
, pDblOut
, VT_R8
, 0);
3176 /************************************************************************
3177 * VarR8FromBool (OLEAUT32.86)
3179 * Convert a VT_BOOL to a VT_R8.
3183 * pDblOut [O] Destination
3188 HRESULT WINAPI
VarR8FromBool(VARIANT_BOOL boolIn
, double *pDblOut
)
3190 return VarR8FromI2(boolIn
, pDblOut
);
3193 /************************************************************************
3194 * VarR8FromI1 (OLEAUT32.217)
3196 * Convert a VT_I1 to a VT_R8.
3200 * pDblOut [O] Destination
3204 * Failure: E_INVALIDARG, if the source value is invalid
3205 * DISP_E_OVERFLOW, if the value will not fit in the destination
3206 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3208 HRESULT WINAPI
VarR8FromI1(signed char cIn
, double *pDblOut
)
3210 return _VarR8FromI1(cIn
, pDblOut
);
3213 /************************************************************************
3214 * VarR8FromUI2 (OLEAUT32.218)
3216 * Convert a VT_UI2 to a VT_R8.
3220 * pDblOut [O] Destination
3224 * Failure: E_INVALIDARG, if the source value is invalid
3225 * DISP_E_OVERFLOW, if the value will not fit in the destination
3226 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3228 HRESULT WINAPI
VarR8FromUI2(USHORT usIn
, double *pDblOut
)
3230 return _VarR8FromUI2(usIn
, pDblOut
);
3233 /************************************************************************
3234 * VarR8FromUI4 (OLEAUT32.219)
3236 * Convert a VT_UI4 to a VT_R8.
3240 * pDblOut [O] Destination
3244 * Failure: E_INVALIDARG, if the source value is invalid
3245 * DISP_E_OVERFLOW, if the value will not fit in the destination
3246 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3248 HRESULT WINAPI
VarR8FromUI4(ULONG ulIn
, double *pDblOut
)
3250 return _VarR8FromUI4(ulIn
, pDblOut
);
3253 /************************************************************************
3254 * VarR8FromDec (OLEAUT32.220)
3256 * Convert a VT_DECIMAL to a VT_R8.
3260 * pDblOut [O] Destination
3264 * Failure: E_INVALIDARG, if the source value is invalid.
3266 HRESULT WINAPI
VarR8FromDec(const DECIMAL
* pDecIn
, double *pDblOut
)
3268 BYTE scale
= DEC_SCALE(pDecIn
);
3269 double divisor
= 1.0, highPart
;
3271 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
3272 return E_INVALIDARG
;
3277 if (DEC_SIGN(pDecIn
))
3280 if (DEC_HI32(pDecIn
))
3282 highPart
= (double)DEC_HI32(pDecIn
) / divisor
;
3283 highPart
*= 4294967296.0F
;
3284 highPart
*= 4294967296.0F
;
3289 *pDblOut
= (double)DEC_LO64(pDecIn
) / divisor
+ highPart
;
3293 /************************************************************************
3294 * VarR8FromI8 (OLEAUT32.362)
3296 * Convert a VT_I8 to a VT_R8.
3300 * pDblOut [O] Destination
3305 HRESULT WINAPI
VarR8FromI8(LONG64 llIn
, double *pDblOut
)
3307 return _VarR8FromI8(llIn
, pDblOut
);
3310 /************************************************************************
3311 * VarR8FromUI8 (OLEAUT32.363)
3313 * Convert a VT_UI8 to a VT_R8.
3317 * pDblOut [O] Destination
3322 HRESULT WINAPI
VarR8FromUI8(ULONG64 ullIn
, double *pDblOut
)
3324 return _VarR8FromUI8(ullIn
, pDblOut
);
3327 /************************************************************************
3328 * VarR8Pow (OLEAUT32.315)
3330 * Raise a VT_R8 to a power.
3333 * dblLeft [I] Source
3334 * dblPow [I] Power to raise dblLeft by
3335 * pDblOut [O] Destination
3338 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3340 HRESULT WINAPI
VarR8Pow(double dblLeft
, double dblPow
, double *pDblOut
)
3342 *pDblOut
= pow(dblLeft
, dblPow
);
3346 /************************************************************************
3347 * VarR8Round (OLEAUT32.317)
3349 * Round a VT_R8 to a given number of decimal points.
3353 * nDig [I] Number of decimal points to round to
3354 * pDblOut [O] Destination for rounded number
3357 * Success: S_OK. pDblOut is rounded to nDig digits.
3358 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3361 * The native version of this function rounds using the internal
3362 * binary representation of the number. Wine uses the dutch rounding
3363 * convention, so therefore small differences can occur in the value returned.
3364 * MSDN says that you should use your own rounding function if you want
3365 * rounding to be predictable in your application.
3367 HRESULT WINAPI
VarR8Round(double dblIn
, int nDig
, double *pDblOut
)
3369 double scale
, whole
, fract
;
3372 return E_INVALIDARG
;
3374 scale
= pow(10.0, nDig
);
3377 whole
= dblIn
< 0 ? ceil(dblIn
) : floor(dblIn
);
3378 fract
= dblIn
- whole
;
3381 dblIn
= whole
+ 1.0;
3382 else if (fract
== 0.5)
3383 dblIn
= whole
+ fmod(whole
, 2.0);
3384 else if (fract
>= 0.0)
3386 else if (fract
== -0.5)
3387 dblIn
= whole
- fmod(whole
, 2.0);
3388 else if (fract
> -0.5)
3391 dblIn
= whole
- 1.0;
3393 *pDblOut
= dblIn
/ scale
;
3400 /* Powers of 10 from 0..4 D.P. */
3401 static const int CY_Divisors
[5] = { CY_MULTIPLIER
/10000, CY_MULTIPLIER
/1000,
3402 CY_MULTIPLIER
/100, CY_MULTIPLIER
/10, CY_MULTIPLIER
};
3404 /************************************************************************
3405 * VarCyFromUI1 (OLEAUT32.98)
3407 * Convert a VT_UI1 to a VT_CY.
3411 * pCyOut [O] Destination
3415 * Failure: E_INVALIDARG, if the source value is invalid
3416 * DISP_E_OVERFLOW, if the value will not fit in the destination
3417 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3419 HRESULT WINAPI
VarCyFromUI1(BYTE bIn
, CY
* pCyOut
)
3421 pCyOut
->int64
= (ULONG64
)bIn
* CY_MULTIPLIER
;
3425 /************************************************************************
3426 * VarCyFromI2 (OLEAUT32.99)
3428 * Convert a VT_I2 to a VT_CY.
3432 * pCyOut [O] Destination
3436 * Failure: E_INVALIDARG, if the source value is invalid
3437 * DISP_E_OVERFLOW, if the value will not fit in the destination
3438 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3440 HRESULT WINAPI
VarCyFromI2(SHORT sIn
, CY
* pCyOut
)
3442 pCyOut
->int64
= (LONG64
)sIn
* CY_MULTIPLIER
;
3446 /************************************************************************
3447 * VarCyFromI4 (OLEAUT32.100)
3449 * Convert a VT_I4 to a VT_CY.
3453 * pCyOut [O] Destination
3457 * Failure: E_INVALIDARG, if the source value is invalid
3458 * DISP_E_OVERFLOW, if the value will not fit in the destination
3459 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3461 HRESULT WINAPI
VarCyFromI4(LONG lIn
, CY
* pCyOut
)
3463 pCyOut
->int64
= (LONG64
)lIn
* CY_MULTIPLIER
;
3467 /************************************************************************
3468 * VarCyFromR4 (OLEAUT32.101)
3470 * Convert a VT_R4 to a VT_CY.
3474 * pCyOut [O] Destination
3478 * Failure: E_INVALIDARG, if the source value is invalid
3479 * DISP_E_OVERFLOW, if the value will not fit in the destination
3480 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3482 HRESULT WINAPI
VarCyFromR4(FLOAT fltIn
, CY
* pCyOut
)
3484 return VarCyFromR8(fltIn
, pCyOut
);
3487 /************************************************************************
3488 * VarCyFromR8 (OLEAUT32.102)
3490 * Convert a VT_R8 to a VT_CY.
3494 * pCyOut [O] Destination
3498 * Failure: E_INVALIDARG, if the source value is invalid
3499 * DISP_E_OVERFLOW, if the value will not fit in the destination
3500 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3502 HRESULT WINAPI
VarCyFromR8(double dblIn
, CY
* pCyOut
)
3504 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3505 /* This code gives identical results to Win32 on Intel.
3506 * Here we use fp exceptions to catch overflows when storing the value.
3508 static const unsigned short r8_fpcontrol
= 0x137f;
3509 static const double r8_multiplier
= CY_MULTIPLIER_F
;
3510 unsigned short old_fpcontrol
, result_fpstatus
;
3512 /* Clear exceptions, save the old fp state and load the new state */
3513 __asm__
__volatile__( "fnclex" );
3514 __asm__
__volatile__( "fstcw %0" : "=m" (old_fpcontrol
) : );
3515 __asm__
__volatile__( "fldcw %0" : : "m" (r8_fpcontrol
) );
3516 /* Perform the conversion. */
3517 __asm__
__volatile__( "fldl %0" : : "m" (dblIn
) );
3518 __asm__
__volatile__( "fmull %0" : : "m" (r8_multiplier
) );
3519 __asm__
__volatile__( "fistpll %0" : : "m" (*pCyOut
) );
3520 /* Save the resulting fp state, load the old state and clear exceptions */
3521 __asm__
__volatile__( "fstsw %0" : "=m" (result_fpstatus
) : );
3522 __asm__
__volatile__( "fnclex" );
3523 __asm__
__volatile__( "fldcw %0" : : "m" (old_fpcontrol
) );
3525 if (result_fpstatus
& 0x9) /* Overflow | Invalid */
3526 return DISP_E_OVERFLOW
;
3528 /* This version produces slightly different results for boundary cases */
3529 if (dblIn
< -922337203685477.5807 || dblIn
>= 922337203685477.5807)
3530 return DISP_E_OVERFLOW
;
3531 dblIn
*= CY_MULTIPLIER_F
;
3532 VARIANT_DutchRound(LONG64
, dblIn
, pCyOut
->int64
);
3537 /************************************************************************
3538 * VarCyFromDate (OLEAUT32.103)
3540 * Convert a VT_DATE to a VT_CY.
3544 * pCyOut [O] Destination
3548 * Failure: E_INVALIDARG, if the source value is invalid
3549 * DISP_E_OVERFLOW, if the value will not fit in the destination
3550 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3552 HRESULT WINAPI
VarCyFromDate(DATE dateIn
, CY
* pCyOut
)
3554 return VarCyFromR8(dateIn
, pCyOut
);
3557 /************************************************************************
3558 * VarCyFromStr (OLEAUT32.104)
3560 * Convert a VT_BSTR to a VT_CY.
3564 * lcid [I] LCID for the conversion
3565 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3566 * pCyOut [O] Destination
3570 * Failure: E_INVALIDARG, if the source value is invalid
3571 * DISP_E_OVERFLOW, if the value will not fit in the destination
3572 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3574 HRESULT WINAPI
VarCyFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, CY
* pCyOut
)
3576 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pCyOut
, VT_CY
);
3579 /************************************************************************
3580 * VarCyFromDisp (OLEAUT32.105)
3582 * Convert a VT_DISPATCH to a VT_CY.
3585 * pdispIn [I] Source
3586 * lcid [I] LCID for conversion
3587 * pCyOut [O] Destination
3591 * Failure: E_INVALIDARG, if the source value is invalid
3592 * DISP_E_OVERFLOW, if the value will not fit in the destination
3593 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3595 HRESULT WINAPI
VarCyFromDisp(IDispatch
* pdispIn
, LCID lcid
, CY
* pCyOut
)
3597 return VARIANT_FromDisp(pdispIn
, lcid
, pCyOut
, VT_CY
, 0);
3600 /************************************************************************
3601 * VarCyFromBool (OLEAUT32.106)
3603 * Convert a VT_BOOL to a VT_CY.
3607 * pCyOut [O] Destination
3611 * Failure: E_INVALIDARG, if the source value is invalid
3612 * DISP_E_OVERFLOW, if the value will not fit in the destination
3613 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3616 * While the sign of the boolean is stored in the currency, the value is
3617 * converted to either 0 or 1.
3619 HRESULT WINAPI
VarCyFromBool(VARIANT_BOOL boolIn
, CY
* pCyOut
)
3621 pCyOut
->int64
= (LONG64
)boolIn
* CY_MULTIPLIER
;
3625 /************************************************************************
3626 * VarCyFromI1 (OLEAUT32.225)
3628 * Convert a VT_I1 to a VT_CY.
3632 * pCyOut [O] Destination
3636 * Failure: E_INVALIDARG, if the source value is invalid
3637 * DISP_E_OVERFLOW, if the value will not fit in the destination
3638 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3640 HRESULT WINAPI
VarCyFromI1(signed char cIn
, CY
* pCyOut
)
3642 pCyOut
->int64
= (LONG64
)cIn
* CY_MULTIPLIER
;
3646 /************************************************************************
3647 * VarCyFromUI2 (OLEAUT32.226)
3649 * Convert a VT_UI2 to a VT_CY.
3653 * pCyOut [O] Destination
3657 * Failure: E_INVALIDARG, if the source value is invalid
3658 * DISP_E_OVERFLOW, if the value will not fit in the destination
3659 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3661 HRESULT WINAPI
VarCyFromUI2(USHORT usIn
, CY
* pCyOut
)
3663 pCyOut
->int64
= (ULONG64
)usIn
* CY_MULTIPLIER
;
3667 /************************************************************************
3668 * VarCyFromUI4 (OLEAUT32.227)
3670 * Convert a VT_UI4 to a VT_CY.
3674 * pCyOut [O] Destination
3678 * Failure: E_INVALIDARG, if the source value is invalid
3679 * DISP_E_OVERFLOW, if the value will not fit in the destination
3680 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3682 HRESULT WINAPI
VarCyFromUI4(ULONG ulIn
, CY
* pCyOut
)
3684 pCyOut
->int64
= (ULONG64
)ulIn
* CY_MULTIPLIER
;
3688 /************************************************************************
3689 * VarCyFromDec (OLEAUT32.228)
3691 * Convert a VT_DECIMAL to a VT_CY.
3695 * pCyOut [O] Destination
3699 * Failure: E_INVALIDARG, if the source value is invalid
3700 * DISP_E_OVERFLOW, if the value will not fit in the destination
3701 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3703 HRESULT WINAPI
VarCyFromDec(DECIMAL
* pdecIn
, CY
* pCyOut
)
3708 hRet
= VarDecRound(pdecIn
, 4, &rounded
);
3710 if (SUCCEEDED(hRet
))
3714 if (DEC_HI32(&rounded
))
3715 return DISP_E_OVERFLOW
;
3717 /* Note: Without the casts this promotes to int64 which loses precision */
3718 d
= (double)DEC_LO64(&rounded
) / (double)CY_Divisors
[DEC_SCALE(&rounded
)];
3719 if (DEC_SIGN(&rounded
))
3721 return VarCyFromR8(d
, pCyOut
);
3726 /************************************************************************
3727 * VarCyFromI8 (OLEAUT32.366)
3729 * Convert a VT_I8 to a VT_CY.
3733 * pCyOut [O] Destination
3737 * Failure: E_INVALIDARG, if the source value is invalid
3738 * DISP_E_OVERFLOW, if the value will not fit in the destination
3739 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3741 HRESULT WINAPI
VarCyFromI8(LONG64 llIn
, CY
* pCyOut
)
3743 if (llIn
<= (I8_MIN
/CY_MULTIPLIER
) || llIn
>= (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3744 pCyOut
->int64
= llIn
* CY_MULTIPLIER
;
3748 /************************************************************************
3749 * VarCyFromUI8 (OLEAUT32.375)
3751 * Convert a VT_UI8 to a VT_CY.
3755 * pCyOut [O] Destination
3759 * Failure: E_INVALIDARG, if the source value is invalid
3760 * DISP_E_OVERFLOW, if the value will not fit in the destination
3761 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3763 HRESULT WINAPI
VarCyFromUI8(ULONG64 ullIn
, CY
* pCyOut
)
3765 if (ullIn
> (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3766 pCyOut
->int64
= ullIn
* CY_MULTIPLIER
;
3770 /************************************************************************
3771 * VarCyAdd (OLEAUT32.299)
3773 * Add one CY to another.
3777 * cyRight [I] Value to add
3778 * pCyOut [O] Destination
3782 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3784 HRESULT WINAPI
VarCyAdd(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3787 _VarR8FromCy(cyLeft
, &l
);
3788 _VarR8FromCy(cyRight
, &r
);
3790 return VarCyFromR8(l
, pCyOut
);
3793 /************************************************************************
3794 * VarCyMul (OLEAUT32.303)
3796 * Multiply one CY by another.
3800 * cyRight [I] Value to multiply by
3801 * pCyOut [O] Destination
3805 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3807 HRESULT WINAPI
VarCyMul(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3810 _VarR8FromCy(cyLeft
, &l
);
3811 _VarR8FromCy(cyRight
, &r
);
3813 return VarCyFromR8(l
, pCyOut
);
3816 /************************************************************************
3817 * VarCyMulI4 (OLEAUT32.304)
3819 * Multiply one CY by a VT_I4.
3823 * lRight [I] Value to multiply by
3824 * pCyOut [O] Destination
3828 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3830 HRESULT WINAPI
VarCyMulI4(const CY cyLeft
, LONG lRight
, CY
* pCyOut
)
3834 _VarR8FromCy(cyLeft
, &d
);
3836 return VarCyFromR8(d
, pCyOut
);
3839 /************************************************************************
3840 * VarCySub (OLEAUT32.305)
3842 * Subtract one CY from another.
3846 * cyRight [I] Value to subtract
3847 * pCyOut [O] Destination
3851 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3853 HRESULT WINAPI
VarCySub(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3856 _VarR8FromCy(cyLeft
, &l
);
3857 _VarR8FromCy(cyRight
, &r
);
3859 return VarCyFromR8(l
, pCyOut
);
3862 /************************************************************************
3863 * VarCyAbs (OLEAUT32.306)
3865 * Convert a VT_CY into its absolute value.
3869 * pCyOut [O] Destination
3872 * Success: S_OK. pCyOut contains the absolute value.
3873 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3875 HRESULT WINAPI
VarCyAbs(const CY cyIn
, CY
* pCyOut
)
3877 if (cyIn
.s
.Hi
== (int)0x80000000 && !cyIn
.s
.Lo
)
3878 return DISP_E_OVERFLOW
;
3880 pCyOut
->int64
= cyIn
.int64
< 0 ? -cyIn
.int64
: cyIn
.int64
;
3884 /************************************************************************
3885 * VarCyFix (OLEAUT32.307)
3887 * Return the integer part of a VT_CY.
3891 * pCyOut [O] Destination
3895 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3898 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3899 * negative numbers away from 0, while this function rounds them towards zero.
3901 HRESULT WINAPI
VarCyFix(const CY cyIn
, CY
* pCyOut
)
3903 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3904 pCyOut
->int64
*= CY_MULTIPLIER
;
3908 /************************************************************************
3909 * VarCyInt (OLEAUT32.308)
3911 * Return the integer part of a VT_CY.
3915 * pCyOut [O] Destination
3919 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3922 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3923 * negative numbers towards 0, while this function rounds them away from zero.
3925 HRESULT WINAPI
VarCyInt(const CY cyIn
, CY
* pCyOut
)
3927 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3928 pCyOut
->int64
*= CY_MULTIPLIER
;
3930 if (cyIn
.int64
< 0 && cyIn
.int64
% CY_MULTIPLIER
!= 0)
3932 pCyOut
->int64
-= CY_MULTIPLIER
;
3937 /************************************************************************
3938 * VarCyNeg (OLEAUT32.309)
3940 * Change the sign of a VT_CY.
3944 * pCyOut [O] Destination
3948 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3950 HRESULT WINAPI
VarCyNeg(const CY cyIn
, CY
* pCyOut
)
3952 if (cyIn
.s
.Hi
== (int)0x80000000 && !cyIn
.s
.Lo
)
3953 return DISP_E_OVERFLOW
;
3955 pCyOut
->int64
= -cyIn
.int64
;
3959 /************************************************************************
3960 * VarCyRound (OLEAUT32.310)
3962 * Change the precision of a VT_CY.
3966 * cDecimals [I] New number of decimals to keep
3967 * pCyOut [O] Destination
3971 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3973 HRESULT WINAPI
VarCyRound(const CY cyIn
, int cDecimals
, CY
* pCyOut
)
3976 return E_INVALIDARG
;
3980 /* Rounding to more precision than we have */
3986 double d
, div
= CY_Divisors
[cDecimals
];
3988 _VarR8FromCy(cyIn
, &d
);
3990 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
3991 d
= (double)pCyOut
->int64
/ div
* CY_MULTIPLIER_F
;
3992 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
3997 /************************************************************************
3998 * VarCyCmp (OLEAUT32.311)
4000 * Compare two VT_CY values.
4004 * cyRight [I] Value to compare
4007 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4008 * compare is less, equal or greater than source respectively.
4009 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4011 HRESULT WINAPI
VarCyCmp(const CY cyLeft
, const CY cyRight
)
4016 /* Subtract right from left, and compare the result to 0 */
4017 hRet
= VarCySub(cyLeft
, cyRight
, &result
);
4019 if (SUCCEEDED(hRet
))
4021 if (result
.int64
< 0)
4022 hRet
= (HRESULT
)VARCMP_LT
;
4023 else if (result
.int64
> 0)
4024 hRet
= (HRESULT
)VARCMP_GT
;
4026 hRet
= (HRESULT
)VARCMP_EQ
;
4031 /************************************************************************
4032 * VarCyCmpR8 (OLEAUT32.312)
4034 * Compare a VT_CY to a double
4037 * cyLeft [I] Currency Source
4038 * dblRight [I] double to compare to cyLeft
4041 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4042 * less than, equal to or greater than cyLeft respectively.
4043 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4045 HRESULT WINAPI
VarCyCmpR8(const CY cyLeft
, double dblRight
)
4050 hRet
= VarCyFromR8(dblRight
, &cyRight
);
4052 if (SUCCEEDED(hRet
))
4053 hRet
= VarCyCmp(cyLeft
, cyRight
);
4058 /************************************************************************
4059 * VarCyMulI8 (OLEAUT32.329)
4061 * Multiply a VT_CY by a VT_I8.
4065 * llRight [I] Value to multiply by
4066 * pCyOut [O] Destination
4070 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4072 HRESULT WINAPI
VarCyMulI8(const CY cyLeft
, LONG64 llRight
, CY
* pCyOut
)
4076 _VarR8FromCy(cyLeft
, &d
);
4077 d
= d
* (double)llRight
;
4078 return VarCyFromR8(d
, pCyOut
);
4084 /************************************************************************
4085 * VarDecFromUI1 (OLEAUT32.190)
4087 * Convert a VT_UI1 to a DECIMAL.
4091 * pDecOut [O] Destination
4096 HRESULT WINAPI
VarDecFromUI1(BYTE bIn
, DECIMAL
* pDecOut
)
4098 return VarDecFromUI4(bIn
, pDecOut
);
4101 /************************************************************************
4102 * VarDecFromI2 (OLEAUT32.191)
4104 * Convert a VT_I2 to a DECIMAL.
4108 * pDecOut [O] Destination
4113 HRESULT WINAPI
VarDecFromI2(SHORT sIn
, DECIMAL
* pDecOut
)
4115 return VarDecFromI4(sIn
, pDecOut
);
4118 /************************************************************************
4119 * VarDecFromI4 (OLEAUT32.192)
4121 * Convert a VT_I4 to a DECIMAL.
4125 * pDecOut [O] Destination
4130 HRESULT WINAPI
VarDecFromI4(LONG lIn
, DECIMAL
* pDecOut
)
4132 DEC_HI32(pDecOut
) = 0;
4133 DEC_MID32(pDecOut
) = 0;
4137 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4138 DEC_LO32(pDecOut
) = -lIn
;
4142 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4143 DEC_LO32(pDecOut
) = lIn
;
4148 /* internal representation of the value stored in a DECIMAL. The bytes are
4149 stored from LSB at index 0 to MSB at index 11
4151 typedef struct DECIMAL_internal
4153 DWORD bitsnum
[3]; /* 96 significant bits, unsigned */
4154 unsigned char scale
; /* number scaled * 10 ^ -(scale) */
4155 unsigned int sign
: 1; /* 0 - positive, 1 - negative */
4158 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
);
4159 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
);
4160 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
);
4161 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
);
4162 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
);
4163 static BOOL
VARIANT_int_iszero(const DWORD
* p
, unsigned int n
);
4165 /************************************************************************
4166 * VarDecFromR4 (OLEAUT32.193)
4168 * Convert a VT_R4 to a DECIMAL.
4172 * pDecOut [O] Destination
4177 HRESULT WINAPI
VarDecFromR4(FLOAT fltIn
, DECIMAL
* pDecOut
)
4182 hres
= VARIANT_DI_FromR4(fltIn
, &di
);
4183 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4187 /************************************************************************
4188 * VarDecFromR8 (OLEAUT32.194)
4190 * Convert a VT_R8 to a DECIMAL.
4194 * pDecOut [O] Destination
4199 HRESULT WINAPI
VarDecFromR8(double dblIn
, DECIMAL
* pDecOut
)
4204 hres
= VARIANT_DI_FromR8(dblIn
, &di
);
4205 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4209 /************************************************************************
4210 * VarDecFromDate (OLEAUT32.195)
4212 * Convert a VT_DATE to a DECIMAL.
4216 * pDecOut [O] Destination
4221 HRESULT WINAPI
VarDecFromDate(DATE dateIn
, DECIMAL
* pDecOut
)
4223 return VarDecFromR8(dateIn
, pDecOut
);
4226 /************************************************************************
4227 * VarDecFromCy (OLEAUT32.196)
4229 * Convert a VT_CY to a DECIMAL.
4233 * pDecOut [O] Destination
4238 HRESULT WINAPI
VarDecFromCy(CY cyIn
, DECIMAL
* pDecOut
)
4240 DEC_HI32(pDecOut
) = 0;
4242 /* Note: This assumes 2s complement integer representation */
4243 if (cyIn
.s
.Hi
& 0x80000000)
4245 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,4);
4246 DEC_LO64(pDecOut
) = -cyIn
.int64
;
4250 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,4);
4251 DEC_MID32(pDecOut
) = cyIn
.s
.Hi
;
4252 DEC_LO32(pDecOut
) = cyIn
.s
.Lo
;
4257 /************************************************************************
4258 * VarDecFromStr (OLEAUT32.197)
4260 * Convert a VT_BSTR to a DECIMAL.
4264 * lcid [I] LCID for the conversion
4265 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4266 * pDecOut [O] Destination
4270 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4272 HRESULT WINAPI
VarDecFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DECIMAL
* pDecOut
)
4274 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDecOut
, VT_DECIMAL
);
4277 /************************************************************************
4278 * VarDecFromDisp (OLEAUT32.198)
4280 * Convert a VT_DISPATCH to a DECIMAL.
4283 * pdispIn [I] Source
4284 * lcid [I] LCID for conversion
4285 * pDecOut [O] Destination
4289 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4291 HRESULT WINAPI
VarDecFromDisp(IDispatch
* pdispIn
, LCID lcid
, DECIMAL
* pDecOut
)
4293 return VARIANT_FromDisp(pdispIn
, lcid
, pDecOut
, VT_DECIMAL
, 0);
4296 /************************************************************************
4297 * VarDecFromBool (OLEAUT32.199)
4299 * Convert a VT_BOOL to a DECIMAL.
4303 * pDecOut [O] Destination
4309 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4311 HRESULT WINAPI
VarDecFromBool(VARIANT_BOOL bIn
, DECIMAL
* pDecOut
)
4313 DEC_HI32(pDecOut
) = 0;
4314 DEC_MID32(pDecOut
) = 0;
4317 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4318 DEC_LO32(pDecOut
) = 1;
4322 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4323 DEC_LO32(pDecOut
) = 0;
4328 /************************************************************************
4329 * VarDecFromI1 (OLEAUT32.241)
4331 * Convert a VT_I1 to a DECIMAL.
4335 * pDecOut [O] Destination
4340 HRESULT WINAPI
VarDecFromI1(signed char cIn
, DECIMAL
* pDecOut
)
4342 return VarDecFromI4(cIn
, pDecOut
);
4345 /************************************************************************
4346 * VarDecFromUI2 (OLEAUT32.242)
4348 * Convert a VT_UI2 to a DECIMAL.
4352 * pDecOut [O] Destination
4357 HRESULT WINAPI
VarDecFromUI2(USHORT usIn
, DECIMAL
* pDecOut
)
4359 return VarDecFromUI4(usIn
, pDecOut
);
4362 /************************************************************************
4363 * VarDecFromUI4 (OLEAUT32.243)
4365 * Convert a VT_UI4 to a DECIMAL.
4369 * pDecOut [O] Destination
4374 HRESULT WINAPI
VarDecFromUI4(ULONG ulIn
, DECIMAL
* pDecOut
)
4376 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4377 DEC_HI32(pDecOut
) = 0;
4378 DEC_MID32(pDecOut
) = 0;
4379 DEC_LO32(pDecOut
) = ulIn
;
4383 /************************************************************************
4384 * VarDecFromI8 (OLEAUT32.374)
4386 * Convert a VT_I8 to a DECIMAL.
4390 * pDecOut [O] Destination
4395 HRESULT WINAPI
VarDecFromI8(LONG64 llIn
, DECIMAL
* pDecOut
)
4397 PULARGE_INTEGER pLi
= (PULARGE_INTEGER
)&llIn
;
4399 DEC_HI32(pDecOut
) = 0;
4401 /* Note: This assumes 2s complement integer representation */
4402 if (pLi
->u
.HighPart
& 0x80000000)
4404 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4405 DEC_LO64(pDecOut
) = -pLi
->QuadPart
;
4409 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4410 DEC_MID32(pDecOut
) = pLi
->u
.HighPart
;
4411 DEC_LO32(pDecOut
) = pLi
->u
.LowPart
;
4416 /************************************************************************
4417 * VarDecFromUI8 (OLEAUT32.375)
4419 * Convert a VT_UI8 to a DECIMAL.
4423 * pDecOut [O] Destination
4428 HRESULT WINAPI
VarDecFromUI8(ULONG64 ullIn
, DECIMAL
* pDecOut
)
4430 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4431 DEC_HI32(pDecOut
) = 0;
4432 DEC_LO64(pDecOut
) = ullIn
;
4436 /* Make two DECIMALS the same scale; used by math functions below */
4437 static HRESULT
VARIANT_DecScale(const DECIMAL
** ppDecLeft
,
4438 const DECIMAL
** ppDecRight
,
4441 static DECIMAL scaleFactor
;
4442 unsigned char remainder
;
4447 if (DEC_SIGN(*ppDecLeft
) & ~DECIMAL_NEG
|| DEC_SIGN(*ppDecRight
) & ~DECIMAL_NEG
)
4448 return E_INVALIDARG
;
4450 DEC_LO32(&scaleFactor
) = 10;
4452 i
= scaleAmount
= DEC_SCALE(*ppDecLeft
) - DEC_SCALE(*ppDecRight
);
4455 return S_OK
; /* Same scale */
4457 if (scaleAmount
> 0)
4459 decTemp
= *(*ppDecRight
); /* Left is bigger - scale the right hand side */
4460 *ppDecRight
= &pDecOut
[0];
4464 decTemp
= *(*ppDecLeft
); /* Right is bigger - scale the left hand side */
4465 *ppDecLeft
= &pDecOut
[0];
4469 /* Multiply up the value to be scaled by the correct amount (if possible) */
4470 while (i
> 0 && SUCCEEDED(VarDecMul(&decTemp
, &scaleFactor
, &pDecOut
[0])))
4472 decTemp
= pDecOut
[0];
4478 DEC_SCALE(&pDecOut
[0]) += (scaleAmount
> 0) ? scaleAmount
: (-scaleAmount
);
4479 return S_OK
; /* Same scale */
4482 /* Scaling further not possible, reduce accuracy of other argument */
4483 pDecOut
[0] = decTemp
;
4484 if (scaleAmount
> 0)
4486 DEC_SCALE(&pDecOut
[0]) += scaleAmount
- i
;
4487 VARIANT_DIFromDec(*ppDecLeft
, &di
);
4488 *ppDecLeft
= &pDecOut
[1];
4492 DEC_SCALE(&pDecOut
[0]) += (-scaleAmount
) - i
;
4493 VARIANT_DIFromDec(*ppDecRight
, &di
);
4494 *ppDecRight
= &pDecOut
[1];
4499 while (i
-- > 0 && !VARIANT_int_iszero(di
.bitsnum
, sizeof(di
.bitsnum
)/sizeof(DWORD
)))
4501 remainder
= VARIANT_int_divbychar(di
.bitsnum
, sizeof(di
.bitsnum
)/sizeof(DWORD
), 10);
4502 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4505 /* round up the result - native oleaut32 does this */
4506 if (remainder
>= 5) {
4507 for (remainder
= 1, i
= 0; i
< sizeof(di
.bitsnum
)/sizeof(DWORD
) && remainder
; i
++) {
4508 ULONGLONG digit
= di
.bitsnum
[i
] + 1;
4509 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4510 di
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
4514 VARIANT_DecFromDI(&di
, &pDecOut
[1]);
4518 /* Add two unsigned 32 bit values with overflow */
4519 static ULONG
VARIANT_Add(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4521 ULARGE_INTEGER ul64
;
4523 ul64
.QuadPart
= (ULONG64
)ulLeft
+ (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4524 *pulHigh
= ul64
.u
.HighPart
;
4525 return ul64
.u
.LowPart
;
4528 /* Subtract two unsigned 32 bit values with underflow */
4529 static ULONG
VARIANT_Sub(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4531 BOOL invert
= FALSE
;
4532 ULARGE_INTEGER ul64
;
4534 ul64
.QuadPart
= (LONG64
)ulLeft
- (ULONG64
)ulRight
;
4535 if (ulLeft
< ulRight
)
4538 if (ul64
.QuadPart
> (ULONG64
)*pulHigh
)
4539 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4542 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4546 ul64
.u
.HighPart
= -ul64
.u
.HighPart
;
4548 *pulHigh
= ul64
.u
.HighPart
;
4549 return ul64
.u
.LowPart
;
4552 /* Multiply two unsigned 32 bit values with overflow */
4553 static ULONG
VARIANT_Mul(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4555 ULARGE_INTEGER ul64
;
4557 ul64
.QuadPart
= (ULONG64
)ulLeft
* (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4558 *pulHigh
= ul64
.u
.HighPart
;
4559 return ul64
.u
.LowPart
;
4562 /* Compare two decimals that have the same scale */
4563 static inline int VARIANT_DecCmp(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
)
4565 if ( DEC_HI32(pDecLeft
) < DEC_HI32(pDecRight
) ||
4566 (DEC_HI32(pDecLeft
) <= DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) < DEC_LO64(pDecRight
)))
4568 else if (DEC_HI32(pDecLeft
) == DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) == DEC_LO64(pDecRight
))
4573 /************************************************************************
4574 * VarDecAdd (OLEAUT32.177)
4576 * Add one DECIMAL to another.
4579 * pDecLeft [I] Source
4580 * pDecRight [I] Value to add
4581 * pDecOut [O] Destination
4585 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4587 HRESULT WINAPI
VarDecAdd(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
4592 hRet
= VARIANT_DecScale(&pDecLeft
, &pDecRight
, scaled
);
4594 if (SUCCEEDED(hRet
))
4596 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4598 BYTE sign
= DECIMAL_POS
;
4601 /* Correct for the sign of the result */
4602 if (DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4604 /* -x + -y : Negative */
4606 goto VarDecAdd_AsPositive
;
4608 else if (DEC_SIGN(pDecLeft
) && !DEC_SIGN(pDecRight
))
4610 cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4612 /* -x + y : Negative if x > y */
4616 VarDecAdd_AsNegative
:
4617 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4618 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4619 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4623 VarDecAdd_AsInvertedNegative
:
4624 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecRight
), DEC_LO32(pDecLeft
), &overflow
);
4625 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecRight
), DEC_MID32(pDecLeft
), &overflow
);
4626 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecRight
), DEC_HI32(pDecLeft
), &overflow
);
4629 else if (!DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4631 cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4633 /* x + -y : Negative if x <= y */
4637 goto VarDecAdd_AsInvertedNegative
;
4639 goto VarDecAdd_AsNegative
;
4643 /* x + y : Positive */
4644 VarDecAdd_AsPositive
:
4645 DEC_LO32(pDecOut
) = VARIANT_Add(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4646 DEC_MID32(pDecOut
) = VARIANT_Add(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4647 DEC_HI32(pDecOut
) = VARIANT_Add(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4651 return DISP_E_OVERFLOW
; /* overflowed */
4653 DEC_SCALE(pDecOut
) = DEC_SCALE(pDecLeft
);
4654 DEC_SIGN(pDecOut
) = sign
;
4659 /* translate from external DECIMAL format into an internal representation */
4660 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
)
4662 to
->scale
= DEC_SCALE(from
);
4663 to
->sign
= DEC_SIGN(from
) ? 1 : 0;
4665 to
->bitsnum
[0] = DEC_LO32(from
);
4666 to
->bitsnum
[1] = DEC_MID32(from
);
4667 to
->bitsnum
[2] = DEC_HI32(from
);
4670 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
)
4673 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_NEG
, from
->scale
);
4675 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_POS
, from
->scale
);
4678 DEC_LO32(to
) = from
->bitsnum
[0];
4679 DEC_MID32(to
) = from
->bitsnum
[1];
4680 DEC_HI32(to
) = from
->bitsnum
[2];
4683 /* clear an internal representation of a DECIMAL */
4684 static void VARIANT_DI_clear(VARIANT_DI
* i
)
4686 memset(i
, 0, sizeof(VARIANT_DI
));
4689 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4690 size is supported. The value in p is replaced by the quotient of the division, and
4691 the remainder is returned as a result. This routine is most often used with a divisor
4692 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4694 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
)
4699 } else if (divisor
== 1) {
4700 /* dividend remains unchanged */
4703 unsigned char remainder
= 0;
4704 ULONGLONG iTempDividend
;
4707 for (i
= n
- 1; i
>= 0 && !p
[i
]; i
--); /* skip leading zeros */
4708 for (; i
>= 0; i
--) {
4709 iTempDividend
= ((ULONGLONG
)remainder
<< 32) + p
[i
];
4710 remainder
= iTempDividend
% divisor
;
4711 p
[i
] = iTempDividend
/ divisor
;
4718 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4719 static BOOL
VARIANT_int_iszero(const DWORD
* p
, unsigned int n
)
4721 for (; n
> 0; n
--) if (*p
++ != 0) return FALSE
;
4725 /* multiply two DECIMALS, without changing either one, and place result in third
4726 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4727 digits when scale > 0 in order to fit an overflowing result. Final overflow
4730 static int VARIANT_DI_mul(const VARIANT_DI
* a
, const VARIANT_DI
* b
, VARIANT_DI
* result
)
4732 BOOL r_overflow
= FALSE
;
4734 signed int mulstart
;
4736 VARIANT_DI_clear(result
);
4737 result
->sign
= (a
->sign
^ b
->sign
) ? 1 : 0;
4739 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4740 of the result is formed by adding the scales of the operands.
4742 result
->scale
= a
->scale
+ b
->scale
;
4743 memset(running
, 0, sizeof(running
));
4745 /* count number of leading zero-bytes in operand A */
4746 for (mulstart
= sizeof(a
->bitsnum
)/sizeof(DWORD
) - 1; mulstart
>= 0 && !a
->bitsnum
[mulstart
]; mulstart
--);
4748 /* result is 0, because operand A is 0 */
4752 unsigned char remainder
= 0;
4755 /* perform actual multiplication */
4756 for (iA
= 0; iA
<= mulstart
; iA
++) {
4760 for (iOverflowMul
= 0, iB
= 0; iB
< sizeof(b
->bitsnum
)/sizeof(DWORD
); iB
++) {
4764 iRV
= VARIANT_Mul(b
->bitsnum
[iB
], a
->bitsnum
[iA
], &iOverflowMul
);
4767 running
[iR
] = VARIANT_Add(running
[iR
], 0, &iRV
);
4773 /* Too bad - native oleaut does not do this, so we should not either */
4775 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4776 This operation should not lose significant digits, and gives an
4777 opportunity to reduce the possibility of overflows in future
4778 operations issued by the application.
4780 while (result
->scale
> 0) {
4781 memcpy(quotient
, running
, sizeof(quotient
));
4782 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4783 if (remainder
> 0) break;
4784 memcpy(running
, quotient
, sizeof(quotient
));
4788 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4789 This operation *will* lose significant digits of the result because
4790 all the factors of 10 were consumed by the previous operation.
4792 while (result
->scale
> 0 && !VARIANT_int_iszero(
4793 running
+ sizeof(result
->bitsnum
) / sizeof(DWORD
),
4794 (sizeof(running
) - sizeof(result
->bitsnum
)) / sizeof(DWORD
))) {
4796 remainder
= VARIANT_int_divbychar(running
, sizeof(running
) / sizeof(DWORD
), 10);
4797 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4801 /* round up the result - native oleaut32 does this */
4802 if (remainder
>= 5) {
4804 for (remainder
= 1, i
= 0; i
< sizeof(running
)/sizeof(DWORD
) && remainder
; i
++) {
4805 ULONGLONG digit
= running
[i
] + 1;
4806 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4807 running
[i
] = digit
& 0xFFFFFFFF;
4811 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4812 and copy result bits into result structure
4814 r_overflow
= !VARIANT_int_iszero(
4815 running
+ sizeof(result
->bitsnum
)/sizeof(DWORD
),
4816 (sizeof(running
) - sizeof(result
->bitsnum
))/sizeof(DWORD
));
4817 memcpy(result
->bitsnum
, running
, sizeof(result
->bitsnum
));
4822 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4823 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4824 success, FALSE if insufficient space in output buffer.
4826 static BOOL
VARIANT_DI_tostringW(const VARIANT_DI
* a
, WCHAR
* s
, unsigned int n
)
4828 BOOL overflow
= FALSE
;
4830 unsigned char remainder
;
4833 /* place negative sign */
4834 if (!VARIANT_int_iszero(a
->bitsnum
, sizeof(a
->bitsnum
) / sizeof(DWORD
)) && a
->sign
) {
4839 else overflow
= TRUE
;
4842 /* prepare initial 0 */
4847 } else overflow
= TRUE
;
4851 memcpy(quotient
, a
->bitsnum
, sizeof(a
->bitsnum
));
4852 while (!overflow
&& !VARIANT_int_iszero(quotient
, sizeof(quotient
) / sizeof(DWORD
))) {
4853 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4857 s
[i
++] = '0' + remainder
;
4862 if (!overflow
&& !VARIANT_int_iszero(a
->bitsnum
, sizeof(a
->bitsnum
) / sizeof(DWORD
))) {
4864 /* reverse order of digits */
4865 WCHAR
* x
= s
; WCHAR
* y
= s
+ i
- 1;
4872 /* check for decimal point. "i" now has string length */
4873 if (i
<= a
->scale
) {
4874 unsigned int numzeroes
= a
->scale
+ 1 - i
;
4875 if (i
+ 1 + numzeroes
>= n
) {
4878 memmove(s
+ numzeroes
, s
, (i
+ 1) * sizeof(WCHAR
));
4880 while (numzeroes
> 0) {
4881 s
[--numzeroes
] = '0';
4886 /* place decimal point */
4888 unsigned int periodpos
= i
- a
->scale
;
4892 memmove(s
+ periodpos
+ 1, s
+ periodpos
, (i
+ 1 - periodpos
) * sizeof(WCHAR
));
4893 s
[periodpos
] = '.'; i
++;
4895 /* remove extra zeros at the end, if any */
4896 while (s
[i
- 1] == '0') s
[--i
] = '\0';
4897 if (s
[i
- 1] == '.') s
[--i
] = '\0';
4905 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4906 static void VARIANT_int_shiftleft(DWORD
* p
, unsigned int n
, unsigned int shift
)
4911 /* shift whole DWORDs to the left */
4914 memmove(p
+ 1, p
, (n
- 1) * sizeof(DWORD
));
4915 *p
= 0; shift
-= 32;
4918 /* shift remainder (1..31 bits) */
4920 if (shift
> 0) for (i
= 0; i
< n
; i
++)
4923 b
= p
[i
] >> (32 - shift
);
4924 p
[i
] = (p
[i
] << shift
) | shifted
;
4929 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4930 Value at v is incremented by the value at p. Any size is supported, provided
4931 that v is not shorter than p. Any unapplied carry is returned as a result.
4933 static unsigned char VARIANT_int_add(DWORD
* v
, unsigned int nv
, const DWORD
* p
,
4936 unsigned char carry
= 0;
4942 for (i
= 0; i
< np
; i
++) {
4943 sum
= (ULONGLONG
)v
[i
]
4946 v
[i
] = sum
& 0xffffffff;
4949 for (; i
< nv
&& carry
; i
++) {
4950 sum
= (ULONGLONG
)v
[i
]
4952 v
[i
] = sum
& 0xffffffff;
4959 /* perform integral division with operand p as dividend. Parameter n indicates
4960 number of available DWORDs in divisor p, but available space in p must be
4961 actually at least 2 * n DWORDs, because the remainder of the integral
4962 division is built in the next n DWORDs past the start of the quotient. This
4963 routine replaces the dividend in p with the quotient, and appends n
4964 additional DWORDs for the remainder.
4966 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4967 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4968 source code to the VLI (Very Large Integer) division operator. This algorithm
4969 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4970 variably-scaled integers such as the MS DECIMAL representation.
4972 static void VARIANT_int_div(DWORD
* p
, unsigned int n
, const DWORD
* divisor
,
4977 DWORD
* negdivisor
= tempsub
+ n
;
4979 /* build 2s-complement of divisor */
4980 for (i
= 0; i
< n
; i
++) negdivisor
[i
] = (i
< dn
) ? ~divisor
[i
] : 0xFFFFFFFF;
4982 VARIANT_int_add(negdivisor
, n
, p
+ n
, 1);
4983 memset(p
+ n
, 0, n
* sizeof(DWORD
));
4985 /* skip all leading zero DWORDs in quotient */
4986 for (i
= 0; i
< n
&& !p
[n
- 1]; i
++) VARIANT_int_shiftleft(p
, n
, 32);
4987 /* i is now number of DWORDs left to process */
4988 for (i
<<= 5; i
< (n
<< 5); i
++) {
4989 VARIANT_int_shiftleft(p
, n
<< 1, 1); /* shl quotient+remainder */
4991 /* trial subtraction */
4992 memcpy(tempsub
, p
+ n
, n
* sizeof(DWORD
));
4993 VARIANT_int_add(tempsub
, n
, negdivisor
, n
);
4995 /* check whether result of subtraction was negative */
4996 if ((tempsub
[n
- 1] & 0x80000000) == 0) {
4997 memcpy(p
+ n
, tempsub
, n
* sizeof(DWORD
));
5003 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
5004 static unsigned char VARIANT_int_mulbychar(DWORD
* p
, unsigned int n
, unsigned char m
)
5009 for (iOverflowMul
= 0, i
= 0; i
< n
; i
++)
5010 p
[i
] = VARIANT_Mul(p
[i
], m
, &iOverflowMul
);
5011 return (unsigned char)iOverflowMul
;
5014 /* increment value in A by the value indicated in B, with scale adjusting.
5015 Modifies parameters by adjusting scales. Returns 0 if addition was
5016 successful, nonzero if a parameter underflowed before it could be
5017 successfully used in the addition.
5019 static int VARIANT_int_addlossy(
5020 DWORD
* a
, int * ascale
, unsigned int an
,
5021 DWORD
* b
, int * bscale
, unsigned int bn
)
5025 if (VARIANT_int_iszero(a
, an
)) {
5026 /* if A is zero, copy B into A, after removing digits */
5027 while (bn
> an
&& !VARIANT_int_iszero(b
+ an
, bn
- an
)) {
5028 VARIANT_int_divbychar(b
, bn
, 10);
5031 memcpy(a
, b
, an
* sizeof(DWORD
));
5033 } else if (!VARIANT_int_iszero(b
, bn
)) {
5034 unsigned int tn
= an
+ 1;
5037 if (bn
+ 1 > tn
) tn
= bn
+ 1;
5038 if (*ascale
!= *bscale
) {
5039 /* first (optimistic) try - try to scale down the one with the bigger
5040 scale, while this number is divisible by 10 */
5041 DWORD
* digitchosen
;
5042 unsigned int nchosen
;
5046 if (*ascale
< *bscale
) {
5047 targetscale
= *ascale
;
5048 scalechosen
= bscale
;
5052 targetscale
= *bscale
;
5053 scalechosen
= ascale
;
5057 memset(t
, 0, tn
* sizeof(DWORD
));
5058 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5060 /* divide by 10 until target scale is reached */
5061 while (*scalechosen
> targetscale
) {
5062 unsigned char remainder
= VARIANT_int_divbychar(t
, tn
, 10);
5065 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5070 if (*ascale
!= *bscale
) {
5071 DWORD
* digitchosen
;
5072 unsigned int nchosen
;
5076 /* try to scale up the one with the smaller scale */
5077 if (*ascale
> *bscale
) {
5078 targetscale
= *ascale
;
5079 scalechosen
= bscale
;
5083 targetscale
= *bscale
;
5084 scalechosen
= ascale
;
5088 memset(t
, 0, tn
* sizeof(DWORD
));
5089 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5091 /* multiply by 10 until target scale is reached, or
5092 significant bytes overflow the number
5094 while (*scalechosen
< targetscale
&& t
[nchosen
] == 0) {
5095 VARIANT_int_mulbychar(t
, tn
, 10);
5096 if (t
[nchosen
] == 0) {
5097 /* still does not overflow */
5099 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5104 if (*ascale
!= *bscale
) {
5105 /* still different? try to scale down the one with the bigger scale
5106 (this *will* lose significant digits) */
5107 DWORD
* digitchosen
;
5108 unsigned int nchosen
;
5112 if (*ascale
< *bscale
) {
5113 targetscale
= *ascale
;
5114 scalechosen
= bscale
;
5118 targetscale
= *bscale
;
5119 scalechosen
= ascale
;
5123 memset(t
, 0, tn
* sizeof(DWORD
));
5124 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5126 /* divide by 10 until target scale is reached */
5127 while (*scalechosen
> targetscale
) {
5128 VARIANT_int_divbychar(t
, tn
, 10);
5130 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5134 /* check whether any of the operands still has significant digits
5137 if (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
)) {
5140 /* at this step, both numbers have the same scale and can be added
5141 as integers. However, the result might not fit in A, so further
5142 scaling down might be necessary.
5144 while (!underflow
) {
5145 memset(t
, 0, tn
* sizeof(DWORD
));
5146 memcpy(t
, a
, an
* sizeof(DWORD
));
5148 VARIANT_int_add(t
, tn
, b
, bn
);
5149 if (VARIANT_int_iszero(t
+ an
, tn
- an
)) {
5150 /* addition was successful */
5151 memcpy(a
, t
, an
* sizeof(DWORD
));
5154 /* addition overflowed - remove significant digits
5155 from both operands and try again */
5156 VARIANT_int_divbychar(a
, an
, 10); (*ascale
)--;
5157 VARIANT_int_divbychar(b
, bn
, 10); (*bscale
)--;
5158 /* check whether any operand keeps significant digits after
5159 scaledown (underflow case 2)
5161 underflow
= (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
));
5169 /* perform complete DECIMAL division in the internal representation. Returns
5170 0 if the division was completed (even if quotient is set to 0), or nonzero
5171 in case of quotient overflow.
5173 static HRESULT
VARIANT_DI_div(const VARIANT_DI
* dividend
, const VARIANT_DI
* divisor
,
5174 VARIANT_DI
* quotient
, BOOL round_remainder
)
5176 HRESULT r_overflow
= S_OK
;
5178 if (VARIANT_int_iszero(divisor
->bitsnum
, sizeof(divisor
->bitsnum
)/sizeof(DWORD
))) {
5180 r_overflow
= DISP_E_DIVBYZERO
;
5181 } else if (VARIANT_int_iszero(dividend
->bitsnum
, sizeof(dividend
->bitsnum
)/sizeof(DWORD
))) {
5182 VARIANT_DI_clear(quotient
);
5184 int quotientscale
, remainderscale
, tempquotientscale
;
5185 DWORD remainderplusquotient
[8];
5188 quotientscale
= remainderscale
= (int)dividend
->scale
- (int)divisor
->scale
;
5189 tempquotientscale
= quotientscale
;
5190 VARIANT_DI_clear(quotient
);
5191 quotient
->sign
= (dividend
->sign
^ divisor
->sign
) ? 1 : 0;
5193 /* The following strategy is used for division
5194 1) if there was a nonzero remainder from previous iteration, use it as
5195 dividend for this iteration, else (for first iteration) use intended
5197 2) perform integer division in temporary buffer, develop quotient in
5198 low-order part, remainder in high-order part
5199 3) add quotient from step 2 to final result, with possible loss of
5201 4) multiply integer part of remainder by 10, while incrementing the
5202 scale of the remainder. This operation preserves the intended value
5204 5) loop to step 1 until one of the following is true:
5205 a) remainder is zero (exact division achieved)
5206 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5208 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5209 memcpy(remainderplusquotient
, dividend
->bitsnum
, sizeof(dividend
->bitsnum
));
5212 remainderplusquotient
, 4,
5213 divisor
->bitsnum
, sizeof(divisor
->bitsnum
)/sizeof(DWORD
));
5214 underflow
= VARIANT_int_addlossy(
5215 quotient
->bitsnum
, "ientscale
, sizeof(quotient
->bitsnum
) / sizeof(DWORD
),
5216 remainderplusquotient
, &tempquotientscale
, 4);
5217 if (round_remainder
) {
5218 if(remainderplusquotient
[4] >= 5){
5220 unsigned char remainder
= 1;
5221 for (i
= 0; i
< sizeof(quotient
->bitsnum
) / sizeof(DWORD
) && remainder
; i
++) {
5222 ULONGLONG digit
= quotient
->bitsnum
[i
] + 1;
5223 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5224 quotient
->bitsnum
[i
] = digit
& 0xFFFFFFFF;
5227 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5229 VARIANT_int_mulbychar(remainderplusquotient
+ 4, 4, 10);
5230 memcpy(remainderplusquotient
, remainderplusquotient
+ 4, 4 * sizeof(DWORD
));
5232 tempquotientscale
= ++remainderscale
;
5233 } while (!underflow
&& !VARIANT_int_iszero(remainderplusquotient
+ 4, 4));
5235 /* quotient scale might now be negative (extremely big number). If, so, try
5236 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5237 until scale is 0. If this cannot be done, it is a real overflow.
5239 while (r_overflow
== S_OK
&& quotientscale
< 0) {
5240 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5241 memcpy(remainderplusquotient
, quotient
->bitsnum
, sizeof(quotient
->bitsnum
));
5242 VARIANT_int_mulbychar(remainderplusquotient
, sizeof(remainderplusquotient
)/sizeof(DWORD
), 10);
5243 if (VARIANT_int_iszero(remainderplusquotient
+ sizeof(quotient
->bitsnum
)/sizeof(DWORD
),
5244 (sizeof(remainderplusquotient
) - sizeof(quotient
->bitsnum
))/sizeof(DWORD
))) {
5246 memcpy(quotient
->bitsnum
, remainderplusquotient
, sizeof(quotient
->bitsnum
));
5247 } else r_overflow
= DISP_E_OVERFLOW
;
5249 if (r_overflow
== S_OK
) {
5250 if (quotientscale
<= 255) quotient
->scale
= quotientscale
;
5251 else VARIANT_DI_clear(quotient
);
5257 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5258 with an undefined scale, which will be assigned to (if possible). It also
5259 receives an exponent of 2. This procedure will then manipulate the mantissa
5260 and calculate a corresponding scale, so that the exponent2 value is assimilated
5261 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5262 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5264 static HRESULT
VARIANT_DI_normalize(VARIANT_DI
* val
, int exponent2
, BOOL isDouble
)
5266 HRESULT hres
= S_OK
;
5267 int exponent5
, exponent10
;
5269 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5270 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5271 exponent10 might be used to set the VARIANT_DI scale directly. However,
5272 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5273 exponent5
= -exponent2
;
5274 exponent10
= exponent2
;
5276 /* Handle exponent5 > 0 */
5277 while (exponent5
> 0) {
5281 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5282 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5283 somehow the mantissa should be divided by 2. */
5284 if ((val
->bitsnum
[0] & 1) == 0) {
5285 /* The mantissa is divisible by 2. Therefore the division can be done
5286 without losing significant digits. */
5287 exponent10
++; exponent5
--;
5290 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5291 val
->bitsnum
[2] >>= 1;
5292 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5293 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5294 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5296 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5297 be multiplied by 5, unless the multiplication overflows. */
5298 DWORD temp_bitsnum
[3];
5302 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5303 if (0 == VARIANT_int_mulbychar(temp_bitsnum
, 3, 5)) {
5304 /* Multiplication succeeded without overflow, so copy result back
5306 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5308 /* Mask out 3 extraneous bits introduced by the multiply */
5310 /* Multiplication by 5 overflows. The mantissa should be divided
5311 by 2, and therefore will lose significant digits. */
5315 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5316 val
->bitsnum
[2] >>= 1;
5317 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5318 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5319 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5324 /* Handle exponent5 < 0 */
5325 while (exponent5
< 0) {
5326 /* In order to divide the value represented by the VARIANT_DI by 5, it
5327 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5328 and the mantissa should be multiplied by 2 */
5329 if ((val
->bitsnum
[2] & 0x80000000) == 0) {
5330 /* The mantissa can withstand a shift-left without overflowing */
5331 exponent10
--; exponent5
++;
5332 VARIANT_int_shiftleft(val
->bitsnum
, 3, 1);
5334 /* The mantissa would overflow if shifted. Therefore it should be
5335 directly divided by 5. This will lose significant digits, unless
5336 by chance the mantissa happens to be divisible by 5 */
5338 VARIANT_int_divbychar(val
->bitsnum
, 3, 5);
5342 /* At this point, the mantissa has assimilated the exponent5, but the
5343 exponent10 might not be suitable for assignment. The exponent10 must be
5344 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5345 down appropriately. */
5346 while (hres
== S_OK
&& exponent10
> 0) {
5347 /* In order to bring exponent10 down to 0, the mantissa should be
5348 multiplied by 10 to compensate. If the exponent10 is too big, this
5349 will cause the mantissa to overflow. */
5350 if (0 == VARIANT_int_mulbychar(val
->bitsnum
, 3, 10)) {
5353 hres
= DISP_E_OVERFLOW
;
5356 while (exponent10
< -DEC_MAX_SCALE
) {
5358 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5359 be divided by 10 to compensate. If the exponent10 is too small, this
5360 will cause the mantissa to underflow and become 0 */
5361 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5363 if (VARIANT_int_iszero(val
->bitsnum
, 3)) {
5364 /* Underflow, unable to keep dividing */
5366 } else if (rem10
>= 5) {
5368 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5371 /* This step is required in order to remove excess bits of precision from the
5372 end of the bit representation, down to the precision guaranteed by the
5373 floating point number. */
5375 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || (val
->bitsnum
[1] & 0xFFE00000) != 0)) {
5378 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5382 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5386 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || val
->bitsnum
[1] != 0 ||
5387 (val
->bitsnum
[2] == 0 && val
->bitsnum
[1] == 0 && (val
->bitsnum
[0] & 0xFF000000) != 0))) {
5390 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5394 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5398 /* Remove multiples of 10 from the representation */
5399 while (exponent10
< 0) {
5400 DWORD temp_bitsnum
[3];
5402 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5403 if (0 == VARIANT_int_divbychar(temp_bitsnum
, 3, 10)) {
5405 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5409 /* Scale assignment */
5410 if (hres
== S_OK
) val
->scale
= -exponent10
;
5419 unsigned int m
: 23;
5420 unsigned int exp_bias
: 8;
5421 unsigned int sign
: 1;
5426 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5427 intermediate string step. */
5428 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
)
5430 HRESULT hres
= S_OK
;
5435 /* Detect special cases */
5436 if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0) {
5437 /* Floating-point zero */
5438 VARIANT_DI_clear(dest
);
5439 } else if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0xFF) {
5440 /* Floating-point infinity */
5441 hres
= DISP_E_OVERFLOW
;
5442 } else if (fx
.i
.exp_bias
== 0xFF) {
5443 /* Floating-point NaN */
5444 hres
= DISP_E_BADVARTYPE
;
5447 VARIANT_DI_clear(dest
);
5449 exponent2
= fx
.i
.exp_bias
- 127; /* Get unbiased exponent */
5450 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5452 /* Copy significant bits to VARIANT_DI mantissa */
5453 dest
->bitsnum
[0] = fx
.i
.m
;
5454 dest
->bitsnum
[0] &= 0x007FFFFF;
5455 if (fx
.i
.exp_bias
== 0) {
5456 /* Denormalized number - correct exponent */
5459 /* Add hidden bit to mantissa */
5460 dest
->bitsnum
[0] |= 0x00800000;
5463 /* The act of copying a FP mantissa as integer bits is equivalent to
5464 shifting left the mantissa 23 bits. The exponent2 is reduced to
5468 hres
= VARIANT_DI_normalize(dest
, exponent2
, FALSE
);
5478 unsigned int m_lo
: 32; /* 52 bits of precision */
5479 unsigned int m_hi
: 20;
5480 unsigned int exp_bias
: 11; /* bias == 1023 */
5481 unsigned int sign
: 1;
5486 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5487 intermediate string step. */
5488 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
)
5490 HRESULT hres
= S_OK
;
5495 /* Detect special cases */
5496 if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0) {
5497 /* Floating-point zero */
5498 VARIANT_DI_clear(dest
);
5499 } else if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0x7FF) {
5500 /* Floating-point infinity */
5501 hres
= DISP_E_OVERFLOW
;
5502 } else if (fx
.i
.exp_bias
== 0x7FF) {
5503 /* Floating-point NaN */
5504 hres
= DISP_E_BADVARTYPE
;
5507 VARIANT_DI_clear(dest
);
5509 exponent2
= fx
.i
.exp_bias
- 1023; /* Get unbiased exponent */
5510 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5512 /* Copy significant bits to VARIANT_DI mantissa */
5513 dest
->bitsnum
[0] = fx
.i
.m_lo
;
5514 dest
->bitsnum
[1] = fx
.i
.m_hi
;
5515 dest
->bitsnum
[1] &= 0x000FFFFF;
5516 if (fx
.i
.exp_bias
== 0) {
5517 /* Denormalized number - correct exponent */
5520 /* Add hidden bit to mantissa */
5521 dest
->bitsnum
[1] |= 0x00100000;
5524 /* The act of copying a FP mantissa as integer bits is equivalent to
5525 shifting left the mantissa 52 bits. The exponent2 is reduced to
5529 hres
= VARIANT_DI_normalize(dest
, exponent2
, TRUE
);
5535 static HRESULT
VARIANT_do_division(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
, DECIMAL
*pDecOut
,
5538 HRESULT hRet
= S_OK
;
5539 VARIANT_DI di_left
, di_right
, di_result
;
5542 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5543 VARIANT_DIFromDec(pDecRight
, &di_right
);
5544 divresult
= VARIANT_DI_div(&di_left
, &di_right
, &di_result
, round
);
5545 if (divresult
!= S_OK
)
5547 /* division actually overflowed */
5554 if (di_result
.scale
> DEC_MAX_SCALE
)
5556 unsigned char remainder
= 0;
5558 /* division underflowed. In order to comply with the MSDN
5559 specifications for DECIMAL ranges, some significant digits
5562 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5564 while (di_result
.scale
> DEC_MAX_SCALE
&&
5565 !VARIANT_int_iszero(di_result
.bitsnum
, sizeof(di_result
.bitsnum
) / sizeof(DWORD
)))
5567 remainder
= VARIANT_int_divbychar(di_result
.bitsnum
, sizeof(di_result
.bitsnum
) / sizeof(DWORD
), 10);
5570 if (di_result
.scale
> DEC_MAX_SCALE
)
5572 WARN("result underflowed, setting to 0\n");
5573 di_result
.scale
= 0;
5576 else if (remainder
>= 5) /* round up result - native oleaut32 does this */
5579 for (remainder
= 1, i
= 0; i
< sizeof(di_result
.bitsnum
) / sizeof(DWORD
) && remainder
; i
++) {
5580 ULONGLONG digit
= di_result
.bitsnum
[i
] + 1;
5581 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5582 di_result
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
5586 VARIANT_DecFromDI(&di_result
, pDecOut
);
5591 /************************************************************************
5592 * VarDecDiv (OLEAUT32.178)
5594 * Divide one DECIMAL by another.
5597 * pDecLeft [I] Source
5598 * pDecRight [I] Value to divide by
5599 * pDecOut [O] Destination
5603 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5605 HRESULT WINAPI
VarDecDiv(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5607 if (!pDecLeft
|| !pDecRight
|| !pDecOut
) return E_INVALIDARG
;
5609 return VARIANT_do_division(pDecLeft
, pDecRight
, pDecOut
, FALSE
);
5612 /************************************************************************
5613 * VarDecMul (OLEAUT32.179)
5615 * Multiply one DECIMAL by another.
5618 * pDecLeft [I] Source
5619 * pDecRight [I] Value to multiply by
5620 * pDecOut [O] Destination
5624 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5626 HRESULT WINAPI
VarDecMul(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5628 HRESULT hRet
= S_OK
;
5629 VARIANT_DI di_left
, di_right
, di_result
;
5632 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5633 VARIANT_DIFromDec(pDecRight
, &di_right
);
5634 mulresult
= VARIANT_DI_mul(&di_left
, &di_right
, &di_result
);
5637 /* multiplication actually overflowed */
5638 hRet
= DISP_E_OVERFLOW
;
5642 if (di_result
.scale
> DEC_MAX_SCALE
)
5644 /* multiplication underflowed. In order to comply with the MSDN
5645 specifications for DECIMAL ranges, some significant digits
5648 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5650 while (di_result
.scale
> DEC_MAX_SCALE
&&
5651 !VARIANT_int_iszero(di_result
.bitsnum
, sizeof(di_result
.bitsnum
)/sizeof(DWORD
)))
5653 VARIANT_int_divbychar(di_result
.bitsnum
, sizeof(di_result
.bitsnum
)/sizeof(DWORD
), 10);
5656 if (di_result
.scale
> DEC_MAX_SCALE
)
5658 WARN("result underflowed, setting to 0\n");
5659 di_result
.scale
= 0;
5663 VARIANT_DecFromDI(&di_result
, pDecOut
);
5668 /************************************************************************
5669 * VarDecSub (OLEAUT32.181)
5671 * Subtract one DECIMAL from another.
5674 * pDecLeft [I] Source
5675 * pDecRight [I] DECIMAL to subtract from pDecLeft
5676 * pDecOut [O] Destination
5679 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5681 HRESULT WINAPI
VarDecSub(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5685 /* Implement as addition of the negative */
5686 VarDecNeg(pDecRight
, &decRight
);
5687 return VarDecAdd(pDecLeft
, &decRight
, pDecOut
);
5690 /************************************************************************
5691 * VarDecAbs (OLEAUT32.182)
5693 * Convert a DECIMAL into its absolute value.
5697 * pDecOut [O] Destination
5700 * S_OK. This function does not fail.
5702 HRESULT WINAPI
VarDecAbs(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5705 DEC_SIGN(pDecOut
) &= ~DECIMAL_NEG
;
5709 /************************************************************************
5710 * VarDecFix (OLEAUT32.187)
5712 * Return the integer portion of a DECIMAL.
5716 * pDecOut [O] Destination
5720 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5723 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5724 * negative numbers away from 0, while this function rounds them towards zero.
5726 HRESULT WINAPI
VarDecFix(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5731 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5732 return E_INVALIDARG
;
5734 if (!DEC_SCALE(pDecIn
))
5736 *pDecOut
= *pDecIn
; /* Already an integer */
5740 hr
= VarR8FromDec(pDecIn
, &dbl
);
5741 if (SUCCEEDED(hr
)) {
5742 LONGLONG rounded
= dbl
;
5744 hr
= VarDecFromI8(rounded
, pDecOut
);
5749 /************************************************************************
5750 * VarDecInt (OLEAUT32.188)
5752 * Return the integer portion of a DECIMAL.
5756 * pDecOut [O] Destination
5760 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5763 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5764 * negative numbers towards 0, while this function rounds them away from zero.
5766 HRESULT WINAPI
VarDecInt(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5771 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5772 return E_INVALIDARG
;
5774 if (!(DEC_SIGN(pDecIn
) & DECIMAL_NEG
) || !DEC_SCALE(pDecIn
))
5775 return VarDecFix(pDecIn
, pDecOut
); /* The same, if +ve or no fractionals */
5777 hr
= VarR8FromDec(pDecIn
, &dbl
);
5778 if (SUCCEEDED(hr
)) {
5779 LONGLONG rounded
= dbl
>= 0.0 ? dbl
+ 0.5 : dbl
- 0.5;
5781 hr
= VarDecFromI8(rounded
, pDecOut
);
5786 /************************************************************************
5787 * VarDecNeg (OLEAUT32.189)
5789 * Change the sign of a DECIMAL.
5793 * pDecOut [O] Destination
5796 * S_OK. This function does not fail.
5798 HRESULT WINAPI
VarDecNeg(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5801 DEC_SIGN(pDecOut
) ^= DECIMAL_NEG
;
5805 /************************************************************************
5806 * VarDecRound (OLEAUT32.203)
5808 * Change the precision of a DECIMAL.
5812 * cDecimals [I] New number of decimals to keep
5813 * pDecOut [O] Destination
5816 * Success: S_OK. pDecOut contains the rounded value.
5817 * Failure: E_INVALIDARG if any argument is invalid.
5819 HRESULT WINAPI
VarDecRound(const DECIMAL
* pDecIn
, int cDecimals
, DECIMAL
* pDecOut
)
5821 DECIMAL divisor
, tmp
;
5825 if (cDecimals
< 0 || (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
) || DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
)
5826 return E_INVALIDARG
;
5828 if (cDecimals
>= DEC_SCALE(pDecIn
))
5830 *pDecOut
= *pDecIn
; /* More precision than we have */
5834 /* truncate significant digits and rescale */
5835 memset(&divisor
, 0, sizeof(divisor
));
5836 DEC_LO64(&divisor
) = 1;
5838 memset(&tmp
, 0, sizeof(tmp
));
5839 DEC_LO64(&tmp
) = 10;
5840 for (i
= 0; i
< DEC_SCALE(pDecIn
) - cDecimals
; ++i
)
5842 hr
= VarDecMul(&divisor
, &tmp
, &divisor
);
5847 hr
= VARIANT_do_division(pDecIn
, &divisor
, pDecOut
, TRUE
);
5851 DEC_SCALE(pDecOut
) = cDecimals
;
5856 /************************************************************************
5857 * VarDecCmp (OLEAUT32.204)
5859 * Compare two DECIMAL values.
5862 * pDecLeft [I] Source
5863 * pDecRight [I] Value to compare
5866 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5867 * is less than, equal to or greater than pDecRight respectively.
5868 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5870 HRESULT WINAPI
VarDecCmp(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
)
5875 if (!pDecLeft
|| !pDecRight
)
5878 if ((!(DEC_SIGN(pDecLeft
) & DECIMAL_NEG
)) && (DEC_SIGN(pDecRight
) & DECIMAL_NEG
) &&
5879 (DEC_HI32(pDecLeft
) | DEC_MID32(pDecLeft
) | DEC_LO32(pDecLeft
)))
5881 else if ((DEC_SIGN(pDecLeft
) & DECIMAL_NEG
) && (!(DEC_SIGN(pDecRight
) & DECIMAL_NEG
)) &&
5882 (DEC_HI32(pDecLeft
) | DEC_MID32(pDecLeft
) | DEC_LO32(pDecLeft
)))
5885 /* Subtract right from left, and compare the result to 0 */
5886 hRet
= VarDecSub(pDecLeft
, pDecRight
, &result
);
5888 if (SUCCEEDED(hRet
))
5890 int non_zero
= DEC_HI32(&result
) | DEC_MID32(&result
) | DEC_LO32(&result
);
5892 if ((DEC_SIGN(&result
) & DECIMAL_NEG
) && non_zero
)
5893 hRet
= (HRESULT
)VARCMP_LT
;
5895 hRet
= (HRESULT
)VARCMP_GT
;
5897 hRet
= (HRESULT
)VARCMP_EQ
;
5902 /************************************************************************
5903 * VarDecCmpR8 (OLEAUT32.298)
5905 * Compare a DECIMAL to a double
5908 * pDecLeft [I] DECIMAL Source
5909 * dblRight [I] double to compare to pDecLeft
5912 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5913 * is less than, equal to or greater than pDecLeft respectively.
5914 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5916 HRESULT WINAPI
VarDecCmpR8(const DECIMAL
* pDecLeft
, double dblRight
)
5921 hRet
= VarDecFromR8(dblRight
, &decRight
);
5923 if (SUCCEEDED(hRet
))
5924 hRet
= VarDecCmp(pDecLeft
, &decRight
);
5932 /************************************************************************
5933 * VarBoolFromUI1 (OLEAUT32.118)
5935 * Convert a VT_UI1 to a VT_BOOL.
5939 * pBoolOut [O] Destination
5944 HRESULT WINAPI
VarBoolFromUI1(BYTE bIn
, VARIANT_BOOL
*pBoolOut
)
5946 *pBoolOut
= bIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5950 /************************************************************************
5951 * VarBoolFromI2 (OLEAUT32.119)
5953 * Convert a VT_I2 to a VT_BOOL.
5957 * pBoolOut [O] Destination
5962 HRESULT WINAPI
VarBoolFromI2(SHORT sIn
, VARIANT_BOOL
*pBoolOut
)
5964 *pBoolOut
= sIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5968 /************************************************************************
5969 * VarBoolFromI4 (OLEAUT32.120)
5971 * Convert a VT_I4 to a VT_BOOL.
5975 * pBoolOut [O] Destination
5980 HRESULT WINAPI
VarBoolFromI4(LONG lIn
, VARIANT_BOOL
*pBoolOut
)
5982 *pBoolOut
= lIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5986 /************************************************************************
5987 * VarBoolFromR4 (OLEAUT32.121)
5989 * Convert a VT_R4 to a VT_BOOL.
5993 * pBoolOut [O] Destination
5998 HRESULT WINAPI
VarBoolFromR4(FLOAT fltIn
, VARIANT_BOOL
*pBoolOut
)
6000 *pBoolOut
= fltIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6004 /************************************************************************
6005 * VarBoolFromR8 (OLEAUT32.122)
6007 * Convert a VT_R8 to a VT_BOOL.
6011 * pBoolOut [O] Destination
6016 HRESULT WINAPI
VarBoolFromR8(double dblIn
, VARIANT_BOOL
*pBoolOut
)
6018 *pBoolOut
= dblIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6022 /************************************************************************
6023 * VarBoolFromDate (OLEAUT32.123)
6025 * Convert a VT_DATE to a VT_BOOL.
6029 * pBoolOut [O] Destination
6034 HRESULT WINAPI
VarBoolFromDate(DATE dateIn
, VARIANT_BOOL
*pBoolOut
)
6036 *pBoolOut
= dateIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6040 /************************************************************************
6041 * VarBoolFromCy (OLEAUT32.124)
6043 * Convert a VT_CY to a VT_BOOL.
6047 * pBoolOut [O] Destination
6052 HRESULT WINAPI
VarBoolFromCy(CY cyIn
, VARIANT_BOOL
*pBoolOut
)
6054 *pBoolOut
= cyIn
.int64
? VARIANT_TRUE
: VARIANT_FALSE
;
6058 /************************************************************************
6059 * VARIANT_GetLocalisedText [internal]
6061 * Get a localized string from the resources
6064 static BOOL
VARIANT_GetLocalisedText(LANGID langId
, DWORD dwId
, WCHAR
*lpszDest
)
6068 hrsrc
= FindResourceExW( hProxyDll
, (LPWSTR
)RT_STRING
,
6069 MAKEINTRESOURCEW((dwId
>> 4) + 1), langId
);
6072 HGLOBAL hmem
= LoadResource( hProxyDll
, hrsrc
);
6079 p
= LockResource( hmem
);
6080 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
6082 memcpy( lpszDest
, p
+ 1, *p
* sizeof(WCHAR
) );
6083 lpszDest
[*p
] = '\0';
6084 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest
), langId
);
6091 /************************************************************************
6092 * VarBoolFromStr (OLEAUT32.125)
6094 * Convert a VT_BSTR to a VT_BOOL.
6098 * lcid [I] LCID for the conversion
6099 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6100 * pBoolOut [O] Destination
6104 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6105 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6108 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6109 * it may contain (in any case mapping) the text "true" or "false".
6110 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6111 * localised text of "True" or "False" in the language specified by lcid.
6112 * - If none of these matches occur, the string is treated as a numeric string
6113 * and the boolean pBoolOut will be set according to whether the number is zero
6114 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6115 * - If the text is not numeric and does not match any of the above, then
6116 * DISP_E_TYPEMISMATCH is returned.
6118 HRESULT WINAPI
VarBoolFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, VARIANT_BOOL
*pBoolOut
)
6120 /* Any VB/VBA programmers out there should recognise these strings... */
6121 static const WCHAR szFalse
[] = { '#','F','A','L','S','E','#','\0' };
6122 static const WCHAR szTrue
[] = { '#','T','R','U','E','#','\0' };
6124 LANGID langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6125 HRESULT hRes
= S_OK
;
6127 if (!strIn
|| !pBoolOut
)
6128 return DISP_E_TYPEMISMATCH
;
6130 /* Check if we should be comparing against localised text */
6131 if (dwFlags
& VAR_LOCALBOOL
)
6133 /* Convert our LCID into a usable value */
6134 lcid
= ConvertDefaultLocale(lcid
);
6136 langId
= LANGIDFROMLCID(lcid
);
6138 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6139 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6141 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6142 * I don't think this is needed unless any of the localised text strings
6143 * contain characters that can be so mapped. In the event that this is
6144 * true for a given language (possibly some Asian languages), then strIn
6145 * should be mapped here _only_ if langId is an Id for which this can occur.
6149 /* Note that if we are not comparing against localised strings, langId
6150 * will have its default value of LANG_ENGLISH. This allows us to mimic
6151 * the native behaviour of always checking against English strings even
6152 * after we've checked for localised ones.
6154 VarBoolFromStr_CheckLocalised
:
6155 if (VARIANT_GetLocalisedText(langId
, IDS_TRUE
, szBuff
))
6157 /* Compare against localised strings, ignoring case */
6158 if (!strcmpiW(strIn
, szBuff
))
6160 *pBoolOut
= VARIANT_TRUE
; /* Matched localised 'true' text */
6163 VARIANT_GetLocalisedText(langId
, IDS_FALSE
, szBuff
);
6164 if (!strcmpiW(strIn
, szBuff
))
6166 *pBoolOut
= VARIANT_FALSE
; /* Matched localised 'false' text */
6171 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6173 /* We have checked the localised text, now check English */
6174 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6175 goto VarBoolFromStr_CheckLocalised
;
6178 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6179 if (!strcmpW(strIn
, szFalse
))
6180 *pBoolOut
= VARIANT_FALSE
;
6181 else if (!strcmpW(strIn
, szTrue
))
6182 *pBoolOut
= VARIANT_TRUE
;
6187 /* If this string is a number, convert it as one */
6188 hRes
= VarR8FromStr(strIn
, lcid
, dwFlags
, &d
);
6189 if (SUCCEEDED(hRes
)) *pBoolOut
= d
? VARIANT_TRUE
: VARIANT_FALSE
;
6194 /************************************************************************
6195 * VarBoolFromDisp (OLEAUT32.126)
6197 * Convert a VT_DISPATCH to a VT_BOOL.
6200 * pdispIn [I] Source
6201 * lcid [I] LCID for conversion
6202 * pBoolOut [O] Destination
6206 * Failure: E_INVALIDARG, if the source value is invalid
6207 * DISP_E_OVERFLOW, if the value will not fit in the destination
6208 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6210 HRESULT WINAPI
VarBoolFromDisp(IDispatch
* pdispIn
, LCID lcid
, VARIANT_BOOL
*pBoolOut
)
6212 return VARIANT_FromDisp(pdispIn
, lcid
, pBoolOut
, VT_BOOL
, 0);
6215 /************************************************************************
6216 * VarBoolFromI1 (OLEAUT32.233)
6218 * Convert a VT_I1 to a VT_BOOL.
6222 * pBoolOut [O] Destination
6227 HRESULT WINAPI
VarBoolFromI1(signed char cIn
, VARIANT_BOOL
*pBoolOut
)
6229 *pBoolOut
= cIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6233 /************************************************************************
6234 * VarBoolFromUI2 (OLEAUT32.234)
6236 * Convert a VT_UI2 to a VT_BOOL.
6240 * pBoolOut [O] Destination
6245 HRESULT WINAPI
VarBoolFromUI2(USHORT usIn
, VARIANT_BOOL
*pBoolOut
)
6247 *pBoolOut
= usIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6251 /************************************************************************
6252 * VarBoolFromUI4 (OLEAUT32.235)
6254 * Convert a VT_UI4 to a VT_BOOL.
6258 * pBoolOut [O] Destination
6263 HRESULT WINAPI
VarBoolFromUI4(ULONG ulIn
, VARIANT_BOOL
*pBoolOut
)
6265 *pBoolOut
= ulIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6269 /************************************************************************
6270 * VarBoolFromDec (OLEAUT32.236)
6272 * Convert a VT_DECIMAL to a VT_BOOL.
6276 * pBoolOut [O] Destination
6280 * Failure: E_INVALIDARG, if pDecIn is invalid.
6282 HRESULT WINAPI
VarBoolFromDec(DECIMAL
* pDecIn
, VARIANT_BOOL
*pBoolOut
)
6284 if (DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
|| (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
))
6285 return E_INVALIDARG
;
6287 if (DEC_HI32(pDecIn
) || DEC_MID32(pDecIn
) || DEC_LO32(pDecIn
))
6288 *pBoolOut
= VARIANT_TRUE
;
6290 *pBoolOut
= VARIANT_FALSE
;
6294 /************************************************************************
6295 * VarBoolFromI8 (OLEAUT32.370)
6297 * Convert a VT_I8 to a VT_BOOL.
6301 * pBoolOut [O] Destination
6306 HRESULT WINAPI
VarBoolFromI8(LONG64 llIn
, VARIANT_BOOL
*pBoolOut
)
6308 *pBoolOut
= llIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6312 /************************************************************************
6313 * VarBoolFromUI8 (OLEAUT32.371)
6315 * Convert a VT_UI8 to a VT_BOOL.
6319 * pBoolOut [O] Destination
6324 HRESULT WINAPI
VarBoolFromUI8(ULONG64 ullIn
, VARIANT_BOOL
*pBoolOut
)
6326 *pBoolOut
= ullIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6333 /* Write a number from a UI8 and sign */
6334 static WCHAR
*VARIANT_WriteNumber(ULONG64 ulVal
, WCHAR
* szOut
)
6338 WCHAR ulNextDigit
= ulVal
% 10;
6340 *szOut
-- = '0' + ulNextDigit
;
6341 ulVal
= (ulVal
- ulNextDigit
) / 10;
6348 /* Create a (possibly localised) BSTR from a UI8 and sign */
6349 static BSTR
VARIANT_MakeBstr(LCID lcid
, DWORD dwFlags
, WCHAR
*szOut
)
6351 WCHAR szConverted
[256];
6353 if (dwFlags
& VAR_NEGATIVE
)
6356 if (dwFlags
& LOCALE_USE_NLS
)
6358 /* Format the number for the locale */
6359 szConverted
[0] = '\0';
6360 GetNumberFormatW(lcid
,
6361 dwFlags
& LOCALE_NOUSEROVERRIDE
,
6362 szOut
, NULL
, szConverted
, sizeof(szConverted
)/sizeof(WCHAR
));
6363 szOut
= szConverted
;
6365 return SysAllocStringByteLen((LPCSTR
)szOut
, strlenW(szOut
) * sizeof(WCHAR
));
6368 /* Create a (possibly localised) BSTR from a UI8 and sign */
6369 static HRESULT
VARIANT_BstrFromUInt(ULONG64 ulVal
, LCID lcid
, DWORD dwFlags
, BSTR
*pbstrOut
)
6371 WCHAR szBuff
[64], *szOut
= szBuff
+ sizeof(szBuff
)/sizeof(WCHAR
) - 1;
6374 return E_INVALIDARG
;
6376 /* Create the basic number string */
6378 szOut
= VARIANT_WriteNumber(ulVal
, szOut
);
6380 *pbstrOut
= VARIANT_MakeBstr(lcid
, dwFlags
, szOut
);
6381 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6382 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6385 /******************************************************************************
6386 * VarBstrFromUI1 (OLEAUT32.108)
6388 * Convert a VT_UI1 to a VT_BSTR.
6392 * lcid [I] LCID for the conversion
6393 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6394 * pbstrOut [O] Destination
6398 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6399 * E_OUTOFMEMORY, if memory allocation fails.
6401 HRESULT WINAPI
VarBstrFromUI1(BYTE bIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6403 return VARIANT_BstrFromUInt(bIn
, lcid
, dwFlags
, pbstrOut
);
6406 /******************************************************************************
6407 * VarBstrFromI2 (OLEAUT32.109)
6409 * Convert a VT_I2 to a VT_BSTR.
6413 * lcid [I] LCID for the conversion
6414 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6415 * pbstrOut [O] Destination
6419 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6420 * E_OUTOFMEMORY, if memory allocation fails.
6422 HRESULT WINAPI
VarBstrFromI2(short sIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6429 dwFlags
|= VAR_NEGATIVE
;
6431 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6434 /******************************************************************************
6435 * VarBstrFromI4 (OLEAUT32.110)
6437 * Convert a VT_I4 to a VT_BSTR.
6441 * lcid [I] LCID for the conversion
6442 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6443 * pbstrOut [O] Destination
6447 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6448 * E_OUTOFMEMORY, if memory allocation fails.
6450 HRESULT WINAPI
VarBstrFromI4(LONG lIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6457 dwFlags
|= VAR_NEGATIVE
;
6459 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6462 static BSTR
VARIANT_BstrReplaceDecimal(const WCHAR
* buff
, LCID lcid
, ULONG dwFlags
)
6465 WCHAR lpDecimalSep
[16];
6467 /* Native oleaut32 uses the locale-specific decimal separator even in the
6468 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6469 American locales will see "one thousand and one tenth" as "1000,1"
6470 instead of "1000.1" (notice the comma). The following code checks for
6471 the need to replace the decimal separator, and if so, will prepare an
6472 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6474 GetLocaleInfoW(lcid
, LOCALE_SDECIMAL
| (dwFlags
& LOCALE_NOUSEROVERRIDE
),
6475 lpDecimalSep
, sizeof(lpDecimalSep
) / sizeof(WCHAR
));
6476 if (lpDecimalSep
[0] == '.' && lpDecimalSep
[1] == '\0')
6478 /* locale is compatible with English - return original string */
6479 bstrOut
= SysAllocString(buff
);
6485 WCHAR empty
[] = {'\0'};
6486 NUMBERFMTW minFormat
;
6488 minFormat
.NumDigits
= 0;
6489 minFormat
.LeadingZero
= 0;
6490 minFormat
.Grouping
= 0;
6491 minFormat
.lpDecimalSep
= lpDecimalSep
;
6492 minFormat
.lpThousandSep
= empty
;
6493 minFormat
.NegativeOrder
= 1; /* NLS_NEG_LEFT */
6495 /* count number of decimal digits in string */
6496 p
= strchrW( buff
, '.' );
6497 if (p
) minFormat
.NumDigits
= strlenW(p
+ 1);
6500 if (!GetNumberFormatW(lcid
, 0, buff
, &minFormat
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
)))
6502 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6503 bstrOut
= SysAllocString(buff
);
6507 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff
));
6508 bstrOut
= SysAllocString(numbuff
);
6514 static HRESULT
VARIANT_BstrFromReal(DOUBLE dblIn
, LCID lcid
, ULONG dwFlags
,
6515 BSTR
* pbstrOut
, LPCWSTR lpszFormat
)
6520 return E_INVALIDARG
;
6522 sprintfW( buff
, lpszFormat
, dblIn
);
6524 /* Negative zeroes are disallowed (some applications depend on this).
6525 If buff starts with a minus, and then nothing follows but zeroes
6526 and/or a period, it is a negative zero and is replaced with a
6527 canonical zero. This duplicates native oleaut32 behavior.
6531 const WCHAR szAccept
[] = {'0', '.', '\0'};
6532 if (strlenW(buff
+ 1) == strspnW(buff
+ 1, szAccept
))
6533 { buff
[0] = '0'; buff
[1] = '\0'; }
6536 TRACE("created string %s\n", debugstr_w(buff
));
6537 if (dwFlags
& LOCALE_USE_NLS
)
6541 /* Format the number for the locale */
6543 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6544 buff
, NULL
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
));
6545 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
6546 *pbstrOut
= SysAllocString(numbuff
);
6550 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
6552 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6555 /******************************************************************************
6556 * VarBstrFromR4 (OLEAUT32.111)
6558 * Convert a VT_R4 to a VT_BSTR.
6562 * lcid [I] LCID for the conversion
6563 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6564 * pbstrOut [O] Destination
6568 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6569 * E_OUTOFMEMORY, if memory allocation fails.
6571 HRESULT WINAPI
VarBstrFromR4(FLOAT fltIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6573 return VARIANT_BstrFromReal(fltIn
, lcid
, dwFlags
, pbstrOut
, szFloatFormatW
);
6576 /******************************************************************************
6577 * VarBstrFromR8 (OLEAUT32.112)
6579 * Convert a VT_R8 to a VT_BSTR.
6583 * lcid [I] LCID for the conversion
6584 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6585 * pbstrOut [O] Destination
6589 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6590 * E_OUTOFMEMORY, if memory allocation fails.
6592 HRESULT WINAPI
VarBstrFromR8(double dblIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6594 return VARIANT_BstrFromReal(dblIn
, lcid
, dwFlags
, pbstrOut
, szDoubleFormatW
);
6597 /******************************************************************************
6598 * VarBstrFromCy [OLEAUT32.113]
6600 * Convert a VT_CY to a VT_BSTR.
6604 * lcid [I] LCID for the conversion
6605 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6606 * pbstrOut [O] Destination
6610 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6611 * E_OUTOFMEMORY, if memory allocation fails.
6613 HRESULT WINAPI
VarBstrFromCy(CY cyIn
, LCID lcid
, ULONG dwFlags
, BSTR
*pbstrOut
)
6619 return E_INVALIDARG
;
6623 decVal
.bitsnum
[0] = cyIn
.s
.Lo
;
6624 decVal
.bitsnum
[1] = cyIn
.s
.Hi
;
6625 if (cyIn
.s
.Hi
& 0x80000000UL
) {
6628 /* Negative number! */
6630 decVal
.bitsnum
[0] = ~decVal
.bitsnum
[0];
6631 decVal
.bitsnum
[1] = ~decVal
.bitsnum
[1];
6632 VARIANT_int_add(decVal
.bitsnum
, 3, &one
, 1);
6634 decVal
.bitsnum
[2] = 0;
6635 VARIANT_DI_tostringW(&decVal
, buff
, sizeof(buff
)/sizeof(buff
[0]));
6637 if (dwFlags
& LOCALE_USE_NLS
)
6641 /* Format the currency for the locale */
6643 GetCurrencyFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6644 buff
, NULL
, cybuff
, sizeof(cybuff
) / sizeof(WCHAR
));
6645 *pbstrOut
= SysAllocString(cybuff
);
6648 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
,lcid
,dwFlags
);
6650 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6653 static inline int output_int_len(int o
, int min_len
, WCHAR
*date
, int date_len
)
6657 if(min_len
>= date_len
)
6660 for(len
=0, tmp
=o
; tmp
; tmp
/=10) len
++;
6665 for(tmp
=min_len
-len
; tmp
>0; tmp
--)
6667 for(tmp
=len
; tmp
>0; tmp
--, o
/=10)
6668 date
[tmp
-1] = '0' + o
%10;
6669 return min_len
>len
? min_len
: len
;
6672 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6673 BOOL
get_date_format(LCID lcid
, DWORD flags
, const SYSTEMTIME
*st
,
6674 const WCHAR
*fmt
, WCHAR
*date
, int date_len
)
6676 static const LCTYPE dayname
[] = {
6677 LOCALE_SDAYNAME7
, LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
,
6678 LOCALE_SDAYNAME4
, LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
6680 static const LCTYPE sdayname
[] = {
6681 LOCALE_SABBREVDAYNAME7
, LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
,
6682 LOCALE_SABBREVDAYNAME3
, LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
,
6683 LOCALE_SABBREVDAYNAME6
6685 static const LCTYPE monthname
[] = {
6686 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
6687 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
6688 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
6690 static const LCTYPE smonthname
[] = {
6691 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
6692 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
6693 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
6694 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
6697 if(flags
& ~(LOCALE_NOUSEROVERRIDE
|VAR_DATEVALUEONLY
))
6698 FIXME("ignoring flags %x\n", flags
);
6699 flags
&= LOCALE_NOUSEROVERRIDE
;
6701 while(*fmt
&& date_len
) {
6709 while(*fmt
== *(fmt
+count
))
6717 count
= GetLocaleInfoW(lcid
, dayname
[st
->wDayOfWeek
] | flags
, date
, date_len
)-1;
6719 count
= GetLocaleInfoW(lcid
, sdayname
[st
->wDayOfWeek
] | flags
, date
, date_len
)-1;
6721 count
= output_int_len(st
->wDay
, count
, date
, date_len
);
6725 count
= GetLocaleInfoW(lcid
, monthname
[st
->wMonth
-1] | flags
, date
, date_len
)-1;
6727 count
= GetLocaleInfoW(lcid
, smonthname
[st
->wMonth
-1] | flags
, date
, date_len
)-1;
6729 count
= output_int_len(st
->wMonth
, count
, date
, date_len
);
6733 count
= output_int_len(st
->wYear
, 0, date
, date_len
);
6735 count
= output_int_len(st
->wYear
%100, count
, date
, date_len
);
6739 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6767 /******************************************************************************
6768 * VarBstrFromDate [OLEAUT32.114]
6770 * Convert a VT_DATE to a VT_BSTR.
6774 * lcid [I] LCID for the conversion
6775 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6776 * pbstrOut [O] Destination
6780 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6781 * E_OUTOFMEMORY, if memory allocation fails.
6783 HRESULT WINAPI
VarBstrFromDate(DATE dateIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6786 DWORD dwFormatFlags
= dwFlags
& LOCALE_NOUSEROVERRIDE
;
6787 WCHAR date
[128], fmt_buff
[80], *time
;
6789 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn
, lcid
, dwFlags
, pbstrOut
);
6791 if (!pbstrOut
|| !VariantTimeToSystemTime(dateIn
, &st
))
6792 return E_INVALIDARG
;
6796 if (dwFlags
& VAR_CALENDAR_THAI
)
6797 st
.wYear
+= 553; /* Use the Thai buddhist calendar year */
6798 else if (dwFlags
& (VAR_CALENDAR_HIJRI
|VAR_CALENDAR_GREGORIAN
))
6799 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6801 if (dwFlags
& LOCALE_USE_NLS
)
6802 dwFlags
&= ~(VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
);
6805 double whole
= dateIn
< 0 ? ceil(dateIn
) : floor(dateIn
);
6806 double partial
= dateIn
- whole
;
6809 dwFlags
|= VAR_TIMEVALUEONLY
;
6810 else if (partial
> -1e-12 && partial
< 1e-12)
6811 dwFlags
|= VAR_DATEVALUEONLY
;
6814 if (dwFlags
& VAR_TIMEVALUEONLY
)
6817 if (!GetLocaleInfoW(lcid
, LOCALE_SSHORTDATE
, fmt_buff
, sizeof(fmt_buff
)/sizeof(WCHAR
)) ||
6818 !get_date_format(lcid
, dwFlags
, &st
, fmt_buff
, date
, sizeof(date
)/sizeof(WCHAR
)))
6819 return E_INVALIDARG
;
6821 if (!(dwFlags
& VAR_DATEVALUEONLY
))
6823 time
= date
+ strlenW(date
);
6826 if (!GetTimeFormatW(lcid
, dwFormatFlags
, &st
, NULL
, time
,
6827 sizeof(date
)/sizeof(WCHAR
)-(time
-date
)))
6828 return E_INVALIDARG
;
6831 *pbstrOut
= SysAllocString(date
);
6833 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6834 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6837 /******************************************************************************
6838 * VarBstrFromBool (OLEAUT32.116)
6840 * Convert a VT_BOOL to a VT_BSTR.
6844 * lcid [I] LCID for the conversion
6845 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6846 * pbstrOut [O] Destination
6850 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6851 * E_OUTOFMEMORY, if memory allocation fails.
6854 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6855 * localised text of "True" or "False". To convert a bool into a
6856 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6858 HRESULT WINAPI
VarBstrFromBool(VARIANT_BOOL boolIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6861 DWORD dwResId
= IDS_TRUE
;
6864 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn
, lcid
, dwFlags
, pbstrOut
);
6867 return E_INVALIDARG
;
6869 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6870 * for variant formatting */
6871 switch (dwFlags
& (VAR_LOCALBOOL
|VAR_BOOLONOFF
|VAR_BOOLYESNO
))
6882 lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
),SORT_DEFAULT
);
6885 lcid
= ConvertDefaultLocale(lcid
);
6886 langId
= LANGIDFROMLCID(lcid
);
6887 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6888 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6890 if (boolIn
== VARIANT_FALSE
)
6891 dwResId
++; /* Use negative form */
6893 VarBstrFromBool_GetLocalised
:
6894 if (VARIANT_GetLocalisedText(langId
, dwResId
, szBuff
))
6896 *pbstrOut
= SysAllocString(szBuff
);
6897 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6900 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6902 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6903 goto VarBstrFromBool_GetLocalised
;
6906 /* Should never get here */
6907 WARN("Failed to load bool text!\n");
6908 return E_OUTOFMEMORY
;
6911 /******************************************************************************
6912 * VarBstrFromI1 (OLEAUT32.229)
6914 * Convert a VT_I1 to a VT_BSTR.
6918 * lcid [I] LCID for the conversion
6919 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6920 * pbstrOut [O] Destination
6924 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6925 * E_OUTOFMEMORY, if memory allocation fails.
6927 HRESULT WINAPI
VarBstrFromI1(signed char cIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6934 dwFlags
|= VAR_NEGATIVE
;
6936 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6939 /******************************************************************************
6940 * VarBstrFromUI2 (OLEAUT32.230)
6942 * Convert a VT_UI2 to a VT_BSTR.
6946 * lcid [I] LCID for the conversion
6947 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6948 * pbstrOut [O] Destination
6952 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6953 * E_OUTOFMEMORY, if memory allocation fails.
6955 HRESULT WINAPI
VarBstrFromUI2(USHORT usIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6957 return VARIANT_BstrFromUInt(usIn
, lcid
, dwFlags
, pbstrOut
);
6960 /******************************************************************************
6961 * VarBstrFromUI4 (OLEAUT32.231)
6963 * Convert a VT_UI4 to a VT_BSTR.
6967 * lcid [I] LCID for the conversion
6968 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6969 * pbstrOut [O] Destination
6973 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6974 * E_OUTOFMEMORY, if memory allocation fails.
6976 HRESULT WINAPI
VarBstrFromUI4(ULONG ulIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6978 return VARIANT_BstrFromUInt(ulIn
, lcid
, dwFlags
, pbstrOut
);
6981 /******************************************************************************
6982 * VarBstrFromDec (OLEAUT32.232)
6984 * Convert a VT_DECIMAL to a VT_BSTR.
6988 * lcid [I] LCID for the conversion
6989 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6990 * pbstrOut [O] Destination
6994 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6995 * E_OUTOFMEMORY, if memory allocation fails.
6997 HRESULT WINAPI
VarBstrFromDec(DECIMAL
* pDecIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7003 return E_INVALIDARG
;
7005 VARIANT_DIFromDec(pDecIn
, &temp
);
7006 VARIANT_DI_tostringW(&temp
, buff
, 256);
7008 if (dwFlags
& LOCALE_USE_NLS
)
7012 /* Format the number for the locale */
7014 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
7015 buff
, NULL
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
));
7016 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
7017 *pbstrOut
= SysAllocString(numbuff
);
7021 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
7024 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
7025 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
7028 /************************************************************************
7029 * VarBstrFromI8 (OLEAUT32.370)
7031 * Convert a VT_I8 to a VT_BSTR.
7035 * lcid [I] LCID for the conversion
7036 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7037 * pbstrOut [O] Destination
7041 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7042 * E_OUTOFMEMORY, if memory allocation fails.
7044 HRESULT WINAPI
VarBstrFromI8(LONG64 llIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7046 ULONG64 ul64
= llIn
;
7051 dwFlags
|= VAR_NEGATIVE
;
7053 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
7056 /************************************************************************
7057 * VarBstrFromUI8 (OLEAUT32.371)
7059 * Convert a VT_UI8 to a VT_BSTR.
7063 * lcid [I] LCID for the conversion
7064 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7065 * pbstrOut [O] Destination
7069 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7070 * E_OUTOFMEMORY, if memory allocation fails.
7072 HRESULT WINAPI
VarBstrFromUI8(ULONG64 ullIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7074 return VARIANT_BstrFromUInt(ullIn
, lcid
, dwFlags
, pbstrOut
);
7077 /************************************************************************
7078 * VarBstrFromDisp (OLEAUT32.115)
7080 * Convert a VT_DISPATCH to a BSTR.
7083 * pdispIn [I] Source
7084 * lcid [I] LCID for conversion
7085 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7086 * pbstrOut [O] Destination
7090 * Failure: E_INVALIDARG, if the source value is invalid
7091 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7093 HRESULT WINAPI
VarBstrFromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7095 return VARIANT_FromDisp(pdispIn
, lcid
, pbstrOut
, VT_BSTR
, dwFlags
);
7098 /**********************************************************************
7099 * VarBstrCat (OLEAUT32.313)
7101 * Concatenate two BSTR values.
7104 * pbstrLeft [I] Source
7105 * pbstrRight [I] Value to concatenate
7106 * pbstrOut [O] Destination
7110 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7111 * E_OUTOFMEMORY, if memory allocation fails.
7113 HRESULT WINAPI
VarBstrCat(BSTR pbstrLeft
, BSTR pbstrRight
, BSTR
*pbstrOut
)
7115 unsigned int lenLeft
, lenRight
;
7118 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
7119 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), pbstrOut
);
7122 return E_INVALIDARG
;
7124 /* use byte length here to properly handle ansi-allocated BSTRs */
7125 lenLeft
= pbstrLeft
? SysStringByteLen(pbstrLeft
) : 0;
7126 lenRight
= pbstrRight
? SysStringByteLen(pbstrRight
) : 0;
7128 *pbstrOut
= SysAllocStringByteLen(NULL
, lenLeft
+ lenRight
);
7130 return E_OUTOFMEMORY
;
7132 (*pbstrOut
)[0] = '\0';
7135 memcpy(*pbstrOut
, pbstrLeft
, lenLeft
);
7138 memcpy((CHAR
*)*pbstrOut
+ lenLeft
, pbstrRight
, lenRight
);
7140 TRACE("%s\n", debugstr_wn(*pbstrOut
, SysStringLen(*pbstrOut
)));
7144 /**********************************************************************
7145 * VarBstrCmp (OLEAUT32.314)
7147 * Compare two BSTR values.
7150 * pbstrLeft [I] Source
7151 * pbstrRight [I] Value to compare
7152 * lcid [I] LCID for the comparison
7153 * dwFlags [I] Flags to pass directly to CompareStringW().
7156 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7157 * than, equal to or greater than pbstrRight respectively.
7160 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7161 * states. A NULL BSTR pointer is equivalent to an empty string.
7162 * If LCID is equal to 0, a byte by byte comparison is performed.
7164 HRESULT WINAPI
VarBstrCmp(BSTR pbstrLeft
, BSTR pbstrRight
, LCID lcid
, DWORD dwFlags
)
7169 TRACE("%s,%s,%d,%08x\n",
7170 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
7171 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), lcid
, dwFlags
);
7173 if (!pbstrLeft
|| !*pbstrLeft
)
7175 if (pbstrRight
&& *pbstrRight
)
7178 else if (!pbstrRight
|| !*pbstrRight
)
7183 unsigned int lenLeft
= SysStringByteLen(pbstrLeft
);
7184 unsigned int lenRight
= SysStringByteLen(pbstrRight
);
7185 ret
= memcmp(pbstrLeft
, pbstrRight
, min(lenLeft
, lenRight
));
7190 if (lenLeft
< lenRight
)
7192 if (lenLeft
> lenRight
)
7198 unsigned int lenLeft
= SysStringLen(pbstrLeft
);
7199 unsigned int lenRight
= SysStringLen(pbstrRight
);
7201 if (lenLeft
== 0 || lenRight
== 0)
7203 if (lenLeft
== 0 && lenRight
== 0) return VARCMP_EQ
;
7204 return lenLeft
< lenRight
? VARCMP_LT
: VARCMP_GT
;
7207 hres
= CompareStringW(lcid
, dwFlags
, pbstrLeft
, lenLeft
,
7208 pbstrRight
, lenRight
) - CSTR_LESS_THAN
;
7209 TRACE("%d\n", hres
);
7218 /******************************************************************************
7219 * VarDateFromUI1 (OLEAUT32.88)
7221 * Convert a VT_UI1 to a VT_DATE.
7225 * pdateOut [O] Destination
7230 HRESULT WINAPI
VarDateFromUI1(BYTE bIn
, DATE
* pdateOut
)
7232 return VarR8FromUI1(bIn
, pdateOut
);
7235 /******************************************************************************
7236 * VarDateFromI2 (OLEAUT32.89)
7238 * Convert a VT_I2 to a VT_DATE.
7242 * pdateOut [O] Destination
7247 HRESULT WINAPI
VarDateFromI2(short sIn
, DATE
* pdateOut
)
7249 return VarR8FromI2(sIn
, pdateOut
);
7252 /******************************************************************************
7253 * VarDateFromI4 (OLEAUT32.90)
7255 * Convert a VT_I4 to a VT_DATE.
7259 * pdateOut [O] Destination
7264 HRESULT WINAPI
VarDateFromI4(LONG lIn
, DATE
* pdateOut
)
7266 return VarDateFromR8(lIn
, pdateOut
);
7269 /******************************************************************************
7270 * VarDateFromR4 (OLEAUT32.91)
7272 * Convert a VT_R4 to a VT_DATE.
7276 * pdateOut [O] Destination
7281 HRESULT WINAPI
VarDateFromR4(FLOAT fltIn
, DATE
* pdateOut
)
7283 return VarR8FromR4(fltIn
, pdateOut
);
7286 /******************************************************************************
7287 * VarDateFromR8 (OLEAUT32.92)
7289 * Convert a VT_R8 to a VT_DATE.
7293 * pdateOut [O] Destination
7298 HRESULT WINAPI
VarDateFromR8(double dblIn
, DATE
* pdateOut
)
7300 if (dblIn
<= (DATE_MIN
- 1.0) || dblIn
>= (DATE_MAX
+ 1.0)) return DISP_E_OVERFLOW
;
7301 *pdateOut
= (DATE
)dblIn
;
7305 /**********************************************************************
7306 * VarDateFromDisp (OLEAUT32.95)
7308 * Convert a VT_DISPATCH to a VT_DATE.
7311 * pdispIn [I] Source
7312 * lcid [I] LCID for conversion
7313 * pdateOut [O] Destination
7317 * Failure: E_INVALIDARG, if the source value is invalid
7318 * DISP_E_OVERFLOW, if the value will not fit in the destination
7319 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7321 HRESULT WINAPI
VarDateFromDisp(IDispatch
* pdispIn
, LCID lcid
, DATE
* pdateOut
)
7323 return VARIANT_FromDisp(pdispIn
, lcid
, pdateOut
, VT_DATE
, 0);
7326 /******************************************************************************
7327 * VarDateFromBool (OLEAUT32.96)
7329 * Convert a VT_BOOL to a VT_DATE.
7333 * pdateOut [O] Destination
7338 HRESULT WINAPI
VarDateFromBool(VARIANT_BOOL boolIn
, DATE
* pdateOut
)
7340 return VarR8FromBool(boolIn
, pdateOut
);
7343 /**********************************************************************
7344 * VarDateFromCy (OLEAUT32.93)
7346 * Convert a VT_CY to a VT_DATE.
7350 * pdateOut [O] Destination
7355 HRESULT WINAPI
VarDateFromCy(CY cyIn
, DATE
* pdateOut
)
7357 return VarR8FromCy(cyIn
, pdateOut
);
7360 /* Date string parsing */
7361 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7362 #define DP_DATESEP 0x02 /* Date separator */
7363 #define DP_MONTH 0x04 /* Month name */
7364 #define DP_AM 0x08 /* AM */
7365 #define DP_PM 0x10 /* PM */
7367 typedef struct tagDATEPARSE
7369 DWORD dwCount
; /* Number of fields found so far (maximum 6) */
7370 DWORD dwParseFlags
; /* Global parse flags (DP_ Flags above) */
7371 DWORD dwFlags
[6]; /* Flags for each field */
7372 DWORD dwValues
[6]; /* Value of each field */
7375 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7377 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7379 /* Determine if a day is valid in a given month of a given year */
7380 static BOOL
VARIANT_IsValidMonthDay(DWORD day
, DWORD month
, DWORD year
)
7382 static const BYTE days
[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7384 if (day
&& month
&& month
< 13)
7386 if (day
<= days
[month
] || (month
== 2 && day
== 29 && IsLeapYear(year
)))
7392 /* Possible orders for 3 numbers making up a date */
7393 #define ORDER_MDY 0x01
7394 #define ORDER_YMD 0x02
7395 #define ORDER_YDM 0x04
7396 #define ORDER_DMY 0x08
7397 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7399 /* Determine a date for a particular locale, from 3 numbers */
7400 static inline HRESULT
VARIANT_MakeDate(DATEPARSE
*dp
, DWORD iDate
,
7401 DWORD offset
, SYSTEMTIME
*st
)
7403 DWORD dwAllOrders
, dwTry
, dwCount
= 0, v1
, v2
, v3
;
7407 v1
= 30; /* Default to (Variant) 0 date part */
7410 goto VARIANT_MakeDate_OK
;
7413 v1
= dp
->dwValues
[offset
+ 0];
7414 v2
= dp
->dwValues
[offset
+ 1];
7415 if (dp
->dwCount
== 2)
7418 GetSystemTime(¤t
);
7422 v3
= dp
->dwValues
[offset
+ 2];
7424 TRACE("(%d,%d,%d,%d,%d)\n", v1
, v2
, v3
, iDate
, offset
);
7426 /* If one number must be a month (Because a month name was given), then only
7427 * consider orders with the month in that position.
7428 * If we took the current year as 'v3', then only allow a year in that position.
7430 if (dp
->dwFlags
[offset
+ 0] & DP_MONTH
)
7432 dwAllOrders
= ORDER_MDY
;
7434 else if (dp
->dwFlags
[offset
+ 1] & DP_MONTH
)
7436 dwAllOrders
= ORDER_DMY
;
7437 if (dp
->dwCount
> 2)
7438 dwAllOrders
|= ORDER_YMD
;
7440 else if (dp
->dwCount
> 2 && dp
->dwFlags
[offset
+ 2] & DP_MONTH
)
7442 dwAllOrders
= ORDER_YDM
;
7446 dwAllOrders
= ORDER_MDY
|ORDER_DMY
;
7447 if (dp
->dwCount
> 2)
7448 dwAllOrders
|= (ORDER_YMD
|ORDER_YDM
);
7451 VARIANT_MakeDate_Start
:
7452 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders
);
7460 /* First: Try the order given by iDate */
7463 case 0: dwTry
= dwAllOrders
& ORDER_MDY
; break;
7464 case 1: dwTry
= dwAllOrders
& ORDER_DMY
; break;
7465 default: dwTry
= dwAllOrders
& ORDER_YMD
; break;
7468 else if (dwCount
== 1)
7470 /* Second: Try all the orders compatible with iDate */
7473 case 0: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7474 case 1: dwTry
= dwAllOrders
& ~(ORDER_MDY
|ORDER_YDM
|ORDER_MYD
); break;
7475 default: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7480 /* Finally: Try any remaining orders */
7481 dwTry
= dwAllOrders
;
7484 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount
, dwTry
);
7490 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7492 if (dwTry
& ORDER_MDY
)
7494 if (VARIANT_IsValidMonthDay(v2
,v1
,v3
))
7497 goto VARIANT_MakeDate_OK
;
7499 dwAllOrders
&= ~ORDER_MDY
;
7501 if (dwTry
& ORDER_YMD
)
7503 if (VARIANT_IsValidMonthDay(v3
,v2
,v1
))
7506 goto VARIANT_MakeDate_OK
;
7508 dwAllOrders
&= ~ORDER_YMD
;
7510 if (dwTry
& ORDER_YDM
)
7512 if (VARIANT_IsValidMonthDay(v2
,v3
,v1
))
7516 goto VARIANT_MakeDate_OK
;
7518 dwAllOrders
&= ~ORDER_YDM
;
7520 if (dwTry
& ORDER_DMY
)
7522 if (VARIANT_IsValidMonthDay(v1
,v2
,v3
))
7523 goto VARIANT_MakeDate_OK
;
7524 dwAllOrders
&= ~ORDER_DMY
;
7526 if (dwTry
& ORDER_MYD
)
7528 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7529 if (VARIANT_IsValidMonthDay(v3
,v1
,v2
))
7533 goto VARIANT_MakeDate_OK
;
7535 dwAllOrders
&= ~ORDER_MYD
;
7539 if (dp
->dwCount
== 2)
7541 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7542 v3
= 1; /* 1st of the month */
7543 dwAllOrders
= ORDER_YMD
|ORDER_MYD
;
7544 dp
->dwCount
= 0; /* Don't return to this code path again */
7546 goto VARIANT_MakeDate_Start
;
7549 /* No valid dates were able to be constructed */
7550 return DISP_E_TYPEMISMATCH
;
7552 VARIANT_MakeDate_OK
:
7554 /* Check that the time part is ok */
7555 if (st
->wHour
> 23 || st
->wMinute
> 59 || st
->wSecond
> 59)
7556 return DISP_E_TYPEMISMATCH
;
7558 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7559 if (st
->wHour
< 12 && (dp
->dwParseFlags
& DP_PM
))
7561 else if (st
->wHour
== 12 && (dp
->dwParseFlags
& DP_AM
))
7563 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7567 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7568 * be retrieved from:
7569 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7570 * But Wine doesn't have/use that key as at the time of writing.
7572 st
->wYear
= v3
< 30 ? 2000 + v3
: v3
< 100 ? 1900 + v3
: v3
;
7573 TRACE("Returning date %d/%d/%d\n", v1
, v2
, st
->wYear
);
7577 /******************************************************************************
7578 * VarDateFromStr [OLEAUT32.94]
7580 * Convert a VT_BSTR to at VT_DATE.
7583 * strIn [I] String to convert
7584 * lcid [I] Locale identifier for the conversion
7585 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7586 * pdateOut [O] Destination for the converted value
7589 * Success: S_OK. pdateOut contains the converted value.
7590 * FAILURE: An HRESULT error code indicating the problem.
7593 * Any date format that can be created using the date formats from lcid
7594 * (Either from kernel Nls functions, variant conversion or formatting) is a
7595 * valid input to this function. In addition, a few more esoteric formats are
7596 * also supported for compatibility with the native version. The date is
7597 * interpreted according to the date settings in the control panel, unless
7598 * the date is invalid in that format, in which the most compatible format
7599 * that produces a valid date will be used.
7601 HRESULT WINAPI
VarDateFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DATE
* pdateOut
)
7603 static const USHORT ParseDateTokens
[] =
7605 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
7606 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
7607 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
,
7608 LOCALE_SMONTHNAME13
,
7609 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
7610 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
7611 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
7612 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
,
7613 LOCALE_SABBREVMONTHNAME13
,
7614 LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
, LOCALE_SDAYNAME4
,
7615 LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
, LOCALE_SDAYNAME7
,
7616 LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
, LOCALE_SABBREVDAYNAME3
,
7617 LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
, LOCALE_SABBREVDAYNAME6
,
7618 LOCALE_SABBREVDAYNAME7
,
7619 LOCALE_S1159
, LOCALE_S2359
,
7622 static const BYTE ParseDateMonths
[] =
7624 1,2,3,4,5,6,7,8,9,10,11,12,13,
7625 1,2,3,4,5,6,7,8,9,10,11,12,13
7628 BSTR tokens
[sizeof(ParseDateTokens
)/sizeof(ParseDateTokens
[0])];
7630 DWORD dwDateSeps
= 0, iDate
= 0;
7631 HRESULT hRet
= S_OK
;
7633 if ((dwFlags
& (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
)) ==
7634 (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
))
7635 return E_INVALIDARG
;
7638 return DISP_E_TYPEMISMATCH
;
7642 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn
), lcid
, dwFlags
, pdateOut
);
7644 memset(&dp
, 0, sizeof(dp
));
7646 GetLocaleInfoW(lcid
, LOCALE_IDATE
|LOCALE_RETURN_NUMBER
|(dwFlags
& LOCALE_NOUSEROVERRIDE
),
7647 (LPWSTR
)&iDate
, sizeof(iDate
)/sizeof(WCHAR
));
7648 TRACE("iDate is %d\n", iDate
);
7650 /* Get the month/day/am/pm tokens for this locale */
7651 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7654 LCTYPE lctype
= ParseDateTokens
[i
] | (dwFlags
& LOCALE_NOUSEROVERRIDE
);
7656 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7657 * GetAltMonthNames(). We should really cache these strings too.
7660 GetLocaleInfoW(lcid
, lctype
, buff
, sizeof(buff
)/sizeof(WCHAR
));
7661 tokens
[i
] = SysAllocString(buff
);
7662 TRACE("token %d is %s\n", i
, debugstr_w(tokens
[i
]));
7665 /* Parse the string into our structure */
7668 if (isdigitW(*strIn
))
7670 if (dp
.dwCount
>= 6)
7672 hRet
= DISP_E_TYPEMISMATCH
;
7675 dp
.dwValues
[dp
.dwCount
] = strtoulW(strIn
, &strIn
, 10);
7679 else if (isalphaW(*strIn
))
7681 BOOL bFound
= FALSE
;
7683 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7685 DWORD dwLen
= strlenW(tokens
[i
]);
7686 if (dwLen
&& !strncmpiW(strIn
, tokens
[i
], dwLen
))
7690 if (dp
.dwCount
>= 6)
7691 hRet
= DISP_E_TYPEMISMATCH
;
7694 dp
.dwValues
[dp
.dwCount
] = ParseDateMonths
[i
];
7695 dp
.dwFlags
[dp
.dwCount
] |= (DP_MONTH
|DP_DATESEP
);
7699 else if (i
> 39 && i
< 42)
7701 if (!dp
.dwCount
|| dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7702 hRet
= DISP_E_TYPEMISMATCH
;
7705 dp
.dwFlags
[dp
.dwCount
- 1] |= (i
== 40 ? DP_AM
: DP_PM
);
7706 dp
.dwParseFlags
|= (i
== 40 ? DP_AM
: DP_PM
);
7709 strIn
+= (dwLen
- 1);
7717 if ((*strIn
== 'a' || *strIn
== 'A' || *strIn
== 'p' || *strIn
== 'P') &&
7718 (dp
.dwCount
&& !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7720 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7721 if (*strIn
== 'a' || *strIn
== 'A')
7723 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_AM
;
7724 dp
.dwParseFlags
|= DP_AM
;
7728 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_PM
;
7729 dp
.dwParseFlags
|= DP_PM
;
7735 TRACE("No matching token for %s\n", debugstr_w(strIn
));
7736 hRet
= DISP_E_TYPEMISMATCH
;
7741 else if (*strIn
== ':' || *strIn
== '.')
7743 if (!dp
.dwCount
|| !strIn
[1])
7744 hRet
= DISP_E_TYPEMISMATCH
;
7746 if (tokens
[42][0] == *strIn
)
7750 hRet
= DISP_E_TYPEMISMATCH
;
7752 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7755 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_TIMESEP
;
7757 else if (*strIn
== '-' || *strIn
== '/')
7760 if (dwDateSeps
> 2 || !dp
.dwCount
|| !strIn
[1])
7761 hRet
= DISP_E_TYPEMISMATCH
;
7763 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7765 else if (*strIn
== ',' || isspaceW(*strIn
))
7767 if (*strIn
== ',' && !strIn
[1])
7768 hRet
= DISP_E_TYPEMISMATCH
;
7772 hRet
= DISP_E_TYPEMISMATCH
;
7777 if (!dp
.dwCount
|| dp
.dwCount
> 6 ||
7778 (dp
.dwCount
== 1 && !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7779 hRet
= DISP_E_TYPEMISMATCH
;
7781 if (SUCCEEDED(hRet
))
7784 DWORD dwOffset
= 0; /* Start of date fields in dp.dwValues */
7786 st
.wDayOfWeek
= st
.wHour
= st
.wMinute
= st
.wSecond
= st
.wMilliseconds
= 0;
7788 /* Figure out which numbers correspond to which fields.
7790 * This switch statement works based on the fact that native interprets any
7791 * fields that are not joined with a time separator ('.' or ':') as date
7792 * fields. Thus we construct a value from 0-32 where each set bit indicates
7793 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7794 * For valid permutations, we set dwOffset to point to the first date field
7795 * and shorten dp.dwCount by the number of time fields found. The real
7796 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7797 * each date number must represent in the context of iDate.
7799 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7801 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7803 case 0x1: /* TT TTDD TTDDD */
7804 if (dp
.dwCount
> 3 &&
7805 ((dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) ||
7806 (dp
.dwFlags
[4] & (DP_AM
|DP_PM
))))
7807 hRet
= DISP_E_TYPEMISMATCH
;
7808 else if (dp
.dwCount
!= 2 && dp
.dwCount
!= 4 && dp
.dwCount
!= 5)
7809 hRet
= DISP_E_TYPEMISMATCH
;
7810 st
.wHour
= dp
.dwValues
[0];
7811 st
.wMinute
= dp
.dwValues
[1];
7816 case 0x3: /* TTT TTTDD TTTDDD */
7817 if (dp
.dwCount
> 4 &&
7818 ((dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[4] & (DP_AM
|DP_PM
)) ||
7819 (dp
.dwFlags
[5] & (DP_AM
|DP_PM
))))
7820 hRet
= DISP_E_TYPEMISMATCH
;
7821 else if (dp
.dwCount
!= 3 && dp
.dwCount
!= 5 && dp
.dwCount
!= 6)
7822 hRet
= DISP_E_TYPEMISMATCH
;
7823 st
.wHour
= dp
.dwValues
[0];
7824 st
.wMinute
= dp
.dwValues
[1];
7825 st
.wSecond
= dp
.dwValues
[2];
7830 case 0x4: /* DDTT */
7831 if (dp
.dwCount
!= 4 ||
7832 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7833 hRet
= DISP_E_TYPEMISMATCH
;
7835 st
.wHour
= dp
.dwValues
[2];
7836 st
.wMinute
= dp
.dwValues
[3];
7840 case 0x0: /* T DD DDD TDDD TDDD */
7841 if (dp
.dwCount
== 1 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7843 st
.wHour
= dp
.dwValues
[0]; /* T */
7847 else if (dp
.dwCount
> 4 || (dp
.dwCount
< 3 && dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7849 hRet
= DISP_E_TYPEMISMATCH
;
7851 else if (dp
.dwCount
== 3)
7853 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDD */
7856 st
.wHour
= dp
.dwValues
[0];
7860 if (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) /* DDT */
7863 st
.wHour
= dp
.dwValues
[2];
7866 else if (dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7867 hRet
= DISP_E_TYPEMISMATCH
;
7869 else if (dp
.dwCount
== 4)
7872 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDDD */
7874 st
.wHour
= dp
.dwValues
[0];
7877 else if (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) /* DDDT */
7879 st
.wHour
= dp
.dwValues
[3];
7882 hRet
= DISP_E_TYPEMISMATCH
;
7885 /* .. fall through .. */
7887 case 0x8: /* DDDTT */
7888 if ((dp
.dwCount
== 2 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
))) ||
7889 (dp
.dwCount
== 5 && ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) ||
7890 (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))) ||
7891 dp
.dwCount
== 4 || dp
.dwCount
== 6)
7892 hRet
= DISP_E_TYPEMISMATCH
;
7893 st
.wHour
= dp
.dwValues
[3];
7894 st
.wMinute
= dp
.dwValues
[4];
7895 if (dp
.dwCount
== 5)
7899 case 0xC: /* DDTTT */
7900 if (dp
.dwCount
!= 5 ||
7901 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7902 hRet
= DISP_E_TYPEMISMATCH
;
7903 st
.wHour
= dp
.dwValues
[2];
7904 st
.wMinute
= dp
.dwValues
[3];
7905 st
.wSecond
= dp
.dwValues
[4];
7909 case 0x18: /* DDDTTT */
7910 if ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) ||
7911 (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))
7912 hRet
= DISP_E_TYPEMISMATCH
;
7913 st
.wHour
= dp
.dwValues
[3];
7914 st
.wMinute
= dp
.dwValues
[4];
7915 st
.wSecond
= dp
.dwValues
[5];
7920 hRet
= DISP_E_TYPEMISMATCH
;
7924 if (SUCCEEDED(hRet
))
7926 hRet
= VARIANT_MakeDate(&dp
, iDate
, dwOffset
, &st
);
7928 if (dwFlags
& VAR_TIMEVALUEONLY
)
7934 else if (dwFlags
& VAR_DATEVALUEONLY
)
7935 st
.wHour
= st
.wMinute
= st
.wSecond
= 0;
7937 /* Finally, convert the value to a VT_DATE */
7938 if (SUCCEEDED(hRet
))
7939 hRet
= SystemTimeToVariantTime(&st
, pdateOut
) ? S_OK
: DISP_E_TYPEMISMATCH
;
7943 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7944 SysFreeString(tokens
[i
]);
7948 /******************************************************************************
7949 * VarDateFromI1 (OLEAUT32.221)
7951 * Convert a VT_I1 to a VT_DATE.
7955 * pdateOut [O] Destination
7960 HRESULT WINAPI
VarDateFromI1(signed char cIn
, DATE
* pdateOut
)
7962 return VarR8FromI1(cIn
, pdateOut
);
7965 /******************************************************************************
7966 * VarDateFromUI2 (OLEAUT32.222)
7968 * Convert a VT_UI2 to a VT_DATE.
7972 * pdateOut [O] Destination
7977 HRESULT WINAPI
VarDateFromUI2(USHORT uiIn
, DATE
* pdateOut
)
7979 return VarR8FromUI2(uiIn
, pdateOut
);
7982 /******************************************************************************
7983 * VarDateFromUI4 (OLEAUT32.223)
7985 * Convert a VT_UI4 to a VT_DATE.
7989 * pdateOut [O] Destination
7994 HRESULT WINAPI
VarDateFromUI4(ULONG ulIn
, DATE
* pdateOut
)
7996 return VarDateFromR8(ulIn
, pdateOut
);
7999 /**********************************************************************
8000 * VarDateFromDec (OLEAUT32.224)
8002 * Convert a VT_DECIMAL to a VT_DATE.
8006 * pdateOut [O] Destination
8011 HRESULT WINAPI
VarDateFromDec(DECIMAL
*pdecIn
, DATE
* pdateOut
)
8013 return VarR8FromDec(pdecIn
, pdateOut
);
8016 /******************************************************************************
8017 * VarDateFromI8 (OLEAUT32.364)
8019 * Convert a VT_I8 to a VT_DATE.
8023 * pdateOut [O] Destination
8027 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8029 HRESULT WINAPI
VarDateFromI8(LONG64 llIn
, DATE
* pdateOut
)
8031 if (llIn
< DATE_MIN
|| llIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
8032 *pdateOut
= (DATE
)llIn
;
8036 /******************************************************************************
8037 * VarDateFromUI8 (OLEAUT32.365)
8039 * Convert a VT_UI8 to a VT_DATE.
8043 * pdateOut [O] Destination
8047 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8049 HRESULT WINAPI
VarDateFromUI8(ULONG64 ullIn
, DATE
* pdateOut
)
8051 if (ullIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
8052 *pdateOut
= (DATE
)ullIn
;