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 OLEAUT32_hModule
;
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 const 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 hRet
= IDispatch_Invoke(pdispIn
, DISPID_VALUE
, &IID_NULL
, lcid
, DISPATCH_PROPERTYGET
,
126 (DISPPARAMS
*)&emptyParams
, &srcVar
, NULL
, NULL
);
130 /* Convert the property to the requested type */
131 V_VT(&dstVar
) = VT_EMPTY
;
132 hRet
= VariantChangeTypeEx(&dstVar
, &srcVar
, lcid
, dwFlags
, vt
);
133 VariantClear(&srcVar
);
137 VARIANT_CopyData(&dstVar
, vt
, pOut
);
138 VariantClear(&srcVar
);
142 hRet
= DISP_E_TYPEMISMATCH
;
146 /* Inline return type */
147 #define RETTYP inline static HRESULT
150 /* Simple compiler cast from one type to another */
151 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
152 *out = in; return S_OK; }
154 /* Compiler cast where input cannot be negative */
155 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
156 if (in < (src)0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
158 /* Compiler cast where input cannot be > some number */
159 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
160 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
162 /* Compiler cast where input cannot be < some number or >= some other number */
163 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
164 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
167 POSTST(signed char, BYTE
, VarI1FromUI1
, I1_MAX
);
168 BOTHTST(signed char, SHORT
, VarI1FromI2
, I1_MIN
, I1_MAX
);
169 BOTHTST(signed char, LONG
, VarI1FromI4
, I1_MIN
, I1_MAX
);
170 SIMPLE(signed char, VARIANT_BOOL
, VarI1FromBool
);
171 POSTST(signed char, USHORT
, VarI1FromUI2
, I1_MAX
);
172 POSTST(signed char, ULONG
, VarI1FromUI4
, I1_MAX
);
173 BOTHTST(signed char, LONG64
, VarI1FromI8
, I1_MIN
, I1_MAX
);
174 POSTST(signed char, ULONG64
, VarI1FromUI8
, I1_MAX
);
177 BOTHTST(BYTE
, SHORT
, VarUI1FromI2
, UI1_MIN
, UI1_MAX
);
178 SIMPLE(BYTE
, VARIANT_BOOL
, VarUI1FromBool
);
179 NEGTST(BYTE
, signed char, VarUI1FromI1
);
180 POSTST(BYTE
, USHORT
, VarUI1FromUI2
, UI1_MAX
);
181 BOTHTST(BYTE
, LONG
, VarUI1FromI4
, UI1_MIN
, UI1_MAX
);
182 POSTST(BYTE
, ULONG
, VarUI1FromUI4
, UI1_MAX
);
183 BOTHTST(BYTE
, LONG64
, VarUI1FromI8
, UI1_MIN
, UI1_MAX
);
184 POSTST(BYTE
, ULONG64
, VarUI1FromUI8
, UI1_MAX
);
187 SIMPLE(SHORT
, BYTE
, VarI2FromUI1
);
188 BOTHTST(SHORT
, LONG
, VarI2FromI4
, I2_MIN
, I2_MAX
);
189 SIMPLE(SHORT
, VARIANT_BOOL
, VarI2FromBool
);
190 SIMPLE(SHORT
, signed char, VarI2FromI1
);
191 POSTST(SHORT
, USHORT
, VarI2FromUI2
, I2_MAX
);
192 POSTST(SHORT
, ULONG
, VarI2FromUI4
, I2_MAX
);
193 BOTHTST(SHORT
, LONG64
, VarI2FromI8
, I2_MIN
, I2_MAX
);
194 POSTST(SHORT
, ULONG64
, VarI2FromUI8
, I2_MAX
);
197 SIMPLE(USHORT
, BYTE
, VarUI2FromUI1
);
198 NEGTST(USHORT
, SHORT
, VarUI2FromI2
);
199 BOTHTST(USHORT
, LONG
, VarUI2FromI4
, UI2_MIN
, UI2_MAX
);
200 SIMPLE(USHORT
, VARIANT_BOOL
, VarUI2FromBool
);
201 NEGTST(USHORT
, signed char, VarUI2FromI1
);
202 POSTST(USHORT
, ULONG
, VarUI2FromUI4
, UI2_MAX
);
203 BOTHTST(USHORT
, LONG64
, VarUI2FromI8
, UI2_MIN
, UI2_MAX
);
204 POSTST(USHORT
, ULONG64
, VarUI2FromUI8
, UI2_MAX
);
207 SIMPLE(LONG
, BYTE
, VarI4FromUI1
);
208 SIMPLE(LONG
, SHORT
, VarI4FromI2
);
209 SIMPLE(LONG
, VARIANT_BOOL
, VarI4FromBool
);
210 SIMPLE(LONG
, signed char, VarI4FromI1
);
211 SIMPLE(LONG
, USHORT
, VarI4FromUI2
);
212 POSTST(LONG
, ULONG
, VarI4FromUI4
, I4_MAX
);
213 BOTHTST(LONG
, LONG64
, VarI4FromI8
, I4_MIN
, I4_MAX
);
214 POSTST(LONG
, ULONG64
, VarI4FromUI8
, I4_MAX
);
217 SIMPLE(ULONG
, BYTE
, VarUI4FromUI1
);
218 NEGTST(ULONG
, SHORT
, VarUI4FromI2
);
219 NEGTST(ULONG
, LONG
, VarUI4FromI4
);
220 SIMPLE(ULONG
, VARIANT_BOOL
, VarUI4FromBool
);
221 NEGTST(ULONG
, signed char, VarUI4FromI1
);
222 SIMPLE(ULONG
, USHORT
, VarUI4FromUI2
);
223 BOTHTST(ULONG
, LONG64
, VarUI4FromI8
, UI4_MIN
, UI4_MAX
);
224 POSTST(ULONG
, ULONG64
, VarUI4FromUI8
, UI4_MAX
);
227 SIMPLE(LONG64
, BYTE
, VarI8FromUI1
);
228 SIMPLE(LONG64
, SHORT
, VarI8FromI2
);
229 SIMPLE(LONG64
, signed char, VarI8FromI1
);
230 SIMPLE(LONG64
, USHORT
, VarI8FromUI2
);
231 SIMPLE(LONG64
, LONG
, VarI8FromI4
);
232 SIMPLE(LONG64
, ULONG
, VarI8FromUI4
);
233 POSTST(LONG64
, ULONG64
, VarI8FromUI8
, I8_MAX
);
236 SIMPLE(ULONG64
, BYTE
, VarUI8FromUI1
);
237 NEGTST(ULONG64
, SHORT
, VarUI8FromI2
);
238 NEGTST(ULONG64
, signed char, VarUI8FromI1
);
239 SIMPLE(ULONG64
, USHORT
, VarUI8FromUI2
);
240 NEGTST(ULONG64
, LONG
, VarUI8FromI4
);
241 SIMPLE(ULONG64
, ULONG
, VarUI8FromUI4
);
242 NEGTST(ULONG64
, LONG64
, VarUI8FromI8
);
245 SIMPLE(float, BYTE
, VarR4FromUI1
);
246 SIMPLE(float, SHORT
, VarR4FromI2
);
247 SIMPLE(float, signed char, VarR4FromI1
);
248 SIMPLE(float, USHORT
, VarR4FromUI2
);
249 SIMPLE(float, LONG
, VarR4FromI4
);
250 SIMPLE(float, ULONG
, VarR4FromUI4
);
251 SIMPLE(float, LONG64
, VarR4FromI8
);
252 SIMPLE(float, ULONG64
, VarR4FromUI8
);
255 SIMPLE(double, BYTE
, VarR8FromUI1
);
256 SIMPLE(double, SHORT
, VarR8FromI2
);
257 SIMPLE(double, float, VarR8FromR4
);
258 RETTYP
_VarR8FromCy(CY i
, double* o
) { *o
= (double)i
.int64
/ CY_MULTIPLIER_F
; return S_OK
; }
259 SIMPLE(double, DATE
, VarR8FromDate
);
260 SIMPLE(double, signed char, VarR8FromI1
);
261 SIMPLE(double, USHORT
, VarR8FromUI2
);
262 SIMPLE(double, LONG
, VarR8FromI4
);
263 SIMPLE(double, ULONG
, VarR8FromUI4
);
264 SIMPLE(double, LONG64
, VarR8FromI8
);
265 SIMPLE(double, ULONG64
, VarR8FromUI8
);
271 /************************************************************************
272 * VarI1FromUI1 (OLEAUT32.244)
274 * Convert a VT_UI1 to a VT_I1.
278 * pcOut [O] Destination
282 * Failure: E_INVALIDARG, if the source value is invalid
283 * DISP_E_OVERFLOW, if the value will not fit in the destination
285 HRESULT WINAPI
VarI1FromUI1(BYTE bIn
, signed char* pcOut
)
287 return _VarI1FromUI1(bIn
, pcOut
);
290 /************************************************************************
291 * VarI1FromI2 (OLEAUT32.245)
293 * Convert a VT_I2 to a VT_I1.
297 * pcOut [O] Destination
301 * Failure: E_INVALIDARG, if the source value is invalid
302 * DISP_E_OVERFLOW, if the value will not fit in the destination
304 HRESULT WINAPI
VarI1FromI2(SHORT sIn
, signed char* pcOut
)
306 return _VarI1FromI2(sIn
, pcOut
);
309 /************************************************************************
310 * VarI1FromI4 (OLEAUT32.246)
312 * Convert a VT_I4 to a VT_I1.
316 * pcOut [O] Destination
320 * Failure: E_INVALIDARG, if the source value is invalid
321 * DISP_E_OVERFLOW, if the value will not fit in the destination
323 HRESULT WINAPI
VarI1FromI4(LONG iIn
, signed char* pcOut
)
325 return _VarI1FromI4(iIn
, pcOut
);
328 /************************************************************************
329 * VarI1FromR4 (OLEAUT32.247)
331 * Convert a VT_R4 to a VT_I1.
335 * pcOut [O] Destination
339 * Failure: E_INVALIDARG, if the source value is invalid
340 * DISP_E_OVERFLOW, if the value will not fit in the destination
342 HRESULT WINAPI
VarI1FromR4(FLOAT fltIn
, signed char* pcOut
)
344 return VarI1FromR8(fltIn
, pcOut
);
347 /************************************************************************
348 * VarI1FromR8 (OLEAUT32.248)
350 * Convert a VT_R8 to a VT_I1.
354 * pcOut [O] Destination
358 * Failure: E_INVALIDARG, if the source value is invalid
359 * DISP_E_OVERFLOW, if the value will not fit in the destination
362 * See VarI8FromR8() for details concerning rounding.
364 HRESULT WINAPI
VarI1FromR8(double dblIn
, signed char* pcOut
)
366 if (dblIn
< (double)I1_MIN
|| dblIn
> (double)I1_MAX
)
367 return DISP_E_OVERFLOW
;
368 VARIANT_DutchRound(CHAR
, dblIn
, *pcOut
);
372 /************************************************************************
373 * VarI1FromDate (OLEAUT32.249)
375 * Convert a VT_DATE to a VT_I1.
379 * pcOut [O] Destination
383 * Failure: E_INVALIDARG, if the source value is invalid
384 * DISP_E_OVERFLOW, if the value will not fit in the destination
386 HRESULT WINAPI
VarI1FromDate(DATE dateIn
, signed char* pcOut
)
388 return VarI1FromR8(dateIn
, pcOut
);
391 /************************************************************************
392 * VarI1FromCy (OLEAUT32.250)
394 * Convert a VT_CY to a VT_I1.
398 * pcOut [O] Destination
402 * Failure: E_INVALIDARG, if the source value is invalid
403 * DISP_E_OVERFLOW, if the value will not fit in the destination
405 HRESULT WINAPI
VarI1FromCy(CY cyIn
, signed char* pcOut
)
409 VarI4FromCy(cyIn
, &i
);
410 return _VarI1FromI4(i
, pcOut
);
413 /************************************************************************
414 * VarI1FromStr (OLEAUT32.251)
416 * Convert a VT_BSTR to a VT_I1.
420 * lcid [I] LCID for the conversion
421 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
422 * pcOut [O] Destination
426 * Failure: E_INVALIDARG, if the source value is invalid
427 * DISP_E_OVERFLOW, if the value will not fit in the destination
428 * DISP_E_TYPEMISMATCH, if the type cannot be converted
430 HRESULT WINAPI
VarI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, signed char* pcOut
)
432 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pcOut
, VT_I1
);
435 /************************************************************************
436 * VarI1FromDisp (OLEAUT32.252)
438 * Convert a VT_DISPATCH to a VT_I1.
442 * lcid [I] LCID for conversion
443 * pcOut [O] Destination
447 * Failure: E_INVALIDARG, if the source value is invalid
448 * DISP_E_OVERFLOW, if the value will not fit in the destination
449 * DISP_E_TYPEMISMATCH, if the type cannot be converted
451 HRESULT WINAPI
VarI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, signed char* pcOut
)
453 return VARIANT_FromDisp(pdispIn
, lcid
, pcOut
, VT_I1
, 0);
456 /************************************************************************
457 * VarI1FromBool (OLEAUT32.253)
459 * Convert a VT_BOOL to a VT_I1.
463 * pcOut [O] Destination
468 HRESULT WINAPI
VarI1FromBool(VARIANT_BOOL boolIn
, signed char* pcOut
)
470 return _VarI1FromBool(boolIn
, pcOut
);
473 /************************************************************************
474 * VarI1FromUI2 (OLEAUT32.254)
476 * Convert a VT_UI2 to a VT_I1.
480 * pcOut [O] Destination
484 * Failure: E_INVALIDARG, if the source value is invalid
485 * DISP_E_OVERFLOW, if the value will not fit in the destination
487 HRESULT WINAPI
VarI1FromUI2(USHORT usIn
, signed char* pcOut
)
489 return _VarI1FromUI2(usIn
, pcOut
);
492 /************************************************************************
493 * VarI1FromUI4 (OLEAUT32.255)
495 * Convert a VT_UI4 to a VT_I1.
499 * pcOut [O] Destination
503 * Failure: E_INVALIDARG, if the source value is invalid
504 * DISP_E_OVERFLOW, if the value will not fit in the destination
505 * DISP_E_TYPEMISMATCH, if the type cannot be converted
507 HRESULT WINAPI
VarI1FromUI4(ULONG ulIn
, signed char* pcOut
)
509 return _VarI1FromUI4(ulIn
, pcOut
);
512 /************************************************************************
513 * VarI1FromDec (OLEAUT32.256)
515 * Convert a VT_DECIMAL to a VT_I1.
519 * pcOut [O] Destination
523 * Failure: E_INVALIDARG, if the source value is invalid
524 * DISP_E_OVERFLOW, if the value will not fit in the destination
526 HRESULT WINAPI
VarI1FromDec(DECIMAL
*pdecIn
, signed char* pcOut
)
531 hRet
= VarI8FromDec(pdecIn
, &i64
);
534 hRet
= _VarI1FromI8(i64
, pcOut
);
538 /************************************************************************
539 * VarI1FromI8 (OLEAUT32.376)
541 * Convert a VT_I8 to a VT_I1.
545 * pcOut [O] Destination
549 * Failure: E_INVALIDARG, if the source value is invalid
550 * DISP_E_OVERFLOW, if the value will not fit in the destination
552 HRESULT WINAPI
VarI1FromI8(LONG64 llIn
, signed char* pcOut
)
554 return _VarI1FromI8(llIn
, pcOut
);
557 /************************************************************************
558 * VarI1FromUI8 (OLEAUT32.377)
560 * Convert a VT_UI8 to a VT_I1.
564 * pcOut [O] Destination
568 * Failure: E_INVALIDARG, if the source value is invalid
569 * DISP_E_OVERFLOW, if the value will not fit in the destination
571 HRESULT WINAPI
VarI1FromUI8(ULONG64 ullIn
, signed char* pcOut
)
573 return _VarI1FromUI8(ullIn
, pcOut
);
579 /************************************************************************
580 * VarUI1FromI2 (OLEAUT32.130)
582 * Convert a VT_I2 to a VT_UI1.
586 * pbOut [O] Destination
590 * Failure: E_INVALIDARG, if the source value is invalid
591 * DISP_E_OVERFLOW, if the value will not fit in the destination
593 HRESULT WINAPI
VarUI1FromI2(SHORT sIn
, BYTE
* pbOut
)
595 return _VarUI1FromI2(sIn
, pbOut
);
598 /************************************************************************
599 * VarUI1FromI4 (OLEAUT32.131)
601 * Convert a VT_I4 to a VT_UI1.
605 * pbOut [O] Destination
609 * Failure: E_INVALIDARG, if the source value is invalid
610 * DISP_E_OVERFLOW, if the value will not fit in the destination
612 HRESULT WINAPI
VarUI1FromI4(LONG iIn
, BYTE
* pbOut
)
614 return _VarUI1FromI4(iIn
, pbOut
);
617 /************************************************************************
618 * VarUI1FromR4 (OLEAUT32.132)
620 * Convert a VT_R4 to a VT_UI1.
624 * pbOut [O] Destination
628 * Failure: E_INVALIDARG, if the source value is invalid
629 * DISP_E_OVERFLOW, if the value will not fit in the destination
630 * DISP_E_TYPEMISMATCH, if the type cannot be converted
632 HRESULT WINAPI
VarUI1FromR4(FLOAT fltIn
, BYTE
* pbOut
)
634 return VarUI1FromR8(fltIn
, pbOut
);
637 /************************************************************************
638 * VarUI1FromR8 (OLEAUT32.133)
640 * Convert a VT_R8 to a VT_UI1.
644 * pbOut [O] Destination
648 * Failure: E_INVALIDARG, if the source value is invalid
649 * DISP_E_OVERFLOW, if the value will not fit in the destination
652 * See VarI8FromR8() for details concerning rounding.
654 HRESULT WINAPI
VarUI1FromR8(double dblIn
, BYTE
* pbOut
)
656 if (dblIn
< -0.5 || dblIn
> (double)UI1_MAX
)
657 return DISP_E_OVERFLOW
;
658 VARIANT_DutchRound(BYTE
, dblIn
, *pbOut
);
662 /************************************************************************
663 * VarUI1FromCy (OLEAUT32.134)
665 * Convert a VT_CY to a VT_UI1.
669 * pbOut [O] Destination
673 * Failure: E_INVALIDARG, if the source value is invalid
674 * DISP_E_OVERFLOW, if the value will not fit in the destination
677 * Negative values >= -5000 will be converted to 0.
679 HRESULT WINAPI
VarUI1FromCy(CY cyIn
, BYTE
* pbOut
)
681 ULONG i
= UI1_MAX
+ 1;
683 VarUI4FromCy(cyIn
, &i
);
684 return _VarUI1FromUI4(i
, pbOut
);
687 /************************************************************************
688 * VarUI1FromDate (OLEAUT32.135)
690 * Convert a VT_DATE to a VT_UI1.
694 * pbOut [O] Destination
698 * Failure: E_INVALIDARG, if the source value is invalid
699 * DISP_E_OVERFLOW, if the value will not fit in the destination
701 HRESULT WINAPI
VarUI1FromDate(DATE dateIn
, BYTE
* pbOut
)
703 return VarUI1FromR8(dateIn
, pbOut
);
706 /************************************************************************
707 * VarUI1FromStr (OLEAUT32.136)
709 * Convert a VT_BSTR to a VT_UI1.
713 * lcid [I] LCID for the conversion
714 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
715 * pbOut [O] Destination
719 * Failure: E_INVALIDARG, if the source value is invalid
720 * DISP_E_OVERFLOW, if the value will not fit in the destination
721 * DISP_E_TYPEMISMATCH, if the type cannot be converted
723 HRESULT WINAPI
VarUI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, BYTE
* pbOut
)
725 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pbOut
, VT_UI1
);
728 /************************************************************************
729 * VarUI1FromDisp (OLEAUT32.137)
731 * Convert a VT_DISPATCH to a VT_UI1.
735 * lcid [I] LCID for conversion
736 * pbOut [O] Destination
740 * Failure: E_INVALIDARG, if the source value is invalid
741 * DISP_E_OVERFLOW, if the value will not fit in the destination
742 * DISP_E_TYPEMISMATCH, if the type cannot be converted
744 HRESULT WINAPI
VarUI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, BYTE
* pbOut
)
746 return VARIANT_FromDisp(pdispIn
, lcid
, pbOut
, VT_UI1
, 0);
749 /************************************************************************
750 * VarUI1FromBool (OLEAUT32.138)
752 * Convert a VT_BOOL to a VT_UI1.
756 * pbOut [O] Destination
761 HRESULT WINAPI
VarUI1FromBool(VARIANT_BOOL boolIn
, BYTE
* pbOut
)
763 return _VarUI1FromBool(boolIn
, pbOut
);
766 /************************************************************************
767 * VarUI1FromI1 (OLEAUT32.237)
769 * Convert a VT_I1 to a VT_UI1.
773 * pbOut [O] Destination
777 * Failure: E_INVALIDARG, if the source value is invalid
778 * DISP_E_OVERFLOW, if the value will not fit in the destination
780 HRESULT WINAPI
VarUI1FromI1(signed char cIn
, BYTE
* pbOut
)
782 return _VarUI1FromI1(cIn
, pbOut
);
785 /************************************************************************
786 * VarUI1FromUI2 (OLEAUT32.238)
788 * Convert a VT_UI2 to a VT_UI1.
792 * pbOut [O] Destination
796 * Failure: E_INVALIDARG, if the source value is invalid
797 * DISP_E_OVERFLOW, if the value will not fit in the destination
799 HRESULT WINAPI
VarUI1FromUI2(USHORT usIn
, BYTE
* pbOut
)
801 return _VarUI1FromUI2(usIn
, pbOut
);
804 /************************************************************************
805 * VarUI1FromUI4 (OLEAUT32.239)
807 * Convert a VT_UI4 to a VT_UI1.
811 * pbOut [O] Destination
815 * Failure: E_INVALIDARG, if the source value is invalid
816 * DISP_E_OVERFLOW, if the value will not fit in the destination
818 HRESULT WINAPI
VarUI1FromUI4(ULONG ulIn
, BYTE
* pbOut
)
820 return _VarUI1FromUI4(ulIn
, pbOut
);
823 /************************************************************************
824 * VarUI1FromDec (OLEAUT32.240)
826 * Convert a VT_DECIMAL to a VT_UI1.
830 * pbOut [O] Destination
834 * Failure: E_INVALIDARG, if the source value is invalid
835 * DISP_E_OVERFLOW, if the value will not fit in the destination
837 HRESULT WINAPI
VarUI1FromDec(DECIMAL
*pdecIn
, BYTE
* pbOut
)
842 hRet
= VarI8FromDec(pdecIn
, &i64
);
845 hRet
= _VarUI1FromI8(i64
, pbOut
);
849 /************************************************************************
850 * VarUI1FromI8 (OLEAUT32.372)
852 * Convert a VT_I8 to a VT_UI1.
856 * pbOut [O] Destination
860 * Failure: E_INVALIDARG, if the source value is invalid
861 * DISP_E_OVERFLOW, if the value will not fit in the destination
863 HRESULT WINAPI
VarUI1FromI8(LONG64 llIn
, BYTE
* pbOut
)
865 return _VarUI1FromI8(llIn
, pbOut
);
868 /************************************************************************
869 * VarUI1FromUI8 (OLEAUT32.373)
871 * Convert a VT_UI8 to a VT_UI1.
875 * pbOut [O] Destination
879 * Failure: E_INVALIDARG, if the source value is invalid
880 * DISP_E_OVERFLOW, if the value will not fit in the destination
882 HRESULT WINAPI
VarUI1FromUI8(ULONG64 ullIn
, BYTE
* pbOut
)
884 return _VarUI1FromUI8(ullIn
, pbOut
);
891 /************************************************************************
892 * VarI2FromUI1 (OLEAUT32.48)
894 * Convert a VT_UI2 to a VT_I2.
898 * psOut [O] Destination
903 HRESULT WINAPI
VarI2FromUI1(BYTE bIn
, SHORT
* psOut
)
905 return _VarI2FromUI1(bIn
, psOut
);
908 /************************************************************************
909 * VarI2FromI4 (OLEAUT32.49)
911 * Convert a VT_I4 to a VT_I2.
915 * psOut [O] Destination
919 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
921 HRESULT WINAPI
VarI2FromI4(LONG iIn
, SHORT
* psOut
)
923 return _VarI2FromI4(iIn
, psOut
);
926 /************************************************************************
927 * VarI2FromR4 (OLEAUT32.50)
929 * Convert a VT_R4 to a VT_I2.
933 * psOut [O] Destination
937 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
939 HRESULT WINAPI
VarI2FromR4(FLOAT fltIn
, SHORT
* psOut
)
941 return VarI2FromR8(fltIn
, psOut
);
944 /************************************************************************
945 * VarI2FromR8 (OLEAUT32.51)
947 * Convert a VT_R8 to a VT_I2.
951 * psOut [O] Destination
955 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
958 * See VarI8FromR8() for details concerning rounding.
960 HRESULT WINAPI
VarI2FromR8(double dblIn
, SHORT
* psOut
)
962 if (dblIn
< (double)I2_MIN
|| dblIn
> (double)I2_MAX
)
963 return DISP_E_OVERFLOW
;
964 VARIANT_DutchRound(SHORT
, dblIn
, *psOut
);
968 /************************************************************************
969 * VarI2FromCy (OLEAUT32.52)
971 * Convert a VT_CY to a VT_I2.
975 * psOut [O] Destination
979 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
981 HRESULT WINAPI
VarI2FromCy(CY cyIn
, SHORT
* psOut
)
985 VarI4FromCy(cyIn
, &i
);
986 return _VarI2FromI4(i
, psOut
);
989 /************************************************************************
990 * VarI2FromDate (OLEAUT32.53)
992 * Convert a VT_DATE to a VT_I2.
996 * psOut [O] Destination
1000 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1002 HRESULT WINAPI
VarI2FromDate(DATE dateIn
, SHORT
* psOut
)
1004 return VarI2FromR8(dateIn
, psOut
);
1007 /************************************************************************
1008 * VarI2FromStr (OLEAUT32.54)
1010 * Convert a VT_BSTR to a VT_I2.
1014 * lcid [I] LCID for the conversion
1015 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1016 * psOut [O] Destination
1020 * Failure: E_INVALIDARG, if any parameter is invalid
1021 * DISP_E_OVERFLOW, if the value will not fit in the destination
1022 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1024 HRESULT WINAPI
VarI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, SHORT
* psOut
)
1026 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, psOut
, VT_I2
);
1029 /************************************************************************
1030 * VarI2FromDisp (OLEAUT32.55)
1032 * Convert a VT_DISPATCH to a VT_I2.
1035 * pdispIn [I] Source
1036 * lcid [I] LCID for conversion
1037 * psOut [O] Destination
1041 * Failure: E_INVALIDARG, if pdispIn is invalid,
1042 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1043 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1045 HRESULT WINAPI
VarI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, SHORT
* psOut
)
1047 return VARIANT_FromDisp(pdispIn
, lcid
, psOut
, VT_I2
, 0);
1050 /************************************************************************
1051 * VarI2FromBool (OLEAUT32.56)
1053 * Convert a VT_BOOL to a VT_I2.
1057 * psOut [O] Destination
1062 HRESULT WINAPI
VarI2FromBool(VARIANT_BOOL boolIn
, SHORT
* psOut
)
1064 return _VarI2FromBool(boolIn
, psOut
);
1067 /************************************************************************
1068 * VarI2FromI1 (OLEAUT32.205)
1070 * Convert a VT_I1 to a VT_I2.
1074 * psOut [O] Destination
1079 HRESULT WINAPI
VarI2FromI1(signed char cIn
, SHORT
* psOut
)
1081 return _VarI2FromI1(cIn
, psOut
);
1084 /************************************************************************
1085 * VarI2FromUI2 (OLEAUT32.206)
1087 * Convert a VT_UI2 to a VT_I2.
1091 * psOut [O] Destination
1095 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1097 HRESULT WINAPI
VarI2FromUI2(USHORT usIn
, SHORT
* psOut
)
1099 return _VarI2FromUI2(usIn
, psOut
);
1102 /************************************************************************
1103 * VarI2FromUI4 (OLEAUT32.207)
1105 * Convert a VT_UI4 to a VT_I2.
1109 * psOut [O] Destination
1113 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1115 HRESULT WINAPI
VarI2FromUI4(ULONG ulIn
, SHORT
* psOut
)
1117 return _VarI2FromUI4(ulIn
, psOut
);
1120 /************************************************************************
1121 * VarI2FromDec (OLEAUT32.208)
1123 * Convert a VT_DECIMAL to a VT_I2.
1127 * psOut [O] Destination
1131 * Failure: E_INVALIDARG, if the source value is invalid
1132 * DISP_E_OVERFLOW, if the value will not fit in the destination
1134 HRESULT WINAPI
VarI2FromDec(DECIMAL
*pdecIn
, SHORT
* psOut
)
1139 hRet
= VarI8FromDec(pdecIn
, &i64
);
1141 if (SUCCEEDED(hRet
))
1142 hRet
= _VarI2FromI8(i64
, psOut
);
1146 /************************************************************************
1147 * VarI2FromI8 (OLEAUT32.346)
1149 * Convert a VT_I8 to a VT_I2.
1153 * psOut [O] Destination
1157 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1159 HRESULT WINAPI
VarI2FromI8(LONG64 llIn
, SHORT
* psOut
)
1161 return _VarI2FromI8(llIn
, psOut
);
1164 /************************************************************************
1165 * VarI2FromUI8 (OLEAUT32.347)
1167 * Convert a VT_UI8 to a VT_I2.
1171 * psOut [O] Destination
1175 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1177 HRESULT WINAPI
VarI2FromUI8(ULONG64 ullIn
, SHORT
* psOut
)
1179 return _VarI2FromUI8(ullIn
, psOut
);
1185 /************************************************************************
1186 * VarUI2FromUI1 (OLEAUT32.257)
1188 * Convert a VT_UI1 to a VT_UI2.
1192 * pusOut [O] Destination
1197 HRESULT WINAPI
VarUI2FromUI1(BYTE bIn
, USHORT
* pusOut
)
1199 return _VarUI2FromUI1(bIn
, pusOut
);
1202 /************************************************************************
1203 * VarUI2FromI2 (OLEAUT32.258)
1205 * Convert a VT_I2 to a VT_UI2.
1209 * pusOut [O] Destination
1213 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1215 HRESULT WINAPI
VarUI2FromI2(SHORT sIn
, USHORT
* pusOut
)
1217 return _VarUI2FromI2(sIn
, pusOut
);
1220 /************************************************************************
1221 * VarUI2FromI4 (OLEAUT32.259)
1223 * Convert a VT_I4 to a VT_UI2.
1227 * pusOut [O] Destination
1231 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1233 HRESULT WINAPI
VarUI2FromI4(LONG iIn
, USHORT
* pusOut
)
1235 return _VarUI2FromI4(iIn
, pusOut
);
1238 /************************************************************************
1239 * VarUI2FromR4 (OLEAUT32.260)
1241 * Convert a VT_R4 to a VT_UI2.
1245 * pusOut [O] Destination
1249 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1251 HRESULT WINAPI
VarUI2FromR4(FLOAT fltIn
, USHORT
* pusOut
)
1253 return VarUI2FromR8(fltIn
, pusOut
);
1256 /************************************************************************
1257 * VarUI2FromR8 (OLEAUT32.261)
1259 * Convert a VT_R8 to a VT_UI2.
1263 * pusOut [O] Destination
1267 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1270 * See VarI8FromR8() for details concerning rounding.
1272 HRESULT WINAPI
VarUI2FromR8(double dblIn
, USHORT
* pusOut
)
1274 if (dblIn
< -0.5 || dblIn
> (double)UI2_MAX
)
1275 return DISP_E_OVERFLOW
;
1276 VARIANT_DutchRound(USHORT
, dblIn
, *pusOut
);
1280 /************************************************************************
1281 * VarUI2FromDate (OLEAUT32.262)
1283 * Convert a VT_DATE to a VT_UI2.
1287 * pusOut [O] Destination
1291 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1293 HRESULT WINAPI
VarUI2FromDate(DATE dateIn
, USHORT
* pusOut
)
1295 return VarUI2FromR8(dateIn
, pusOut
);
1298 /************************************************************************
1299 * VarUI2FromCy (OLEAUT32.263)
1301 * Convert a VT_CY to a VT_UI2.
1305 * pusOut [O] Destination
1309 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1312 * Negative values >= -5000 will be converted to 0.
1314 HRESULT WINAPI
VarUI2FromCy(CY cyIn
, USHORT
* pusOut
)
1316 ULONG i
= UI2_MAX
+ 1;
1318 VarUI4FromCy(cyIn
, &i
);
1319 return _VarUI2FromUI4(i
, pusOut
);
1322 /************************************************************************
1323 * VarUI2FromStr (OLEAUT32.264)
1325 * Convert a VT_BSTR to a VT_UI2.
1329 * lcid [I] LCID for the conversion
1330 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1331 * pusOut [O] Destination
1335 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1336 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1338 HRESULT WINAPI
VarUI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, USHORT
* pusOut
)
1340 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pusOut
, VT_UI2
);
1343 /************************************************************************
1344 * VarUI2FromDisp (OLEAUT32.265)
1346 * Convert a VT_DISPATCH to a VT_UI2.
1349 * pdispIn [I] Source
1350 * lcid [I] LCID for conversion
1351 * pusOut [O] Destination
1355 * Failure: E_INVALIDARG, if the source value is invalid
1356 * DISP_E_OVERFLOW, if the value will not fit in the destination
1357 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1359 HRESULT WINAPI
VarUI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, USHORT
* pusOut
)
1361 return VARIANT_FromDisp(pdispIn
, lcid
, pusOut
, VT_UI2
, 0);
1364 /************************************************************************
1365 * VarUI2FromBool (OLEAUT32.266)
1367 * Convert a VT_BOOL to a VT_UI2.
1371 * pusOut [O] Destination
1376 HRESULT WINAPI
VarUI2FromBool(VARIANT_BOOL boolIn
, USHORT
* pusOut
)
1378 return _VarUI2FromBool(boolIn
, pusOut
);
1381 /************************************************************************
1382 * VarUI2FromI1 (OLEAUT32.267)
1384 * Convert a VT_I1 to a VT_UI2.
1388 * pusOut [O] Destination
1392 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1394 HRESULT WINAPI
VarUI2FromI1(signed char cIn
, USHORT
* pusOut
)
1396 return _VarUI2FromI1(cIn
, pusOut
);
1399 /************************************************************************
1400 * VarUI2FromUI4 (OLEAUT32.268)
1402 * Convert a VT_UI4 to a VT_UI2.
1406 * pusOut [O] Destination
1410 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1412 HRESULT WINAPI
VarUI2FromUI4(ULONG ulIn
, USHORT
* pusOut
)
1414 return _VarUI2FromUI4(ulIn
, pusOut
);
1417 /************************************************************************
1418 * VarUI2FromDec (OLEAUT32.269)
1420 * Convert a VT_DECIMAL to a VT_UI2.
1424 * pusOut [O] Destination
1428 * Failure: E_INVALIDARG, if the source value is invalid
1429 * DISP_E_OVERFLOW, if the value will not fit in the destination
1431 HRESULT WINAPI
VarUI2FromDec(DECIMAL
*pdecIn
, USHORT
* pusOut
)
1436 hRet
= VarI8FromDec(pdecIn
, &i64
);
1438 if (SUCCEEDED(hRet
))
1439 hRet
= _VarUI2FromI8(i64
, pusOut
);
1443 /************************************************************************
1444 * VarUI2FromI8 (OLEAUT32.378)
1446 * Convert a VT_I8 to a VT_UI2.
1450 * pusOut [O] Destination
1454 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1456 HRESULT WINAPI
VarUI2FromI8(LONG64 llIn
, USHORT
* pusOut
)
1458 return _VarUI2FromI8(llIn
, pusOut
);
1461 /************************************************************************
1462 * VarUI2FromUI8 (OLEAUT32.379)
1464 * Convert a VT_UI8 to a VT_UI2.
1468 * pusOut [O] Destination
1472 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1474 HRESULT WINAPI
VarUI2FromUI8(ULONG64 ullIn
, USHORT
* pusOut
)
1476 return _VarUI2FromUI8(ullIn
, pusOut
);
1482 /************************************************************************
1483 * VarI4FromUI1 (OLEAUT32.58)
1485 * Convert a VT_UI1 to a VT_I4.
1489 * piOut [O] Destination
1494 HRESULT WINAPI
VarI4FromUI1(BYTE bIn
, LONG
*piOut
)
1496 return _VarI4FromUI1(bIn
, piOut
);
1499 /************************************************************************
1500 * VarI4FromI2 (OLEAUT32.59)
1502 * Convert a VT_I2 to a VT_I4.
1506 * piOut [O] Destination
1510 * Failure: E_INVALIDARG, if the source value is invalid
1511 * DISP_E_OVERFLOW, if the value will not fit in the destination
1513 HRESULT WINAPI
VarI4FromI2(SHORT sIn
, LONG
*piOut
)
1515 return _VarI4FromI2(sIn
, piOut
);
1518 /************************************************************************
1519 * VarI4FromR4 (OLEAUT32.60)
1521 * Convert a VT_R4 to a VT_I4.
1525 * piOut [O] Destination
1529 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1531 HRESULT WINAPI
VarI4FromR4(FLOAT fltIn
, LONG
*piOut
)
1533 return VarI4FromR8(fltIn
, piOut
);
1536 /************************************************************************
1537 * VarI4FromR8 (OLEAUT32.61)
1539 * Convert a VT_R8 to a VT_I4.
1543 * piOut [O] Destination
1547 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1550 * See VarI8FromR8() for details concerning rounding.
1552 HRESULT WINAPI
VarI4FromR8(double dblIn
, LONG
*piOut
)
1554 if (dblIn
< (double)I4_MIN
|| dblIn
> (double)I4_MAX
)
1555 return DISP_E_OVERFLOW
;
1556 VARIANT_DutchRound(LONG
, dblIn
, *piOut
);
1560 /************************************************************************
1561 * VarI4FromCy (OLEAUT32.62)
1563 * Convert a VT_CY to a VT_I4.
1567 * piOut [O] Destination
1571 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1573 HRESULT WINAPI
VarI4FromCy(CY cyIn
, LONG
*piOut
)
1575 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1576 return VarI4FromR8(d
, piOut
);
1579 /************************************************************************
1580 * VarI4FromDate (OLEAUT32.63)
1582 * Convert a VT_DATE to a VT_I4.
1586 * piOut [O] Destination
1590 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1592 HRESULT WINAPI
VarI4FromDate(DATE dateIn
, LONG
*piOut
)
1594 return VarI4FromR8(dateIn
, piOut
);
1597 /************************************************************************
1598 * VarI4FromStr (OLEAUT32.64)
1600 * Convert a VT_BSTR to a VT_I4.
1604 * lcid [I] LCID for the conversion
1605 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1606 * piOut [O] Destination
1610 * Failure: E_INVALIDARG, if any parameter is invalid
1611 * DISP_E_OVERFLOW, if the value will not fit in the destination
1612 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1614 HRESULT WINAPI
VarI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG
*piOut
)
1616 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, piOut
, VT_I4
);
1619 /************************************************************************
1620 * VarI4FromDisp (OLEAUT32.65)
1622 * Convert a VT_DISPATCH to a VT_I4.
1625 * pdispIn [I] Source
1626 * lcid [I] LCID for conversion
1627 * piOut [O] Destination
1631 * Failure: E_INVALIDARG, if the source value is invalid
1632 * DISP_E_OVERFLOW, if the value will not fit in the destination
1633 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1635 HRESULT WINAPI
VarI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG
*piOut
)
1637 return VARIANT_FromDisp(pdispIn
, lcid
, piOut
, VT_I4
, 0);
1640 /************************************************************************
1641 * VarI4FromBool (OLEAUT32.66)
1643 * Convert a VT_BOOL to a VT_I4.
1647 * piOut [O] Destination
1652 HRESULT WINAPI
VarI4FromBool(VARIANT_BOOL boolIn
, LONG
*piOut
)
1654 return _VarI4FromBool(boolIn
, piOut
);
1657 /************************************************************************
1658 * VarI4FromI1 (OLEAUT32.209)
1660 * Convert a VT_I4 to a VT_I4.
1664 * piOut [O] Destination
1669 HRESULT WINAPI
VarI4FromI1(signed char cIn
, LONG
*piOut
)
1671 return _VarI4FromI1(cIn
, piOut
);
1674 /************************************************************************
1675 * VarI4FromUI2 (OLEAUT32.210)
1677 * Convert a VT_UI2 to a VT_I4.
1681 * piOut [O] Destination
1686 HRESULT WINAPI
VarI4FromUI2(USHORT usIn
, LONG
*piOut
)
1688 return _VarI4FromUI2(usIn
, piOut
);
1691 /************************************************************************
1692 * VarI4FromUI4 (OLEAUT32.211)
1694 * Convert a VT_UI4 to a VT_I4.
1698 * piOut [O] Destination
1702 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1704 HRESULT WINAPI
VarI4FromUI4(ULONG ulIn
, LONG
*piOut
)
1706 return _VarI4FromUI4(ulIn
, piOut
);
1709 /************************************************************************
1710 * VarI4FromDec (OLEAUT32.212)
1712 * Convert a VT_DECIMAL to a VT_I4.
1716 * piOut [O] Destination
1720 * Failure: E_INVALIDARG, if pdecIn is invalid
1721 * DISP_E_OVERFLOW, if the value will not fit in the destination
1723 HRESULT WINAPI
VarI4FromDec(DECIMAL
*pdecIn
, LONG
*piOut
)
1728 hRet
= VarI8FromDec(pdecIn
, &i64
);
1730 if (SUCCEEDED(hRet
))
1731 hRet
= _VarI4FromI8(i64
, piOut
);
1735 /************************************************************************
1736 * VarI4FromI8 (OLEAUT32.348)
1738 * Convert a VT_I8 to a VT_I4.
1742 * piOut [O] Destination
1746 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1748 HRESULT WINAPI
VarI4FromI8(LONG64 llIn
, LONG
*piOut
)
1750 return _VarI4FromI8(llIn
, piOut
);
1753 /************************************************************************
1754 * VarI4FromUI8 (OLEAUT32.349)
1756 * Convert a VT_UI8 to a VT_I4.
1760 * piOut [O] Destination
1764 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1766 HRESULT WINAPI
VarI4FromUI8(ULONG64 ullIn
, LONG
*piOut
)
1768 return _VarI4FromUI8(ullIn
, piOut
);
1774 /************************************************************************
1775 * VarUI4FromUI1 (OLEAUT32.270)
1777 * Convert a VT_UI1 to a VT_UI4.
1781 * pulOut [O] Destination
1786 HRESULT WINAPI
VarUI4FromUI1(BYTE bIn
, ULONG
*pulOut
)
1788 return _VarUI4FromUI1(bIn
, pulOut
);
1791 /************************************************************************
1792 * VarUI4FromI2 (OLEAUT32.271)
1794 * Convert a VT_I2 to a VT_UI4.
1798 * pulOut [O] Destination
1802 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1804 HRESULT WINAPI
VarUI4FromI2(SHORT sIn
, ULONG
*pulOut
)
1806 return _VarUI4FromI2(sIn
, pulOut
);
1809 /************************************************************************
1810 * VarUI4FromI4 (OLEAUT32.272)
1812 * Convert a VT_I4 to a VT_UI4.
1816 * pulOut [O] Destination
1820 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1822 HRESULT WINAPI
VarUI4FromI4(LONG iIn
, ULONG
*pulOut
)
1824 return _VarUI4FromI4(iIn
, pulOut
);
1827 /************************************************************************
1828 * VarUI4FromR4 (OLEAUT32.273)
1830 * Convert a VT_R4 to a VT_UI4.
1834 * pulOut [O] Destination
1838 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1840 HRESULT WINAPI
VarUI4FromR4(FLOAT fltIn
, ULONG
*pulOut
)
1842 return VarUI4FromR8(fltIn
, pulOut
);
1845 /************************************************************************
1846 * VarUI4FromR8 (OLEAUT32.274)
1848 * Convert a VT_R8 to a VT_UI4.
1852 * pulOut [O] Destination
1856 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1859 * See VarI8FromR8() for details concerning rounding.
1861 HRESULT WINAPI
VarUI4FromR8(double dblIn
, ULONG
*pulOut
)
1863 if (dblIn
< -0.5 || dblIn
> (double)UI4_MAX
)
1864 return DISP_E_OVERFLOW
;
1865 VARIANT_DutchRound(ULONG
, dblIn
, *pulOut
);
1869 /************************************************************************
1870 * VarUI4FromDate (OLEAUT32.275)
1872 * Convert a VT_DATE to a VT_UI4.
1876 * pulOut [O] Destination
1880 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1882 HRESULT WINAPI
VarUI4FromDate(DATE dateIn
, ULONG
*pulOut
)
1884 return VarUI4FromR8(dateIn
, pulOut
);
1887 /************************************************************************
1888 * VarUI4FromCy (OLEAUT32.276)
1890 * Convert a VT_CY to a VT_UI4.
1894 * pulOut [O] Destination
1898 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1900 HRESULT WINAPI
VarUI4FromCy(CY cyIn
, ULONG
*pulOut
)
1902 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1903 return VarUI4FromR8(d
, pulOut
);
1906 /************************************************************************
1907 * VarUI4FromStr (OLEAUT32.277)
1909 * Convert a VT_BSTR to a VT_UI4.
1913 * lcid [I] LCID for the conversion
1914 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1915 * pulOut [O] Destination
1919 * Failure: E_INVALIDARG, if any parameter is invalid
1920 * DISP_E_OVERFLOW, if the value will not fit in the destination
1921 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1923 HRESULT WINAPI
VarUI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG
*pulOut
)
1925 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pulOut
, VT_UI4
);
1928 /************************************************************************
1929 * VarUI4FromDisp (OLEAUT32.278)
1931 * Convert a VT_DISPATCH to a VT_UI4.
1934 * pdispIn [I] Source
1935 * lcid [I] LCID for conversion
1936 * pulOut [O] Destination
1940 * Failure: E_INVALIDARG, if the source value is invalid
1941 * DISP_E_OVERFLOW, if the value will not fit in the destination
1942 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1944 HRESULT WINAPI
VarUI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG
*pulOut
)
1946 return VARIANT_FromDisp(pdispIn
, lcid
, pulOut
, VT_UI4
, 0);
1949 /************************************************************************
1950 * VarUI4FromBool (OLEAUT32.279)
1952 * Convert a VT_BOOL to a VT_UI4.
1956 * pulOut [O] Destination
1961 HRESULT WINAPI
VarUI4FromBool(VARIANT_BOOL boolIn
, ULONG
*pulOut
)
1963 return _VarUI4FromBool(boolIn
, pulOut
);
1966 /************************************************************************
1967 * VarUI4FromI1 (OLEAUT32.280)
1969 * Convert a VT_I1 to a VT_UI4.
1973 * pulOut [O] Destination
1977 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1979 HRESULT WINAPI
VarUI4FromI1(signed char cIn
, ULONG
*pulOut
)
1981 return _VarUI4FromI1(cIn
, pulOut
);
1984 /************************************************************************
1985 * VarUI4FromUI2 (OLEAUT32.281)
1987 * Convert a VT_UI2 to a VT_UI4.
1991 * pulOut [O] Destination
1996 HRESULT WINAPI
VarUI4FromUI2(USHORT usIn
, ULONG
*pulOut
)
1998 return _VarUI4FromUI2(usIn
, pulOut
);
2001 /************************************************************************
2002 * VarUI4FromDec (OLEAUT32.282)
2004 * Convert a VT_DECIMAL to a VT_UI4.
2008 * pulOut [O] Destination
2012 * Failure: E_INVALIDARG, if pdecIn is invalid
2013 * DISP_E_OVERFLOW, if the value will not fit in the destination
2015 HRESULT WINAPI
VarUI4FromDec(DECIMAL
*pdecIn
, ULONG
*pulOut
)
2020 hRet
= VarI8FromDec(pdecIn
, &i64
);
2022 if (SUCCEEDED(hRet
))
2023 hRet
= _VarUI4FromI8(i64
, pulOut
);
2027 /************************************************************************
2028 * VarUI4FromI8 (OLEAUT32.425)
2030 * Convert a VT_I8 to a VT_UI4.
2034 * pulOut [O] Destination
2038 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2040 HRESULT WINAPI
VarUI4FromI8(LONG64 llIn
, ULONG
*pulOut
)
2042 return _VarUI4FromI8(llIn
, pulOut
);
2045 /************************************************************************
2046 * VarUI4FromUI8 (OLEAUT32.426)
2048 * Convert a VT_UI8 to a VT_UI4.
2052 * pulOut [O] Destination
2056 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2058 HRESULT WINAPI
VarUI4FromUI8(ULONG64 ullIn
, ULONG
*pulOut
)
2060 return _VarUI4FromUI8(ullIn
, pulOut
);
2066 /************************************************************************
2067 * VarI8FromUI1 (OLEAUT32.333)
2069 * Convert a VT_UI1 to a VT_I8.
2073 * pi64Out [O] Destination
2078 HRESULT WINAPI
VarI8FromUI1(BYTE bIn
, LONG64
* pi64Out
)
2080 return _VarI8FromUI1(bIn
, pi64Out
);
2084 /************************************************************************
2085 * VarI8FromI2 (OLEAUT32.334)
2087 * Convert a VT_I2 to a VT_I8.
2091 * pi64Out [O] Destination
2096 HRESULT WINAPI
VarI8FromI2(SHORT sIn
, LONG64
* pi64Out
)
2098 return _VarI8FromI2(sIn
, pi64Out
);
2101 /************************************************************************
2102 * VarI8FromR4 (OLEAUT32.335)
2104 * Convert a VT_R4 to a VT_I8.
2108 * pi64Out [O] Destination
2112 * Failure: E_INVALIDARG, if the source value is invalid
2113 * DISP_E_OVERFLOW, if the value will not fit in the destination
2115 HRESULT WINAPI
VarI8FromR4(FLOAT fltIn
, LONG64
* pi64Out
)
2117 return VarI8FromR8(fltIn
, pi64Out
);
2120 /************************************************************************
2121 * VarI8FromR8 (OLEAUT32.336)
2123 * Convert a VT_R8 to a VT_I8.
2127 * pi64Out [O] Destination
2131 * Failure: E_INVALIDARG, if the source value is invalid
2132 * DISP_E_OVERFLOW, if the value will not fit in the destination
2135 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2136 * very high or low values will not be accurately converted.
2138 * Numbers are rounded using Dutch rounding, as follows:
2140 *| Fractional Part Sign Direction Example
2141 *| --------------- ---- --------- -------
2142 *| < 0.5 + Down 0.4 -> 0.0
2143 *| < 0.5 - Up -0.4 -> 0.0
2144 *| > 0.5 + Up 0.6 -> 1.0
2145 *| < 0.5 - Up -0.6 -> -1.0
2146 *| = 0.5 + Up/Down Down if even, Up if odd
2147 *| = 0.5 - Up/Down Up if even, Down if odd
2149 * This system is often used in supermarkets.
2151 HRESULT WINAPI
VarI8FromR8(double dblIn
, LONG64
* pi64Out
)
2153 if ( dblIn
< -4611686018427387904.0 || dblIn
>= 4611686018427387904.0)
2154 return DISP_E_OVERFLOW
;
2155 VARIANT_DutchRound(LONG64
, dblIn
, *pi64Out
);
2159 /************************************************************************
2160 * VarI8FromCy (OLEAUT32.337)
2162 * Convert a VT_CY to a VT_I8.
2166 * pi64Out [O] Destination
2172 * All negative numbers are rounded down by 1, including those that are
2173 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2174 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2177 HRESULT WINAPI
VarI8FromCy(CY cyIn
, LONG64
* pi64Out
)
2179 *pi64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2182 (*pi64Out
)--; /* Mimic Win32 bug */
2185 cyIn
.int64
-= *pi64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2187 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pi64Out
& 0x1)))
2193 /************************************************************************
2194 * VarI8FromDate (OLEAUT32.338)
2196 * Convert a VT_DATE to a VT_I8.
2200 * pi64Out [O] Destination
2204 * Failure: E_INVALIDARG, if the source value is invalid
2205 * DISP_E_OVERFLOW, if the value will not fit in the destination
2206 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2208 HRESULT WINAPI
VarI8FromDate(DATE dateIn
, LONG64
* pi64Out
)
2210 return VarI8FromR8(dateIn
, pi64Out
);
2213 /************************************************************************
2214 * VarI8FromStr (OLEAUT32.339)
2216 * Convert a VT_BSTR to a VT_I8.
2220 * lcid [I] LCID for the conversion
2221 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2222 * pi64Out [O] Destination
2226 * Failure: E_INVALIDARG, if the source value is invalid
2227 * DISP_E_OVERFLOW, if the value will not fit in the destination
2228 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2230 HRESULT WINAPI
VarI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG64
* pi64Out
)
2232 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pi64Out
, VT_I8
);
2235 /************************************************************************
2236 * VarI8FromDisp (OLEAUT32.340)
2238 * Convert a VT_DISPATCH to a VT_I8.
2241 * pdispIn [I] Source
2242 * lcid [I] LCID for conversion
2243 * pi64Out [O] Destination
2247 * Failure: E_INVALIDARG, if the source value is invalid
2248 * DISP_E_OVERFLOW, if the value will not fit in the destination
2249 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2251 HRESULT WINAPI
VarI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG64
* pi64Out
)
2253 return VARIANT_FromDisp(pdispIn
, lcid
, pi64Out
, VT_I8
, 0);
2256 /************************************************************************
2257 * VarI8FromBool (OLEAUT32.341)
2259 * Convert a VT_BOOL to a VT_I8.
2263 * pi64Out [O] Destination
2268 HRESULT WINAPI
VarI8FromBool(VARIANT_BOOL boolIn
, LONG64
* pi64Out
)
2270 return VarI8FromI2(boolIn
, pi64Out
);
2273 /************************************************************************
2274 * VarI8FromI1 (OLEAUT32.342)
2276 * Convert a VT_I1 to a VT_I8.
2280 * pi64Out [O] Destination
2285 HRESULT WINAPI
VarI8FromI1(signed char cIn
, LONG64
* pi64Out
)
2287 return _VarI8FromI1(cIn
, pi64Out
);
2290 /************************************************************************
2291 * VarI8FromUI2 (OLEAUT32.343)
2293 * Convert a VT_UI2 to a VT_I8.
2297 * pi64Out [O] Destination
2302 HRESULT WINAPI
VarI8FromUI2(USHORT usIn
, LONG64
* pi64Out
)
2304 return _VarI8FromUI2(usIn
, pi64Out
);
2307 /************************************************************************
2308 * VarI8FromUI4 (OLEAUT32.344)
2310 * Convert a VT_UI4 to a VT_I8.
2314 * pi64Out [O] Destination
2319 HRESULT WINAPI
VarI8FromUI4(ULONG ulIn
, LONG64
* pi64Out
)
2321 return _VarI8FromUI4(ulIn
, pi64Out
);
2324 /************************************************************************
2325 * VarI8FromDec (OLEAUT32.345)
2327 * Convert a VT_DECIMAL to a VT_I8.
2331 * pi64Out [O] Destination
2335 * Failure: E_INVALIDARG, if the source value is invalid
2336 * DISP_E_OVERFLOW, if the value will not fit in the destination
2338 HRESULT WINAPI
VarI8FromDec(DECIMAL
*pdecIn
, LONG64
* pi64Out
)
2340 if (!DEC_SCALE(pdecIn
))
2342 /* This decimal is just a 96 bit integer */
2343 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2344 return E_INVALIDARG
;
2346 if (DEC_HI32(pdecIn
) || DEC_MID32(pdecIn
) & 0x80000000)
2347 return DISP_E_OVERFLOW
;
2349 if (DEC_SIGN(pdecIn
))
2350 *pi64Out
= -DEC_LO64(pdecIn
);
2352 *pi64Out
= DEC_LO64(pdecIn
);
2357 /* Decimal contains a floating point number */
2361 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2362 if (SUCCEEDED(hRet
))
2363 hRet
= VarI8FromR8(dbl
, pi64Out
);
2368 /************************************************************************
2369 * VarI8FromUI8 (OLEAUT32.427)
2371 * Convert a VT_UI8 to a VT_I8.
2375 * pi64Out [O] Destination
2379 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2381 HRESULT WINAPI
VarI8FromUI8(ULONG64 ullIn
, LONG64
* pi64Out
)
2383 return _VarI8FromUI8(ullIn
, pi64Out
);
2389 /************************************************************************
2390 * VarUI8FromI8 (OLEAUT32.428)
2392 * Convert a VT_I8 to a VT_UI8.
2396 * pui64Out [O] Destination
2400 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2402 HRESULT WINAPI
VarUI8FromI8(LONG64 llIn
, ULONG64
* pui64Out
)
2404 return _VarUI8FromI8(llIn
, pui64Out
);
2407 /************************************************************************
2408 * VarUI8FromUI1 (OLEAUT32.429)
2410 * Convert a VT_UI1 to a VT_UI8.
2414 * pui64Out [O] Destination
2419 HRESULT WINAPI
VarUI8FromUI1(BYTE bIn
, ULONG64
* pui64Out
)
2421 return _VarUI8FromUI1(bIn
, pui64Out
);
2424 /************************************************************************
2425 * VarUI8FromI2 (OLEAUT32.430)
2427 * Convert a VT_I2 to a VT_UI8.
2431 * pui64Out [O] Destination
2436 HRESULT WINAPI
VarUI8FromI2(SHORT sIn
, ULONG64
* pui64Out
)
2438 return _VarUI8FromI2(sIn
, pui64Out
);
2441 /************************************************************************
2442 * VarUI8FromR4 (OLEAUT32.431)
2444 * Convert a VT_R4 to a VT_UI8.
2448 * pui64Out [O] Destination
2452 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2454 HRESULT WINAPI
VarUI8FromR4(FLOAT fltIn
, ULONG64
* pui64Out
)
2456 return VarUI8FromR8(fltIn
, pui64Out
);
2459 /************************************************************************
2460 * VarUI8FromR8 (OLEAUT32.432)
2462 * Convert a VT_R8 to a VT_UI8.
2466 * pui64Out [O] Destination
2470 * Failure: E_INVALIDARG, if the source value is invalid
2471 * DISP_E_OVERFLOW, if the value will not fit in the destination
2474 * See VarI8FromR8() for details concerning rounding.
2476 HRESULT WINAPI
VarUI8FromR8(double dblIn
, ULONG64
* pui64Out
)
2478 if (dblIn
< -0.5 || dblIn
> 1.844674407370955e19
)
2479 return DISP_E_OVERFLOW
;
2480 VARIANT_DutchRound(ULONG64
, dblIn
, *pui64Out
);
2484 /************************************************************************
2485 * VarUI8FromCy (OLEAUT32.433)
2487 * Convert a VT_CY to a VT_UI8.
2491 * pui64Out [O] Destination
2495 * Failure: E_INVALIDARG, if the source value is invalid
2496 * DISP_E_OVERFLOW, if the value will not fit in the destination
2499 * Negative values >= -5000 will be converted to 0.
2501 HRESULT WINAPI
VarUI8FromCy(CY cyIn
, ULONG64
* pui64Out
)
2505 if (cyIn
.int64
< -CY_HALF
)
2506 return DISP_E_OVERFLOW
;
2511 *pui64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2513 cyIn
.int64
-= *pui64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2515 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pui64Out
& 0x1)))
2521 /************************************************************************
2522 * VarUI8FromDate (OLEAUT32.434)
2524 * Convert a VT_DATE to a VT_UI8.
2528 * pui64Out [O] Destination
2532 * Failure: E_INVALIDARG, if the source value is invalid
2533 * DISP_E_OVERFLOW, if the value will not fit in the destination
2534 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2536 HRESULT WINAPI
VarUI8FromDate(DATE dateIn
, ULONG64
* pui64Out
)
2538 return VarUI8FromR8(dateIn
, pui64Out
);
2541 /************************************************************************
2542 * VarUI8FromStr (OLEAUT32.435)
2544 * Convert a VT_BSTR to a VT_UI8.
2548 * lcid [I] LCID for the conversion
2549 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2550 * pui64Out [O] Destination
2554 * Failure: E_INVALIDARG, if the source value is invalid
2555 * DISP_E_OVERFLOW, if the value will not fit in the destination
2556 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2558 HRESULT WINAPI
VarUI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG64
* pui64Out
)
2560 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pui64Out
, VT_UI8
);
2563 /************************************************************************
2564 * VarUI8FromDisp (OLEAUT32.436)
2566 * Convert a VT_DISPATCH to a VT_UI8.
2569 * pdispIn [I] Source
2570 * lcid [I] LCID for conversion
2571 * pui64Out [O] Destination
2575 * Failure: E_INVALIDARG, if the source value is invalid
2576 * DISP_E_OVERFLOW, if the value will not fit in the destination
2577 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2579 HRESULT WINAPI
VarUI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG64
* pui64Out
)
2581 return VARIANT_FromDisp(pdispIn
, lcid
, pui64Out
, VT_UI8
, 0);
2584 /************************************************************************
2585 * VarUI8FromBool (OLEAUT32.437)
2587 * Convert a VT_BOOL to a VT_UI8.
2591 * pui64Out [O] Destination
2595 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2597 HRESULT WINAPI
VarUI8FromBool(VARIANT_BOOL boolIn
, ULONG64
* pui64Out
)
2599 return VarI8FromI2(boolIn
, (LONG64
*)pui64Out
);
2601 /************************************************************************
2602 * VarUI8FromI1 (OLEAUT32.438)
2604 * Convert a VT_I1 to a VT_UI8.
2608 * pui64Out [O] Destination
2612 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2614 HRESULT WINAPI
VarUI8FromI1(signed char cIn
, ULONG64
* pui64Out
)
2616 return _VarUI8FromI1(cIn
, pui64Out
);
2619 /************************************************************************
2620 * VarUI8FromUI2 (OLEAUT32.439)
2622 * Convert a VT_UI2 to a VT_UI8.
2626 * pui64Out [O] Destination
2631 HRESULT WINAPI
VarUI8FromUI2(USHORT usIn
, ULONG64
* pui64Out
)
2633 return _VarUI8FromUI2(usIn
, pui64Out
);
2636 /************************************************************************
2637 * VarUI8FromUI4 (OLEAUT32.440)
2639 * Convert a VT_UI4 to a VT_UI8.
2643 * pui64Out [O] Destination
2648 HRESULT WINAPI
VarUI8FromUI4(ULONG ulIn
, ULONG64
* pui64Out
)
2650 return _VarUI8FromUI4(ulIn
, pui64Out
);
2653 /************************************************************************
2654 * VarUI8FromDec (OLEAUT32.441)
2656 * Convert a VT_DECIMAL to a VT_UI8.
2660 * pui64Out [O] Destination
2664 * Failure: E_INVALIDARG, if the source value is invalid
2665 * DISP_E_OVERFLOW, if the value will not fit in the destination
2668 * Under native Win32, if the source value has a scale of 0, its sign is
2669 * ignored, i.e. this function takes the absolute value rather than fail
2670 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2671 * (use VarAbs() on pDecIn first if you really want this behaviour).
2673 HRESULT WINAPI
VarUI8FromDec(DECIMAL
*pdecIn
, ULONG64
* pui64Out
)
2675 if (!DEC_SCALE(pdecIn
))
2677 /* This decimal is just a 96 bit integer */
2678 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2679 return E_INVALIDARG
;
2681 if (DEC_HI32(pdecIn
))
2682 return DISP_E_OVERFLOW
;
2684 if (DEC_SIGN(pdecIn
))
2686 WARN("Sign would be ignored under Win32!\n");
2687 return DISP_E_OVERFLOW
;
2690 *pui64Out
= DEC_LO64(pdecIn
);
2695 /* Decimal contains a floating point number */
2699 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2700 if (SUCCEEDED(hRet
))
2701 hRet
= VarUI8FromR8(dbl
, pui64Out
);
2709 /************************************************************************
2710 * VarR4FromUI1 (OLEAUT32.68)
2712 * Convert a VT_UI1 to a VT_R4.
2716 * pFltOut [O] Destination
2721 HRESULT WINAPI
VarR4FromUI1(BYTE bIn
, float *pFltOut
)
2723 return _VarR4FromUI1(bIn
, pFltOut
);
2726 /************************************************************************
2727 * VarR4FromI2 (OLEAUT32.69)
2729 * Convert a VT_I2 to a VT_R4.
2733 * pFltOut [O] Destination
2738 HRESULT WINAPI
VarR4FromI2(SHORT sIn
, float *pFltOut
)
2740 return _VarR4FromI2(sIn
, pFltOut
);
2743 /************************************************************************
2744 * VarR4FromI4 (OLEAUT32.70)
2746 * Convert a VT_I4 to a VT_R4.
2750 * pFltOut [O] Destination
2755 HRESULT WINAPI
VarR4FromI4(LONG lIn
, float *pFltOut
)
2757 return _VarR4FromI4(lIn
, pFltOut
);
2760 /************************************************************************
2761 * VarR4FromR8 (OLEAUT32.71)
2763 * Convert a VT_R8 to a VT_R4.
2767 * pFltOut [O] Destination
2771 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2773 HRESULT WINAPI
VarR4FromR8(double dblIn
, float *pFltOut
)
2775 double d
= dblIn
< 0.0 ? -dblIn
: dblIn
;
2776 if (d
> R4_MAX
) return DISP_E_OVERFLOW
;
2781 /************************************************************************
2782 * VarR4FromCy (OLEAUT32.72)
2784 * Convert a VT_CY to a VT_R4.
2788 * pFltOut [O] Destination
2793 HRESULT WINAPI
VarR4FromCy(CY cyIn
, float *pFltOut
)
2795 *pFltOut
= (double)cyIn
.int64
/ CY_MULTIPLIER_F
;
2799 /************************************************************************
2800 * VarR4FromDate (OLEAUT32.73)
2802 * Convert a VT_DATE to a VT_R4.
2806 * pFltOut [O] Destination
2810 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2812 HRESULT WINAPI
VarR4FromDate(DATE dateIn
, float *pFltOut
)
2814 return VarR4FromR8(dateIn
, pFltOut
);
2817 /************************************************************************
2818 * VarR4FromStr (OLEAUT32.74)
2820 * Convert a VT_BSTR to a VT_R4.
2824 * lcid [I] LCID for the conversion
2825 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2826 * pFltOut [O] Destination
2830 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2831 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2833 HRESULT WINAPI
VarR4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, float *pFltOut
)
2835 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pFltOut
, VT_R4
);
2838 /************************************************************************
2839 * VarR4FromDisp (OLEAUT32.75)
2841 * Convert a VT_DISPATCH to a VT_R4.
2844 * pdispIn [I] Source
2845 * lcid [I] LCID for conversion
2846 * pFltOut [O] Destination
2850 * Failure: E_INVALIDARG, if the source value is invalid
2851 * DISP_E_OVERFLOW, if the value will not fit in the destination
2852 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2854 HRESULT WINAPI
VarR4FromDisp(IDispatch
* pdispIn
, LCID lcid
, float *pFltOut
)
2856 return VARIANT_FromDisp(pdispIn
, lcid
, pFltOut
, VT_R4
, 0);
2859 /************************************************************************
2860 * VarR4FromBool (OLEAUT32.76)
2862 * Convert a VT_BOOL to a VT_R4.
2866 * pFltOut [O] Destination
2871 HRESULT WINAPI
VarR4FromBool(VARIANT_BOOL boolIn
, float *pFltOut
)
2873 return VarR4FromI2(boolIn
, pFltOut
);
2876 /************************************************************************
2877 * VarR4FromI1 (OLEAUT32.213)
2879 * Convert a VT_I1 to a VT_R4.
2883 * pFltOut [O] Destination
2887 * Failure: E_INVALIDARG, if the source value is invalid
2888 * DISP_E_OVERFLOW, if the value will not fit in the destination
2889 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2891 HRESULT WINAPI
VarR4FromI1(signed char cIn
, float *pFltOut
)
2893 return _VarR4FromI1(cIn
, pFltOut
);
2896 /************************************************************************
2897 * VarR4FromUI2 (OLEAUT32.214)
2899 * Convert a VT_UI2 to a VT_R4.
2903 * pFltOut [O] Destination
2907 * Failure: E_INVALIDARG, if the source value is invalid
2908 * DISP_E_OVERFLOW, if the value will not fit in the destination
2909 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2911 HRESULT WINAPI
VarR4FromUI2(USHORT usIn
, float *pFltOut
)
2913 return _VarR4FromUI2(usIn
, pFltOut
);
2916 /************************************************************************
2917 * VarR4FromUI4 (OLEAUT32.215)
2919 * Convert a VT_UI4 to a VT_R4.
2923 * pFltOut [O] Destination
2927 * Failure: E_INVALIDARG, if the source value is invalid
2928 * DISP_E_OVERFLOW, if the value will not fit in the destination
2929 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2931 HRESULT WINAPI
VarR4FromUI4(ULONG ulIn
, float *pFltOut
)
2933 return _VarR4FromUI4(ulIn
, pFltOut
);
2936 /************************************************************************
2937 * VarR4FromDec (OLEAUT32.216)
2939 * Convert a VT_DECIMAL to a VT_R4.
2943 * pFltOut [O] Destination
2947 * Failure: E_INVALIDARG, if the source value is invalid.
2949 HRESULT WINAPI
VarR4FromDec(DECIMAL
* pDecIn
, float *pFltOut
)
2951 BYTE scale
= DEC_SCALE(pDecIn
);
2955 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
2956 return E_INVALIDARG
;
2961 if (DEC_SIGN(pDecIn
))
2964 if (DEC_HI32(pDecIn
))
2966 highPart
= (double)DEC_HI32(pDecIn
) / (double)divisor
;
2967 highPart
*= 4294967296.0F
;
2968 highPart
*= 4294967296.0F
;
2973 *pFltOut
= (double)DEC_LO64(pDecIn
) / (double)divisor
+ highPart
;
2977 /************************************************************************
2978 * VarR4FromI8 (OLEAUT32.360)
2980 * Convert a VT_I8 to a VT_R4.
2984 * pFltOut [O] Destination
2989 HRESULT WINAPI
VarR4FromI8(LONG64 llIn
, float *pFltOut
)
2991 return _VarR4FromI8(llIn
, pFltOut
);
2994 /************************************************************************
2995 * VarR4FromUI8 (OLEAUT32.361)
2997 * Convert a VT_UI8 to a VT_R4.
3001 * pFltOut [O] Destination
3006 HRESULT WINAPI
VarR4FromUI8(ULONG64 ullIn
, float *pFltOut
)
3008 return _VarR4FromUI8(ullIn
, pFltOut
);
3011 /************************************************************************
3012 * VarR4CmpR8 (OLEAUT32.316)
3014 * Compare a VT_R4 to a VT_R8.
3017 * fltLeft [I] Source
3018 * dblRight [I] Value to compare
3021 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3022 * equal to or greater than dblRight respectively.
3024 HRESULT WINAPI
VarR4CmpR8(float fltLeft
, double dblRight
)
3026 if (fltLeft
< dblRight
)
3028 else if (fltLeft
> dblRight
)
3036 /************************************************************************
3037 * VarR8FromUI1 (OLEAUT32.78)
3039 * Convert a VT_UI1 to a VT_R8.
3043 * pDblOut [O] Destination
3048 HRESULT WINAPI
VarR8FromUI1(BYTE bIn
, double *pDblOut
)
3050 return _VarR8FromUI1(bIn
, pDblOut
);
3053 /************************************************************************
3054 * VarR8FromI2 (OLEAUT32.79)
3056 * Convert a VT_I2 to a VT_R8.
3060 * pDblOut [O] Destination
3065 HRESULT WINAPI
VarR8FromI2(SHORT sIn
, double *pDblOut
)
3067 return _VarR8FromI2(sIn
, pDblOut
);
3070 /************************************************************************
3071 * VarR8FromI4 (OLEAUT32.80)
3073 * Convert a VT_I4 to a VT_R8.
3077 * pDblOut [O] Destination
3082 HRESULT WINAPI
VarR8FromI4(LONG lIn
, double *pDblOut
)
3084 return _VarR8FromI4(lIn
, pDblOut
);
3087 /************************************************************************
3088 * VarR8FromR4 (OLEAUT32.81)
3090 * Convert a VT_R4 to a VT_R8.
3094 * pDblOut [O] Destination
3099 HRESULT WINAPI
VarR8FromR4(FLOAT fltIn
, double *pDblOut
)
3101 return _VarR8FromR4(fltIn
, pDblOut
);
3104 /************************************************************************
3105 * VarR8FromCy (OLEAUT32.82)
3107 * Convert a VT_CY to a VT_R8.
3111 * pDblOut [O] Destination
3116 HRESULT WINAPI
VarR8FromCy(CY cyIn
, double *pDblOut
)
3118 return _VarR8FromCy(cyIn
, pDblOut
);
3121 /************************************************************************
3122 * VarR8FromDate (OLEAUT32.83)
3124 * Convert a VT_DATE to a VT_R8.
3128 * pDblOut [O] Destination
3133 HRESULT WINAPI
VarR8FromDate(DATE dateIn
, double *pDblOut
)
3135 return _VarR8FromDate(dateIn
, pDblOut
);
3138 /************************************************************************
3139 * VarR8FromStr (OLEAUT32.84)
3141 * Convert a VT_BSTR to a VT_R8.
3145 * lcid [I] LCID for the conversion
3146 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3147 * pDblOut [O] Destination
3151 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3152 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3154 HRESULT WINAPI
VarR8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, double *pDblOut
)
3156 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDblOut
, VT_R8
);
3159 /************************************************************************
3160 * VarR8FromDisp (OLEAUT32.85)
3162 * Convert a VT_DISPATCH to a VT_R8.
3165 * pdispIn [I] Source
3166 * lcid [I] LCID for conversion
3167 * pDblOut [O] Destination
3171 * Failure: E_INVALIDARG, if the source value is invalid
3172 * DISP_E_OVERFLOW, if the value will not fit in the destination
3173 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3175 HRESULT WINAPI
VarR8FromDisp(IDispatch
* pdispIn
, LCID lcid
, double *pDblOut
)
3177 return VARIANT_FromDisp(pdispIn
, lcid
, pDblOut
, VT_R8
, 0);
3180 /************************************************************************
3181 * VarR8FromBool (OLEAUT32.86)
3183 * Convert a VT_BOOL to a VT_R8.
3187 * pDblOut [O] Destination
3192 HRESULT WINAPI
VarR8FromBool(VARIANT_BOOL boolIn
, double *pDblOut
)
3194 return VarR8FromI2(boolIn
, pDblOut
);
3197 /************************************************************************
3198 * VarR8FromI1 (OLEAUT32.217)
3200 * Convert a VT_I1 to a VT_R8.
3204 * pDblOut [O] Destination
3208 * Failure: E_INVALIDARG, if the source value is invalid
3209 * DISP_E_OVERFLOW, if the value will not fit in the destination
3210 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3212 HRESULT WINAPI
VarR8FromI1(signed char cIn
, double *pDblOut
)
3214 return _VarR8FromI1(cIn
, pDblOut
);
3217 /************************************************************************
3218 * VarR8FromUI2 (OLEAUT32.218)
3220 * Convert a VT_UI2 to a VT_R8.
3224 * pDblOut [O] Destination
3228 * Failure: E_INVALIDARG, if the source value is invalid
3229 * DISP_E_OVERFLOW, if the value will not fit in the destination
3230 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3232 HRESULT WINAPI
VarR8FromUI2(USHORT usIn
, double *pDblOut
)
3234 return _VarR8FromUI2(usIn
, pDblOut
);
3237 /************************************************************************
3238 * VarR8FromUI4 (OLEAUT32.219)
3240 * Convert a VT_UI4 to a VT_R8.
3244 * pDblOut [O] Destination
3248 * Failure: E_INVALIDARG, if the source value is invalid
3249 * DISP_E_OVERFLOW, if the value will not fit in the destination
3250 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3252 HRESULT WINAPI
VarR8FromUI4(ULONG ulIn
, double *pDblOut
)
3254 return _VarR8FromUI4(ulIn
, pDblOut
);
3257 /************************************************************************
3258 * VarR8FromDec (OLEAUT32.220)
3260 * Convert a VT_DECIMAL to a VT_R8.
3264 * pDblOut [O] Destination
3268 * Failure: E_INVALIDARG, if the source value is invalid.
3270 HRESULT WINAPI
VarR8FromDec(DECIMAL
* pDecIn
, double *pDblOut
)
3272 BYTE scale
= DEC_SCALE(pDecIn
);
3273 double divisor
= 1.0, highPart
;
3275 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
3276 return E_INVALIDARG
;
3281 if (DEC_SIGN(pDecIn
))
3284 if (DEC_HI32(pDecIn
))
3286 highPart
= (double)DEC_HI32(pDecIn
) / divisor
;
3287 highPart
*= 4294967296.0F
;
3288 highPart
*= 4294967296.0F
;
3293 *pDblOut
= (double)DEC_LO64(pDecIn
) / divisor
+ highPart
;
3297 /************************************************************************
3298 * VarR8FromI8 (OLEAUT32.362)
3300 * Convert a VT_I8 to a VT_R8.
3304 * pDblOut [O] Destination
3309 HRESULT WINAPI
VarR8FromI8(LONG64 llIn
, double *pDblOut
)
3311 return _VarR8FromI8(llIn
, pDblOut
);
3314 /************************************************************************
3315 * VarR8FromUI8 (OLEAUT32.363)
3317 * Convert a VT_UI8 to a VT_R8.
3321 * pDblOut [O] Destination
3326 HRESULT WINAPI
VarR8FromUI8(ULONG64 ullIn
, double *pDblOut
)
3328 return _VarR8FromUI8(ullIn
, pDblOut
);
3331 /************************************************************************
3332 * VarR8Pow (OLEAUT32.315)
3334 * Raise a VT_R8 to a power.
3337 * dblLeft [I] Source
3338 * dblPow [I] Power to raise dblLeft by
3339 * pDblOut [O] Destination
3342 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3344 HRESULT WINAPI
VarR8Pow(double dblLeft
, double dblPow
, double *pDblOut
)
3346 *pDblOut
= pow(dblLeft
, dblPow
);
3350 /************************************************************************
3351 * VarR8Round (OLEAUT32.317)
3353 * Round a VT_R8 to a given number of decimal points.
3357 * nDig [I] Number of decimal points to round to
3358 * pDblOut [O] Destination for rounded number
3361 * Success: S_OK. pDblOut is rounded to nDig digits.
3362 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3365 * The native version of this function rounds using the internal
3366 * binary representation of the number. Wine uses the dutch rounding
3367 * convention, so therefore small differences can occur in the value returned.
3368 * MSDN says that you should use your own rounding function if you want
3369 * rounding to be predictable in your application.
3371 HRESULT WINAPI
VarR8Round(double dblIn
, int nDig
, double *pDblOut
)
3373 double scale
, whole
, fract
;
3376 return E_INVALIDARG
;
3378 scale
= pow(10.0, nDig
);
3381 whole
= dblIn
< 0 ? ceil(dblIn
) : floor(dblIn
);
3382 fract
= dblIn
- whole
;
3385 dblIn
= whole
+ 1.0;
3386 else if (fract
== 0.5)
3387 dblIn
= whole
+ fmod(whole
, 2.0);
3388 else if (fract
>= 0.0)
3390 else if (fract
== -0.5)
3391 dblIn
= whole
- fmod(whole
, 2.0);
3392 else if (fract
> -0.5)
3395 dblIn
= whole
- 1.0;
3397 *pDblOut
= dblIn
/ scale
;
3404 /* Powers of 10 from 0..4 D.P. */
3405 static const int CY_Divisors
[5] = { CY_MULTIPLIER
/10000, CY_MULTIPLIER
/1000,
3406 CY_MULTIPLIER
/100, CY_MULTIPLIER
/10, CY_MULTIPLIER
};
3408 /************************************************************************
3409 * VarCyFromUI1 (OLEAUT32.98)
3411 * Convert a VT_UI1 to a VT_CY.
3415 * pCyOut [O] Destination
3419 * Failure: E_INVALIDARG, if the source value is invalid
3420 * DISP_E_OVERFLOW, if the value will not fit in the destination
3421 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3423 HRESULT WINAPI
VarCyFromUI1(BYTE bIn
, CY
* pCyOut
)
3425 return VarCyFromR8(bIn
, pCyOut
);
3428 /************************************************************************
3429 * VarCyFromI2 (OLEAUT32.99)
3431 * Convert a VT_I2 to a VT_CY.
3435 * pCyOut [O] Destination
3439 * Failure: E_INVALIDARG, if the source value is invalid
3440 * DISP_E_OVERFLOW, if the value will not fit in the destination
3441 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3443 HRESULT WINAPI
VarCyFromI2(SHORT sIn
, CY
* pCyOut
)
3445 return VarCyFromR8(sIn
, pCyOut
);
3448 /************************************************************************
3449 * VarCyFromI4 (OLEAUT32.100)
3451 * Convert a VT_I4 to a VT_CY.
3455 * pCyOut [O] Destination
3459 * Failure: E_INVALIDARG, if the source value is invalid
3460 * DISP_E_OVERFLOW, if the value will not fit in the destination
3461 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3463 HRESULT WINAPI
VarCyFromI4(LONG lIn
, CY
* pCyOut
)
3465 return VarCyFromR8(lIn
, pCyOut
);
3468 /************************************************************************
3469 * VarCyFromR4 (OLEAUT32.101)
3471 * Convert a VT_R4 to a VT_CY.
3475 * pCyOut [O] Destination
3479 * Failure: E_INVALIDARG, if the source value is invalid
3480 * DISP_E_OVERFLOW, if the value will not fit in the destination
3481 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3483 HRESULT WINAPI
VarCyFromR4(FLOAT fltIn
, CY
* pCyOut
)
3485 return VarCyFromR8(fltIn
, pCyOut
);
3488 /************************************************************************
3489 * VarCyFromR8 (OLEAUT32.102)
3491 * Convert a VT_R8 to a VT_CY.
3495 * pCyOut [O] Destination
3499 * Failure: E_INVALIDARG, if the source value is invalid
3500 * DISP_E_OVERFLOW, if the value will not fit in the destination
3501 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3503 HRESULT WINAPI
VarCyFromR8(double dblIn
, CY
* pCyOut
)
3505 #if defined(__GNUC__) && defined(__i386__)
3506 /* This code gives identical results to Win32 on Intel.
3507 * Here we use fp exceptions to catch overflows when storing the value.
3509 static const unsigned short r8_fpcontrol
= 0x137f;
3510 static const double r8_multiplier
= CY_MULTIPLIER_F
;
3511 unsigned short old_fpcontrol
, result_fpstatus
;
3513 /* Clear exceptions, save the old fp state and load the new state */
3514 __asm__
__volatile__( "fnclex" );
3515 __asm__
__volatile__( "fstcw %0" : "=m" (old_fpcontrol
) : );
3516 __asm__
__volatile__( "fldcw %0" : : "m" (r8_fpcontrol
) );
3517 /* Perform the conversion. */
3518 __asm__
__volatile__( "fldl %0" : : "m" (dblIn
) );
3519 __asm__
__volatile__( "fmull %0" : : "m" (r8_multiplier
) );
3520 __asm__
__volatile__( "fistpll %0" : : "m" (*pCyOut
) );
3521 /* Save the resulting fp state, load the old state and clear exceptions */
3522 __asm__
__volatile__( "fstsw %0" : "=m" (result_fpstatus
) : );
3523 __asm__
__volatile__( "fnclex" );
3524 __asm__
__volatile__( "fldcw %0" : : "m" (old_fpcontrol
) );
3526 if (result_fpstatus
& 0x9) /* Overflow | Invalid */
3527 return DISP_E_OVERFLOW
;
3530 /* This version produces slightly different results for boundary cases */
3531 if (dblIn
< -922337203685477.5807 || dblIn
>= 922337203685477.5807)
3532 return DISP_E_OVERFLOW
;
3533 dblIn
*= CY_MULTIPLIER_F
;
3534 VARIANT_DutchRound(LONG64
, dblIn
, pCyOut
->int64
);
3539 /************************************************************************
3540 * VarCyFromDate (OLEAUT32.103)
3542 * Convert a VT_DATE to a VT_CY.
3546 * pCyOut [O] Destination
3550 * Failure: E_INVALIDARG, if the source value is invalid
3551 * DISP_E_OVERFLOW, if the value will not fit in the destination
3552 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3554 HRESULT WINAPI
VarCyFromDate(DATE dateIn
, CY
* pCyOut
)
3556 return VarCyFromR8(dateIn
, pCyOut
);
3559 /************************************************************************
3560 * VarCyFromStr (OLEAUT32.104)
3562 * Convert a VT_BSTR to a VT_CY.
3566 * lcid [I] LCID for the conversion
3567 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3568 * pCyOut [O] Destination
3572 * Failure: E_INVALIDARG, if the source value is invalid
3573 * DISP_E_OVERFLOW, if the value will not fit in the destination
3574 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3576 HRESULT WINAPI
VarCyFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, CY
* pCyOut
)
3578 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pCyOut
, VT_CY
);
3581 /************************************************************************
3582 * VarCyFromDisp (OLEAUT32.105)
3584 * Convert a VT_DISPATCH to a VT_CY.
3587 * pdispIn [I] Source
3588 * lcid [I] LCID for conversion
3589 * pCyOut [O] Destination
3593 * Failure: E_INVALIDARG, if the source value is invalid
3594 * DISP_E_OVERFLOW, if the value will not fit in the destination
3595 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3597 HRESULT WINAPI
VarCyFromDisp(IDispatch
* pdispIn
, LCID lcid
, CY
* pCyOut
)
3599 return VARIANT_FromDisp(pdispIn
, lcid
, pCyOut
, VT_CY
, 0);
3602 /************************************************************************
3603 * VarCyFromBool (OLEAUT32.106)
3605 * Convert a VT_BOOL to a VT_CY.
3609 * pCyOut [O] Destination
3613 * Failure: E_INVALIDARG, if the source value is invalid
3614 * DISP_E_OVERFLOW, if the value will not fit in the destination
3615 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3618 * While the sign of the boolean is stored in the currency, the value is
3619 * converted to either 0 or 1.
3621 HRESULT WINAPI
VarCyFromBool(VARIANT_BOOL boolIn
, CY
* pCyOut
)
3623 return VarCyFromR8(boolIn
, pCyOut
);
3626 /************************************************************************
3627 * VarCyFromI1 (OLEAUT32.225)
3629 * Convert a VT_I1 to a VT_CY.
3633 * pCyOut [O] Destination
3637 * Failure: E_INVALIDARG, if the source value is invalid
3638 * DISP_E_OVERFLOW, if the value will not fit in the destination
3639 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3641 HRESULT WINAPI
VarCyFromI1(signed char cIn
, CY
* pCyOut
)
3643 return VarCyFromR8(cIn
, pCyOut
);
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 return VarCyFromR8(usIn
, pCyOut
);
3666 /************************************************************************
3667 * VarCyFromUI4 (OLEAUT32.227)
3669 * Convert a VT_UI4 to a VT_CY.
3673 * pCyOut [O] Destination
3677 * Failure: E_INVALIDARG, if the source value is invalid
3678 * DISP_E_OVERFLOW, if the value will not fit in the destination
3679 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3681 HRESULT WINAPI
VarCyFromUI4(ULONG ulIn
, CY
* pCyOut
)
3683 return VarCyFromR8(ulIn
, pCyOut
);
3686 /************************************************************************
3687 * VarCyFromDec (OLEAUT32.228)
3689 * Convert a VT_DECIMAL to a VT_CY.
3693 * pCyOut [O] Destination
3697 * Failure: E_INVALIDARG, if the source value is invalid
3698 * DISP_E_OVERFLOW, if the value will not fit in the destination
3699 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3701 HRESULT WINAPI
VarCyFromDec(DECIMAL
* pdecIn
, CY
* pCyOut
)
3706 hRet
= VarDecRound(pdecIn
, 4, &rounded
);
3708 if (SUCCEEDED(hRet
))
3712 if (DEC_HI32(&rounded
))
3713 return DISP_E_OVERFLOW
;
3715 /* Note: Without the casts this promotes to int64 which loses precision */
3716 d
= (double)DEC_LO64(&rounded
) / (double)CY_Divisors
[DEC_SCALE(&rounded
)];
3717 if (DEC_SIGN(&rounded
))
3719 return VarCyFromR8(d
, pCyOut
);
3724 /************************************************************************
3725 * VarCyFromI8 (OLEAUT32.366)
3727 * Convert a VT_I8 to a VT_CY.
3731 * pCyOut [O] Destination
3735 * Failure: E_INVALIDARG, if the source value is invalid
3736 * DISP_E_OVERFLOW, if the value will not fit in the destination
3737 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3739 HRESULT WINAPI
VarCyFromI8(LONG64 llIn
, CY
* pCyOut
)
3741 if (llIn
<= (I8_MIN
/CY_MULTIPLIER
) || llIn
>= (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3742 pCyOut
->int64
= llIn
* CY_MULTIPLIER
;
3746 /************************************************************************
3747 * VarCyFromUI8 (OLEAUT32.375)
3749 * Convert a VT_UI8 to a VT_CY.
3753 * pCyOut [O] Destination
3757 * Failure: E_INVALIDARG, if the source value is invalid
3758 * DISP_E_OVERFLOW, if the value will not fit in the destination
3759 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3761 HRESULT WINAPI
VarCyFromUI8(ULONG64 ullIn
, CY
* pCyOut
)
3763 return VarCyFromR8(ullIn
, pCyOut
);
3766 /************************************************************************
3767 * VarCyAdd (OLEAUT32.299)
3769 * Add one CY to another.
3773 * cyRight [I] Value to add
3774 * pCyOut [O] Destination
3778 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3780 HRESULT WINAPI
VarCyAdd(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3783 _VarR8FromCy(cyLeft
, &l
);
3784 _VarR8FromCy(cyRight
, &r
);
3786 return VarCyFromR8(l
, pCyOut
);
3789 /************************************************************************
3790 * VarCyMul (OLEAUT32.303)
3792 * Multiply one CY by another.
3796 * cyRight [I] Value to multiply by
3797 * pCyOut [O] Destination
3801 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3803 HRESULT WINAPI
VarCyMul(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3806 _VarR8FromCy(cyLeft
, &l
);
3807 _VarR8FromCy(cyRight
, &r
);
3809 return VarCyFromR8(l
, pCyOut
);
3812 /************************************************************************
3813 * VarCyMulI4 (OLEAUT32.304)
3815 * Multiply one CY by a VT_I4.
3819 * lRight [I] Value to multiply by
3820 * pCyOut [O] Destination
3824 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3826 HRESULT WINAPI
VarCyMulI4(const CY cyLeft
, LONG lRight
, CY
* pCyOut
)
3830 _VarR8FromCy(cyLeft
, &d
);
3832 return VarCyFromR8(d
, pCyOut
);
3835 /************************************************************************
3836 * VarCySub (OLEAUT32.305)
3838 * Subtract one CY from another.
3842 * cyRight [I] Value to subtract
3843 * pCyOut [O] Destination
3847 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3849 HRESULT WINAPI
VarCySub(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3852 _VarR8FromCy(cyLeft
, &l
);
3853 _VarR8FromCy(cyRight
, &r
);
3855 return VarCyFromR8(l
, pCyOut
);
3858 /************************************************************************
3859 * VarCyAbs (OLEAUT32.306)
3861 * Convert a VT_CY into its absolute value.
3865 * pCyOut [O] Destination
3868 * Success: S_OK. pCyOut contains the absolute value.
3869 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3871 HRESULT WINAPI
VarCyAbs(const CY cyIn
, CY
* pCyOut
)
3873 if (cyIn
.s
.Hi
== (int)0x80000000 && !cyIn
.s
.Lo
)
3874 return DISP_E_OVERFLOW
;
3876 pCyOut
->int64
= cyIn
.int64
< 0 ? -cyIn
.int64
: cyIn
.int64
;
3880 /************************************************************************
3881 * VarCyFix (OLEAUT32.307)
3883 * Return the integer part of a VT_CY.
3887 * pCyOut [O] Destination
3891 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3894 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3895 * negative numbers away from 0, while this function rounds them towards zero.
3897 HRESULT WINAPI
VarCyFix(const CY cyIn
, CY
* pCyOut
)
3899 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3900 pCyOut
->int64
*= CY_MULTIPLIER
;
3904 /************************************************************************
3905 * VarCyInt (OLEAUT32.308)
3907 * Return the integer part of a VT_CY.
3911 * pCyOut [O] Destination
3915 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3918 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3919 * negative numbers towards 0, while this function rounds them away from zero.
3921 HRESULT WINAPI
VarCyInt(const CY cyIn
, CY
* pCyOut
)
3923 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3924 pCyOut
->int64
*= CY_MULTIPLIER
;
3926 if (cyIn
.int64
< 0 && cyIn
.int64
% CY_MULTIPLIER
!= 0)
3928 pCyOut
->int64
-= CY_MULTIPLIER
;
3933 /************************************************************************
3934 * VarCyNeg (OLEAUT32.309)
3936 * Change the sign of a VT_CY.
3940 * pCyOut [O] Destination
3944 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3946 HRESULT WINAPI
VarCyNeg(const CY cyIn
, CY
* pCyOut
)
3948 if (cyIn
.s
.Hi
== (int)0x80000000 && !cyIn
.s
.Lo
)
3949 return DISP_E_OVERFLOW
;
3951 pCyOut
->int64
= -cyIn
.int64
;
3955 /************************************************************************
3956 * VarCyRound (OLEAUT32.310)
3958 * Change the precision of a VT_CY.
3962 * cDecimals [I] New number of decimals to keep
3963 * pCyOut [O] Destination
3967 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3969 HRESULT WINAPI
VarCyRound(const CY cyIn
, int cDecimals
, CY
* pCyOut
)
3972 return E_INVALIDARG
;
3976 /* Rounding to more precision than we have */
3982 double d
, div
= CY_Divisors
[cDecimals
];
3984 _VarR8FromCy(cyIn
, &d
);
3986 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
)
3987 d
= (double)pCyOut
->int64
/ div
* CY_MULTIPLIER_F
;
3988 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
)
3993 /************************************************************************
3994 * VarCyCmp (OLEAUT32.311)
3996 * Compare two VT_CY values.
4000 * cyRight [I] Value to compare
4003 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4004 * compare is less, equal or greater than source respectively.
4005 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4007 HRESULT WINAPI
VarCyCmp(const CY cyLeft
, const CY cyRight
)
4012 /* Subtract right from left, and compare the result to 0 */
4013 hRet
= VarCySub(cyLeft
, cyRight
, &result
);
4015 if (SUCCEEDED(hRet
))
4017 if (result
.int64
< 0)
4018 hRet
= (HRESULT
)VARCMP_LT
;
4019 else if (result
.int64
> 0)
4020 hRet
= (HRESULT
)VARCMP_GT
;
4022 hRet
= (HRESULT
)VARCMP_EQ
;
4027 /************************************************************************
4028 * VarCyCmpR8 (OLEAUT32.312)
4030 * Compare a VT_CY to a double
4033 * cyLeft [I] Currency Source
4034 * dblRight [I] double to compare to cyLeft
4037 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4038 * less than, equal to or greater than cyLeft respectively.
4039 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4041 HRESULT WINAPI
VarCyCmpR8(const CY cyLeft
, double dblRight
)
4046 hRet
= VarCyFromR8(dblRight
, &cyRight
);
4048 if (SUCCEEDED(hRet
))
4049 hRet
= VarCyCmp(cyLeft
, cyRight
);
4054 /************************************************************************
4055 * VarCyMulI8 (OLEAUT32.329)
4057 * Multiply a VT_CY by a VT_I8.
4061 * llRight [I] Value to multiply by
4062 * pCyOut [O] Destination
4066 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4068 HRESULT WINAPI
VarCyMulI8(const CY cyLeft
, LONG64 llRight
, CY
* pCyOut
)
4072 _VarR8FromCy(cyLeft
, &d
);
4073 d
= d
* (double)llRight
;
4074 return VarCyFromR8(d
, pCyOut
);
4080 /************************************************************************
4081 * VarDecFromUI1 (OLEAUT32.190)
4083 * Convert a VT_UI1 to a DECIMAL.
4087 * pDecOut [O] Destination
4092 HRESULT WINAPI
VarDecFromUI1(BYTE bIn
, DECIMAL
* pDecOut
)
4094 return VarDecFromUI4(bIn
, pDecOut
);
4097 /************************************************************************
4098 * VarDecFromI2 (OLEAUT32.191)
4100 * Convert a VT_I2 to a DECIMAL.
4104 * pDecOut [O] Destination
4109 HRESULT WINAPI
VarDecFromI2(SHORT sIn
, DECIMAL
* pDecOut
)
4111 return VarDecFromI4(sIn
, pDecOut
);
4114 /************************************************************************
4115 * VarDecFromI4 (OLEAUT32.192)
4117 * Convert a VT_I4 to a DECIMAL.
4121 * pDecOut [O] Destination
4126 HRESULT WINAPI
VarDecFromI4(LONG lIn
, DECIMAL
* pDecOut
)
4128 DEC_HI32(pDecOut
) = 0;
4129 DEC_MID32(pDecOut
) = 0;
4133 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4134 DEC_LO32(pDecOut
) = -lIn
;
4138 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4139 DEC_LO32(pDecOut
) = lIn
;
4144 #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT))
4146 /************************************************************************
4147 * VarDecFromR4 (OLEAUT32.193)
4149 * Convert a VT_R4 to a DECIMAL.
4153 * pDecOut [O] Destination
4158 HRESULT WINAPI
VarDecFromR4(FLOAT fltIn
, DECIMAL
* pDecOut
)
4162 sprintfW( buff
, szFloatFormatW
, fltIn
);
4163 return VarDecFromStr(buff
, LOCALE_EN_US
, 0, pDecOut
);
4166 /************************************************************************
4167 * VarDecFromR8 (OLEAUT32.194)
4169 * Convert a VT_R8 to a DECIMAL.
4173 * pDecOut [O] Destination
4178 HRESULT WINAPI
VarDecFromR8(double dblIn
, DECIMAL
* pDecOut
)
4182 sprintfW( buff
, szDoubleFormatW
, dblIn
);
4183 return VarDecFromStr(buff
, LOCALE_EN_US
, 0, pDecOut
);
4186 /************************************************************************
4187 * VarDecFromDate (OLEAUT32.195)
4189 * Convert a VT_DATE to a DECIMAL.
4193 * pDecOut [O] Destination
4198 HRESULT WINAPI
VarDecFromDate(DATE dateIn
, DECIMAL
* pDecOut
)
4200 return VarDecFromR8(dateIn
, pDecOut
);
4203 /************************************************************************
4204 * VarDecFromCy (OLEAUT32.196)
4206 * Convert a VT_CY to a DECIMAL.
4210 * pDecOut [O] Destination
4215 HRESULT WINAPI
VarDecFromCy(CY cyIn
, DECIMAL
* pDecOut
)
4217 DEC_HI32(pDecOut
) = 0;
4219 /* Note: This assumes 2s complement integer representation */
4220 if (cyIn
.s
.Hi
& 0x80000000)
4222 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,4);
4223 DEC_LO64(pDecOut
) = -cyIn
.int64
;
4227 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,4);
4228 DEC_MID32(pDecOut
) = cyIn
.s
.Hi
;
4229 DEC_LO32(pDecOut
) = cyIn
.s
.Lo
;
4234 /************************************************************************
4235 * VarDecFromStr (OLEAUT32.197)
4237 * Convert a VT_BSTR to a DECIMAL.
4241 * lcid [I] LCID for the conversion
4242 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4243 * pDecOut [O] Destination
4247 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4249 HRESULT WINAPI
VarDecFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DECIMAL
* pDecOut
)
4251 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDecOut
, VT_DECIMAL
);
4254 /************************************************************************
4255 * VarDecFromDisp (OLEAUT32.198)
4257 * Convert a VT_DISPATCH to a DECIMAL.
4260 * pdispIn [I] Source
4261 * lcid [I] LCID for conversion
4262 * pDecOut [O] Destination
4266 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4268 HRESULT WINAPI
VarDecFromDisp(IDispatch
* pdispIn
, LCID lcid
, DECIMAL
* pDecOut
)
4270 return VARIANT_FromDisp(pdispIn
, lcid
, pDecOut
, VT_DECIMAL
, 0);
4273 /************************************************************************
4274 * VarDecFromBool (OLEAUT32.199)
4276 * Convert a VT_BOOL to a DECIMAL.
4280 * pDecOut [O] Destination
4286 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4288 HRESULT WINAPI
VarDecFromBool(VARIANT_BOOL bIn
, DECIMAL
* pDecOut
)
4290 DEC_HI32(pDecOut
) = 0;
4291 DEC_MID32(pDecOut
) = 0;
4294 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4295 DEC_LO32(pDecOut
) = 1;
4299 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4300 DEC_LO32(pDecOut
) = 0;
4305 /************************************************************************
4306 * VarDecFromI1 (OLEAUT32.241)
4308 * Convert a VT_I1 to a DECIMAL.
4312 * pDecOut [O] Destination
4317 HRESULT WINAPI
VarDecFromI1(signed char cIn
, DECIMAL
* pDecOut
)
4319 return VarDecFromI4(cIn
, pDecOut
);
4322 /************************************************************************
4323 * VarDecFromUI2 (OLEAUT32.242)
4325 * Convert a VT_UI2 to a DECIMAL.
4329 * pDecOut [O] Destination
4334 HRESULT WINAPI
VarDecFromUI2(USHORT usIn
, DECIMAL
* pDecOut
)
4336 return VarDecFromUI4(usIn
, pDecOut
);
4339 /************************************************************************
4340 * VarDecFromUI4 (OLEAUT32.243)
4342 * Convert a VT_UI4 to a DECIMAL.
4346 * pDecOut [O] Destination
4351 HRESULT WINAPI
VarDecFromUI4(ULONG ulIn
, DECIMAL
* pDecOut
)
4353 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4354 DEC_HI32(pDecOut
) = 0;
4355 DEC_MID32(pDecOut
) = 0;
4356 DEC_LO32(pDecOut
) = ulIn
;
4360 /************************************************************************
4361 * VarDecFromI8 (OLEAUT32.374)
4363 * Convert a VT_I8 to a DECIMAL.
4367 * pDecOut [O] Destination
4372 HRESULT WINAPI
VarDecFromI8(LONG64 llIn
, DECIMAL
* pDecOut
)
4374 PULARGE_INTEGER pLi
= (PULARGE_INTEGER
)&llIn
;
4376 DEC_HI32(pDecOut
) = 0;
4378 /* Note: This assumes 2s complement integer representation */
4379 if (pLi
->u
.HighPart
& 0x80000000)
4381 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4382 DEC_LO64(pDecOut
) = -pLi
->QuadPart
;
4386 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4387 DEC_MID32(pDecOut
) = pLi
->u
.HighPart
;
4388 DEC_LO32(pDecOut
) = pLi
->u
.LowPart
;
4393 /************************************************************************
4394 * VarDecFromUI8 (OLEAUT32.375)
4396 * Convert a VT_UI8 to a DECIMAL.
4400 * pDecOut [O] Destination
4405 HRESULT WINAPI
VarDecFromUI8(ULONG64 ullIn
, DECIMAL
* pDecOut
)
4407 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4408 DEC_HI32(pDecOut
) = 0;
4409 DEC_LO64(pDecOut
) = ullIn
;
4413 /* Make two DECIMALS the same scale; used by math functions below */
4414 static HRESULT
VARIANT_DecScale(const DECIMAL
** ppDecLeft
,
4415 const DECIMAL
** ppDecRight
,
4418 static DECIMAL scaleFactor
;
4421 HRESULT hRet
= S_OK
;
4423 if (DEC_SIGN(*ppDecLeft
) & ~DECIMAL_NEG
|| DEC_SIGN(*ppDecRight
) & ~DECIMAL_NEG
)
4424 return E_INVALIDARG
;
4426 DEC_LO32(&scaleFactor
) = 10;
4428 i
= scaleAmount
= DEC_SCALE(*ppDecLeft
) - DEC_SCALE(*ppDecRight
);
4431 return S_OK
; /* Same scale */
4433 if (scaleAmount
> 0)
4435 decTemp
= *(*ppDecRight
); /* Left is bigger - scale the right hand side */
4436 *ppDecRight
= pDecOut
;
4440 decTemp
= *(*ppDecLeft
); /* Right is bigger - scale the left hand side */
4441 *ppDecLeft
= pDecOut
;
4442 i
= scaleAmount
= -scaleAmount
;
4445 if (DEC_SCALE(&decTemp
) + scaleAmount
> DEC_MAX_SCALE
)
4446 return DISP_E_OVERFLOW
; /* Can't scale up */
4448 /* Multiply up the value to be scaled by the correct amount */
4449 while (SUCCEEDED(hRet
) && i
--)
4451 /* Note we are multiplying by a value with a scale of 0, so we don't recurse */
4452 hRet
= VarDecMul(&decTemp
, &scaleFactor
, pDecOut
);
4455 DEC_SCALE(pDecOut
) += scaleAmount
; /* Set the new scale */
4459 /* Add two unsigned 32 bit values with overflow */
4460 static ULONG
VARIANT_Add(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4462 ULARGE_INTEGER ul64
;
4464 ul64
.QuadPart
= (ULONG64
)ulLeft
+ (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4465 *pulHigh
= ul64
.u
.HighPart
;
4466 return ul64
.u
.LowPart
;
4469 /* Subtract two unsigned 32 bit values with underflow */
4470 static ULONG
VARIANT_Sub(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4473 ULARGE_INTEGER ul64
;
4475 ul64
.QuadPart
= (LONG64
)ulLeft
- (ULONG64
)ulRight
;
4476 if (ulLeft
< ulRight
)
4479 if (ul64
.QuadPart
> (ULONG64
)*pulHigh
)
4480 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4483 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4487 ul64
.u
.HighPart
= -ul64
.u
.HighPart
;
4489 *pulHigh
= ul64
.u
.HighPart
;
4490 return ul64
.u
.LowPart
;
4493 /* Multiply two unsigned 32 bit values with overflow */
4494 static ULONG
VARIANT_Mul(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4496 ULARGE_INTEGER ul64
;
4498 ul64
.QuadPart
= (ULONG64
)ulLeft
* (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4499 *pulHigh
= ul64
.u
.HighPart
;
4500 return ul64
.u
.LowPart
;
4503 /* Compare two decimals that have the same scale */
4504 static inline int VARIANT_DecCmp(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
)
4506 if ( DEC_HI32(pDecLeft
) < DEC_HI32(pDecRight
) ||
4507 (DEC_HI32(pDecLeft
) <= DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) < DEC_LO64(pDecRight
)))
4509 else if (DEC_HI32(pDecLeft
) == DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) == DEC_LO64(pDecRight
))
4514 /************************************************************************
4515 * VarDecAdd (OLEAUT32.177)
4517 * Add one DECIMAL to another.
4520 * pDecLeft [I] Source
4521 * pDecRight [I] Value to add
4522 * pDecOut [O] Destination
4526 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4528 HRESULT WINAPI
VarDecAdd(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
4533 hRet
= VARIANT_DecScale(&pDecLeft
, &pDecRight
, &scaled
);
4535 if (SUCCEEDED(hRet
))
4537 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4539 BYTE sign
= DECIMAL_POS
;
4541 /* Correct for the sign of the result */
4542 if (DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4544 /* -x + -y : Negative */
4546 goto VarDecAdd_AsPositive
;
4548 else if (DEC_SIGN(pDecLeft
) && !DEC_SIGN(pDecRight
))
4550 int cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4552 /* -x + y : Negative if x > y */
4556 VarDecAdd_AsNegative
:
4557 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4558 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4559 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4563 VarDecAdd_AsInvertedNegative
:
4564 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecRight
), DEC_LO32(pDecLeft
), &overflow
);
4565 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecRight
), DEC_MID32(pDecLeft
), &overflow
);
4566 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecRight
), DEC_HI32(pDecLeft
), &overflow
);
4569 else if (!DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4571 int cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4573 /* x + -y : Negative if x <= y */
4577 goto VarDecAdd_AsInvertedNegative
;
4579 goto VarDecAdd_AsNegative
;
4583 /* x + y : Positive */
4584 VarDecAdd_AsPositive
:
4585 DEC_LO32(pDecOut
) = VARIANT_Add(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4586 DEC_MID32(pDecOut
) = VARIANT_Add(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4587 DEC_HI32(pDecOut
) = VARIANT_Add(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4591 return DISP_E_OVERFLOW
; /* overflowed */
4593 DEC_SCALE(pDecOut
) = DEC_SCALE(pDecLeft
);
4594 DEC_SIGN(pDecOut
) = sign
;
4599 /* internal representation of the value stored in a DECIMAL. The bytes are
4600 stored from LSB at index 0 to MSB at index 11
4602 typedef struct DECIMAL_internal
4604 DWORD bitsnum
[3]; /* 96 significant bits, unsigned */
4605 unsigned char scale
; /* number scaled * 10 ^ -(scale) */
4606 unsigned int sign
: 1; /* 0 - positive, 1 - negative */
4609 /* translate from external DECIMAL format into an internal representation */
4610 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
)
4612 to
->scale
= DEC_SCALE(from
);
4613 to
->sign
= DEC_SIGN(from
) ? 1 : 0;
4615 to
->bitsnum
[0] = DEC_LO32(from
);
4616 to
->bitsnum
[1] = DEC_MID32(from
);
4617 to
->bitsnum
[2] = DEC_HI32(from
);
4620 static void VARIANT_DecFromDI(VARIANT_DI
* from
, DECIMAL
* to
)
4623 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_NEG
, from
->scale
);
4625 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_POS
, from
->scale
);
4628 DEC_LO32(to
) = from
->bitsnum
[0];
4629 DEC_MID32(to
) = from
->bitsnum
[1];
4630 DEC_HI32(to
) = from
->bitsnum
[2];
4633 /* clear an internal representation of a DECIMAL */
4634 static void VARIANT_DI_clear(VARIANT_DI
* i
)
4636 memset(i
, 0, sizeof(VARIANT_DI
));
4639 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4640 size is supported. The value in p is replaced by the quotient of the division, and
4641 the remainder is returned as a result. This routine is most often used with a divisor
4642 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4644 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
)
4649 } else if (divisor
== 1) {
4650 /* dividend remains unchanged */
4653 unsigned char remainder
= 0;
4654 ULONGLONG iTempDividend
;
4657 for (i
= n
- 1; i
>= 0 && !p
[i
]; i
--); /* skip leading zeros */
4658 for (; i
>= 0; i
--) {
4659 iTempDividend
= ((ULONGLONG
)remainder
<< 32) + p
[i
];
4660 remainder
= iTempDividend
% divisor
;
4661 p
[i
] = iTempDividend
/ divisor
;
4668 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4669 static int VARIANT_int_iszero(DWORD
* p
, unsigned int n
)
4671 for (; n
> 0; n
--) if (*p
++ != 0) return 0;
4675 /* multiply two DECIMALS, without changing either one, and place result in third
4676 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4677 digits when scale > 0 in order to fit an overflowing result. Final overflow
4680 static int VARIANT_DI_mul(VARIANT_DI
* a
, VARIANT_DI
* b
, VARIANT_DI
* result
)
4684 signed int mulstart
;
4686 VARIANT_DI_clear(result
);
4687 result
->sign
= (a
->sign
^ b
->sign
) ? 1 : 0;
4689 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4690 of the result is formed by adding the scales of the operands.
4692 result
->scale
= a
->scale
+ b
->scale
;
4693 memset(running
, 0, sizeof(running
));
4695 /* count number of leading zero-bytes in operand A */
4696 for (mulstart
= sizeof(a
->bitsnum
)/sizeof(DWORD
) - 1; mulstart
>= 0 && !a
->bitsnum
[mulstart
]; mulstart
--);
4698 /* result is 0, because operand A is 0 */
4702 unsigned char remainder
= 0;
4705 /* perform actual multiplication */
4706 for (iA
= 0; iA
<= mulstart
; iA
++) {
4710 for (iOverflowMul
= 0, iB
= 0; iB
< sizeof(b
->bitsnum
)/sizeof(DWORD
); iB
++) {
4714 iRV
= VARIANT_Mul(b
->bitsnum
[iB
], a
->bitsnum
[iA
], &iOverflowMul
);
4717 running
[iR
] = VARIANT_Add(running
[iR
], 0, &iRV
);
4723 /* Too bad - native oleaut does not do this, so we should not either */
4725 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4726 This operation should not lose significant digits, and gives an
4727 opportunity to reduce the possibility of overflows in future
4728 operations issued by the application.
4730 while (result
->scale
> 0) {
4731 memcpy(quotient
, running
, sizeof(quotient
));
4732 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4733 if (remainder
> 0) break;
4734 memcpy(running
, quotient
, sizeof(quotient
));
4738 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4739 This operation *will* lose significant digits of the result because
4740 all the factors of 10 were consumed by the previous operation.
4742 while (result
->scale
> 0 && !VARIANT_int_iszero(
4743 running
+ sizeof(result
->bitsnum
) / sizeof(DWORD
),
4744 (sizeof(running
) - sizeof(result
->bitsnum
)) / sizeof(DWORD
))) {
4746 remainder
= VARIANT_int_divbychar(running
, sizeof(running
) / sizeof(DWORD
), 10);
4747 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4751 /* round up the result - native oleaut32 does this */
4752 if (remainder
>= 5) {
4754 for (remainder
= 1, i
= 0; i
< sizeof(running
)/sizeof(DWORD
) && remainder
; i
++) {
4755 ULONGLONG digit
= running
[i
] + 1;
4756 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4757 running
[i
] = digit
& 0xFFFFFFFF;
4761 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4762 and copy result bits into result structure
4764 r_overflow
= !VARIANT_int_iszero(
4765 running
+ sizeof(result
->bitsnum
)/sizeof(DWORD
),
4766 (sizeof(running
) - sizeof(result
->bitsnum
))/sizeof(DWORD
));
4767 memcpy(result
->bitsnum
, running
, sizeof(result
->bitsnum
));
4772 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4773 hardcoded (period for decimal separator, dash as negative sign). Returns 0 for
4774 success, nonzero if insufficient space in output buffer.
4776 static int VARIANT_DI_tostringW(VARIANT_DI
* a
, WCHAR
* s
, unsigned int n
)
4780 unsigned char remainder
;
4783 /* place negative sign */
4784 if (!VARIANT_int_iszero(a
->bitsnum
, sizeof(a
->bitsnum
) / sizeof(DWORD
)) && a
->sign
) {
4792 /* prepare initial 0 */
4797 } else overflow
= 1;
4801 memcpy(quotient
, a
->bitsnum
, sizeof(a
->bitsnum
));
4802 while (!overflow
&& !VARIANT_int_iszero(quotient
, sizeof(quotient
) / sizeof(DWORD
))) {
4803 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4807 s
[i
++] = '0' + remainder
;
4812 if (!overflow
&& !VARIANT_int_iszero(a
->bitsnum
, sizeof(a
->bitsnum
) / sizeof(DWORD
))) {
4814 /* reverse order of digits */
4815 WCHAR
* x
= s
; WCHAR
* y
= s
+ i
- 1;
4822 /* check for decimal point. "i" now has string length */
4823 if (i
<= a
->scale
) {
4824 unsigned int numzeroes
= a
->scale
+ 1 - i
;
4825 if (i
+ 1 + numzeroes
>= n
) {
4828 memmove(s
+ numzeroes
, s
, (i
+ 1) * sizeof(WCHAR
));
4830 while (numzeroes
> 0) {
4831 s
[--numzeroes
] = '0';
4836 /* place decimal point */
4838 unsigned int periodpos
= i
- a
->scale
;
4842 memmove(s
+ periodpos
+ 1, s
+ periodpos
, (i
+ 1 - periodpos
) * sizeof(WCHAR
));
4843 s
[periodpos
] = '.'; i
++;
4845 /* remove extra zeros at the end, if any */
4846 while (s
[i
- 1] == '0') s
[--i
] = '\0';
4847 if (s
[i
- 1] == '.') s
[--i
] = '\0';
4855 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4856 static void VARIANT_int_shiftleft(DWORD
* p
, unsigned int n
, unsigned int shift
)
4861 /* shift whole DWORDs to the left */
4864 memmove(p
+ 1, p
, (n
- 1) * sizeof(DWORD
));
4865 *p
= 0; shift
-= 32;
4868 /* shift remainder (1..31 bits) */
4870 if (shift
> 0) for (i
= 0; i
< n
; i
++)
4873 b
= p
[i
] >> (32 - shift
);
4874 p
[i
] = (p
[i
] << shift
) | shifted
;
4879 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4880 Value at v is incremented by the value at p. Any size is supported, provided
4881 that v is not shorter than p. Any unapplied carry is returned as a result.
4883 static unsigned char VARIANT_int_add(DWORD
* v
, unsigned int nv
, DWORD
* p
,
4886 unsigned char carry
= 0;
4892 for (i
= 0; i
< np
; i
++) {
4893 sum
= (ULONGLONG
)v
[i
]
4896 v
[i
] = sum
& 0xffffffff;
4899 for (; i
< nv
&& carry
; i
++) {
4900 sum
= (ULONGLONG
)v
[i
]
4902 v
[i
] = sum
& 0xffffffff;
4909 /* perform integral division with operand p as dividend. Parameter n indicates
4910 number of available DWORDs in divisor p, but available space in p must be
4911 actually at least 2 * n DWORDs, because the remainder of the integral
4912 division is built in the next n DWORDs past the start of the quotient. This
4913 routine replaces the dividend in p with the quotient, and appends n
4914 additional DWORDs for the remainder.
4916 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4917 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4918 source code to the VLI (Very Large Integer) division operator. This algorithm
4919 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4920 variably-scaled integers such as the MS DECIMAL representation.
4922 static void VARIANT_int_div(DWORD
* p
, unsigned int n
, DWORD
* divisor
,
4927 DWORD
* negdivisor
= tempsub
+ n
;
4929 /* build 2s-complement of divisor */
4930 for (i
= 0; i
< n
; i
++) negdivisor
[i
] = (i
< dn
) ? ~divisor
[i
] : 0xFFFFFFFF;
4932 VARIANT_int_add(negdivisor
, n
, p
+ n
, 1);
4933 memset(p
+ n
, 0, n
* sizeof(DWORD
));
4935 /* skip all leading zero DWORDs in quotient */
4936 for (i
= 0; i
< n
&& !p
[n
- 1]; i
++) VARIANT_int_shiftleft(p
, n
, 32);
4937 /* i is now number of DWORDs left to process */
4938 for (i
<<= 5; i
< (n
<< 5); i
++) {
4939 VARIANT_int_shiftleft(p
, n
<< 1, 1); /* shl quotient+remainder */
4941 /* trial subtraction */
4942 memcpy(tempsub
, p
+ n
, n
* sizeof(DWORD
));
4943 VARIANT_int_add(tempsub
, n
, negdivisor
, n
);
4945 /* check whether result of subtraction was negative */
4946 if ((tempsub
[n
- 1] & 0x80000000) == 0) {
4947 memcpy(p
+ n
, tempsub
, n
* sizeof(DWORD
));
4953 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4954 static unsigned char VARIANT_int_mulbychar(DWORD
* p
, unsigned int n
, unsigned char m
)
4959 for (iOverflowMul
= 0, i
= 0; i
< n
; i
++)
4960 p
[i
] = VARIANT_Mul(p
[i
], m
, &iOverflowMul
);
4961 return (unsigned char)iOverflowMul
;
4964 /* increment value in A by the value indicated in B, with scale adjusting.
4965 Modifies parameters by adjusting scales. Returns 0 if addition was
4966 successful, nonzero if a parameter underflowed before it could be
4967 successfully used in the addition.
4969 static int VARIANT_int_addlossy(
4970 DWORD
* a
, int * ascale
, unsigned int an
,
4971 DWORD
* b
, int * bscale
, unsigned int bn
)
4975 if (VARIANT_int_iszero(a
, an
)) {
4976 /* if A is zero, copy B into A, after removing digits */
4977 while (bn
> an
&& !VARIANT_int_iszero(b
+ an
, bn
- an
)) {
4978 VARIANT_int_divbychar(b
, bn
, 10);
4981 memcpy(a
, b
, an
* sizeof(DWORD
));
4983 } else if (!VARIANT_int_iszero(b
, bn
)) {
4984 unsigned int tn
= an
+ 1;
4987 if (bn
+ 1 > tn
) tn
= bn
+ 1;
4988 if (*ascale
!= *bscale
) {
4989 /* first (optimistic) try - try to scale down the one with the bigger
4990 scale, while this number is divisible by 10 */
4991 DWORD
* digitchosen
;
4992 unsigned int nchosen
;
4996 if (*ascale
< *bscale
) {
4997 targetscale
= *ascale
;
4998 scalechosen
= bscale
;
5002 targetscale
= *bscale
;
5003 scalechosen
= ascale
;
5007 memset(t
, 0, tn
* sizeof(DWORD
));
5008 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5010 /* divide by 10 until target scale is reached */
5011 while (*scalechosen
> targetscale
) {
5012 unsigned char remainder
= VARIANT_int_divbychar(t
, tn
, 10);
5015 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5020 if (*ascale
!= *bscale
) {
5021 DWORD
* digitchosen
;
5022 unsigned int nchosen
;
5026 /* try to scale up the one with the smaller scale */
5027 if (*ascale
> *bscale
) {
5028 targetscale
= *ascale
;
5029 scalechosen
= bscale
;
5033 targetscale
= *bscale
;
5034 scalechosen
= ascale
;
5038 memset(t
, 0, tn
* sizeof(DWORD
));
5039 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5041 /* multiply by 10 until target scale is reached, or
5042 significant bytes overflow the number
5044 while (*scalechosen
< targetscale
&& t
[nchosen
] == 0) {
5045 VARIANT_int_mulbychar(t
, tn
, 10);
5046 if (t
[nchosen
] == 0) {
5047 /* still does not overflow */
5049 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5054 if (*ascale
!= *bscale
) {
5055 /* still different? try to scale down the one with the bigger scale
5056 (this *will* lose significant digits) */
5057 DWORD
* digitchosen
;
5058 unsigned int nchosen
;
5062 if (*ascale
< *bscale
) {
5063 targetscale
= *ascale
;
5064 scalechosen
= bscale
;
5068 targetscale
= *bscale
;
5069 scalechosen
= ascale
;
5073 memset(t
, 0, tn
* sizeof(DWORD
));
5074 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5076 /* divide by 10 until target scale is reached */
5077 while (*scalechosen
> targetscale
) {
5078 VARIANT_int_divbychar(t
, tn
, 10);
5080 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5084 /* check whether any of the operands still has significant digits
5087 if (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
)) {
5090 /* at this step, both numbers have the same scale and can be added
5091 as integers. However, the result might not fit in A, so further
5092 scaling down might be necessary.
5094 while (!underflow
) {
5095 memset(t
, 0, tn
* sizeof(DWORD
));
5096 memcpy(t
, a
, an
* sizeof(DWORD
));
5098 VARIANT_int_add(t
, tn
, b
, bn
);
5099 if (VARIANT_int_iszero(t
+ an
, tn
- an
)) {
5100 /* addition was successful */
5101 memcpy(a
, t
, an
* sizeof(DWORD
));
5104 /* addition overflowed - remove significant digits
5105 from both operands and try again */
5106 VARIANT_int_divbychar(a
, an
, 10); (*ascale
)--;
5107 VARIANT_int_divbychar(b
, bn
, 10); (*bscale
)--;
5108 /* check whether any operand keeps significant digits after
5109 scaledown (underflow case 2)
5111 underflow
= (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
));
5119 /* perform complete DECIMAL division in the internal representation. Returns
5120 0 if the division was completed (even if quotient is set to 0), or nonzero
5121 in case of quotient overflow.
5123 static HRESULT
VARIANT_DI_div(VARIANT_DI
* dividend
, VARIANT_DI
* divisor
, VARIANT_DI
* quotient
)
5125 HRESULT r_overflow
= S_OK
;
5127 if (VARIANT_int_iszero(divisor
->bitsnum
, sizeof(divisor
->bitsnum
)/sizeof(DWORD
))) {
5129 r_overflow
= DISP_E_DIVBYZERO
;
5130 } else if (VARIANT_int_iszero(dividend
->bitsnum
, sizeof(dividend
->bitsnum
)/sizeof(DWORD
))) {
5131 VARIANT_DI_clear(quotient
);
5133 int quotientscale
, remainderscale
, tempquotientscale
;
5134 DWORD remainderplusquotient
[8];
5137 quotientscale
= remainderscale
= (int)dividend
->scale
- (int)divisor
->scale
;
5138 tempquotientscale
= quotientscale
;
5139 VARIANT_DI_clear(quotient
);
5140 quotient
->sign
= (dividend
->sign
^ divisor
->sign
) ? 1 : 0;
5142 /* The following strategy is used for division
5143 1) if there was a nonzero remainder from previous iteration, use it as
5144 dividend for this iteration, else (for first iteration) use intended
5146 2) perform integer division in temporary buffer, develop quotient in
5147 low-order part, remainder in high-order part
5148 3) add quotient from step 2 to final result, with possible loss of
5150 4) multiply integer part of remainder by 10, while incrementing the
5151 scale of the remainder. This operation preserves the intended value
5153 5) loop to step 1 until one of the following is true:
5154 a) remainder is zero (exact division achieved)
5155 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5157 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5158 memcpy(remainderplusquotient
, dividend
->bitsnum
, sizeof(dividend
->bitsnum
));
5161 remainderplusquotient
, 4,
5162 divisor
->bitsnum
, sizeof(divisor
->bitsnum
)/sizeof(DWORD
));
5163 underflow
= VARIANT_int_addlossy(
5164 quotient
->bitsnum
, "ientscale
, sizeof(quotient
->bitsnum
) / sizeof(DWORD
),
5165 remainderplusquotient
, &tempquotientscale
, 4);
5166 VARIANT_int_mulbychar(remainderplusquotient
+ 4, 4, 10);
5167 memcpy(remainderplusquotient
, remainderplusquotient
+ 4, 4 * sizeof(DWORD
));
5168 tempquotientscale
= ++remainderscale
;
5169 } while (!underflow
&& !VARIANT_int_iszero(remainderplusquotient
+ 4, 4));
5171 /* quotient scale might now be negative (extremely big number). If, so, try
5172 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5173 until scale is 0. If this cannot be done, it is a real overflow.
5175 while (!r_overflow
&& quotientscale
< 0) {
5176 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5177 memcpy(remainderplusquotient
, quotient
->bitsnum
, sizeof(quotient
->bitsnum
));
5178 VARIANT_int_mulbychar(remainderplusquotient
, sizeof(remainderplusquotient
)/sizeof(DWORD
), 10);
5179 if (VARIANT_int_iszero(remainderplusquotient
+ sizeof(quotient
->bitsnum
)/sizeof(DWORD
),
5180 (sizeof(remainderplusquotient
) - sizeof(quotient
->bitsnum
))/sizeof(DWORD
))) {
5182 memcpy(quotient
->bitsnum
, remainderplusquotient
, sizeof(quotient
->bitsnum
));
5183 } else r_overflow
= DISP_E_OVERFLOW
;
5186 if (quotientscale
<= 255) quotient
->scale
= quotientscale
;
5187 else VARIANT_DI_clear(quotient
);
5193 /************************************************************************
5194 * VarDecDiv (OLEAUT32.178)
5196 * Divide one DECIMAL by another.
5199 * pDecLeft [I] Source
5200 * pDecRight [I] Value to divide by
5201 * pDecOut [O] Destination
5205 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5207 HRESULT WINAPI
VarDecDiv(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5209 HRESULT hRet
= S_OK
;
5210 VARIANT_DI di_left
, di_right
, di_result
;
5213 if (!pDecLeft
|| !pDecRight
|| !pDecOut
) return E_INVALIDARG
;
5215 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5216 VARIANT_DIFromDec(pDecRight
, &di_right
);
5217 divresult
= VARIANT_DI_div(&di_left
, &di_right
, &di_result
);
5220 /* division actually overflowed */
5227 if (di_result
.scale
> DEC_MAX_SCALE
)
5229 unsigned char remainder
= 0;
5231 /* division underflowed. In order to comply with the MSDN
5232 specifications for DECIMAL ranges, some significant digits
5235 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5237 while (di_result
.scale
> DEC_MAX_SCALE
&&
5238 !VARIANT_int_iszero(di_result
.bitsnum
, sizeof(di_result
.bitsnum
) / sizeof(DWORD
)))
5240 remainder
= VARIANT_int_divbychar(di_result
.bitsnum
, sizeof(di_result
.bitsnum
) / sizeof(DWORD
), 10);
5243 if (di_result
.scale
> DEC_MAX_SCALE
)
5245 WARN("result underflowed, setting to 0\n");
5246 di_result
.scale
= 0;
5249 else if (remainder
>= 5) /* round up result - native oleaut32 does this */
5252 for (remainder
= 1, i
= 0; i
< sizeof(di_result
.bitsnum
) / sizeof(DWORD
) && remainder
; i
++) {
5253 ULONGLONG digit
= di_result
.bitsnum
[i
] + 1;
5254 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5255 di_result
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
5259 VARIANT_DecFromDI(&di_result
, pDecOut
);
5264 /************************************************************************
5265 * VarDecMul (OLEAUT32.179)
5267 * Multiply one DECIMAL by another.
5270 * pDecLeft [I] Source
5271 * pDecRight [I] Value to multiply by
5272 * pDecOut [O] Destination
5276 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5278 HRESULT WINAPI
VarDecMul(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5280 HRESULT hRet
= S_OK
;
5281 VARIANT_DI di_left
, di_right
, di_result
;
5284 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5285 VARIANT_DIFromDec(pDecRight
, &di_right
);
5286 mulresult
= VARIANT_DI_mul(&di_left
, &di_right
, &di_result
);
5289 /* multiplication actually overflowed */
5290 hRet
= DISP_E_OVERFLOW
;
5294 if (di_result
.scale
> DEC_MAX_SCALE
)
5296 /* multiplication underflowed. In order to comply with the MSDN
5297 specifications for DECIMAL ranges, some significant digits
5300 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5302 while (di_result
.scale
> DEC_MAX_SCALE
&&
5303 !VARIANT_int_iszero(di_result
.bitsnum
, sizeof(di_result
.bitsnum
)/sizeof(DWORD
)))
5305 VARIANT_int_divbychar(di_result
.bitsnum
, sizeof(di_result
.bitsnum
)/sizeof(DWORD
), 10);
5308 if (di_result
.scale
> DEC_MAX_SCALE
)
5310 WARN("result underflowed, setting to 0\n");
5311 di_result
.scale
= 0;
5315 VARIANT_DecFromDI(&di_result
, pDecOut
);
5320 /************************************************************************
5321 * VarDecSub (OLEAUT32.181)
5323 * Subtract one DECIMAL from another.
5326 * pDecLeft [I] Source
5327 * pDecRight [I] DECIMAL to subtract from pDecLeft
5328 * pDecOut [O] Destination
5331 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5333 HRESULT WINAPI
VarDecSub(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5337 /* Implement as addition of the negative */
5338 VarDecNeg(pDecRight
, &decRight
);
5339 return VarDecAdd(pDecLeft
, &decRight
, pDecOut
);
5342 /************************************************************************
5343 * VarDecAbs (OLEAUT32.182)
5345 * Convert a DECIMAL into its absolute value.
5349 * pDecOut [O] Destination
5352 * S_OK. This function does not fail.
5354 HRESULT WINAPI
VarDecAbs(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5357 DEC_SIGN(pDecOut
) &= ~DECIMAL_NEG
;
5361 /************************************************************************
5362 * VarDecFix (OLEAUT32.187)
5364 * Return the integer portion of a DECIMAL.
5368 * pDecOut [O] Destination
5372 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5375 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5376 * negative numbers away from 0, while this function rounds them towards zero.
5378 HRESULT WINAPI
VarDecFix(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5380 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5381 return E_INVALIDARG
;
5383 if (!DEC_SCALE(pDecIn
))
5385 *pDecOut
= *pDecIn
; /* Already an integer */
5389 FIXME("semi-stub!\n");
5390 return DISP_E_OVERFLOW
;
5393 /************************************************************************
5394 * VarDecInt (OLEAUT32.188)
5396 * Return the integer portion of a DECIMAL.
5400 * pDecOut [O] Destination
5404 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5407 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5408 * negative numbers towards 0, while this function rounds them away from zero.
5410 HRESULT WINAPI
VarDecInt(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5412 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5413 return E_INVALIDARG
;
5415 if (!(DEC_SIGN(pDecIn
) & DECIMAL_NEG
) || !DEC_SCALE(pDecIn
))
5416 return VarDecFix(pDecIn
, pDecOut
); /* The same, if +ve or no fractionals */
5418 FIXME("semi-stub!\n");
5419 return DISP_E_OVERFLOW
;
5422 /************************************************************************
5423 * VarDecNeg (OLEAUT32.189)
5425 * Change the sign of a DECIMAL.
5429 * pDecOut [O] Destination
5432 * S_OK. This function does not fail.
5434 HRESULT WINAPI
VarDecNeg(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5437 DEC_SIGN(pDecOut
) ^= DECIMAL_NEG
;
5441 /************************************************************************
5442 * VarDecRound (OLEAUT32.203)
5444 * Change the precision of a DECIMAL.
5448 * cDecimals [I] New number of decimals to keep
5449 * pDecOut [O] Destination
5452 * Success: S_OK. pDecOut contains the rounded value.
5453 * Failure: E_INVALIDARG if any argument is invalid.
5455 HRESULT WINAPI
VarDecRound(const DECIMAL
* pDecIn
, int cDecimals
, DECIMAL
* pDecOut
)
5457 if (cDecimals
< 0 || (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
) || DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
)
5458 return E_INVALIDARG
;
5460 if (cDecimals
>= DEC_SCALE(pDecIn
))
5462 *pDecOut
= *pDecIn
; /* More precision than we have */
5466 FIXME("semi-stub!\n");
5468 return DISP_E_OVERFLOW
;
5471 /************************************************************************
5472 * VarDecCmp (OLEAUT32.204)
5474 * Compare two DECIMAL values.
5477 * pDecLeft [I] Source
5478 * pDecRight [I] Value to compare
5481 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5482 * is less than, equal to or greater than pDecRight respectively.
5483 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5485 HRESULT WINAPI
VarDecCmp(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
)
5490 /* Subtract right from left, and compare the result to 0 */
5491 hRet
= VarDecSub(pDecLeft
, pDecRight
, &result
);
5493 if (SUCCEEDED(hRet
))
5495 int non_zero
= DEC_HI32(&result
) | DEC_MID32(&result
) | DEC_LO32(&result
);
5497 if ((DEC_SIGN(&result
) & DECIMAL_NEG
) && non_zero
)
5498 hRet
= (HRESULT
)VARCMP_LT
;
5500 hRet
= (HRESULT
)VARCMP_GT
;
5502 hRet
= (HRESULT
)VARCMP_EQ
;
5507 /************************************************************************
5508 * VarDecCmpR8 (OLEAUT32.298)
5510 * Compare a DECIMAL to a double
5513 * pDecLeft [I] DECIMAL Source
5514 * dblRight [I] double to compare to pDecLeft
5517 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5518 * is less than, equal to or greater than pDecLeft respectively.
5519 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5521 HRESULT WINAPI
VarDecCmpR8(const DECIMAL
* pDecLeft
, double dblRight
)
5526 hRet
= VarDecFromR8(dblRight
, &decRight
);
5528 if (SUCCEEDED(hRet
))
5529 hRet
= VarDecCmp(pDecLeft
, &decRight
);
5537 /************************************************************************
5538 * VarBoolFromUI1 (OLEAUT32.118)
5540 * Convert a VT_UI1 to a VT_BOOL.
5544 * pBoolOut [O] Destination
5549 HRESULT WINAPI
VarBoolFromUI1(BYTE bIn
, VARIANT_BOOL
*pBoolOut
)
5551 *pBoolOut
= bIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5555 /************************************************************************
5556 * VarBoolFromI2 (OLEAUT32.119)
5558 * Convert a VT_I2 to a VT_BOOL.
5562 * pBoolOut [O] Destination
5567 HRESULT WINAPI
VarBoolFromI2(SHORT sIn
, VARIANT_BOOL
*pBoolOut
)
5569 *pBoolOut
= sIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5573 /************************************************************************
5574 * VarBoolFromI4 (OLEAUT32.120)
5576 * Convert a VT_I4 to a VT_BOOL.
5580 * pBoolOut [O] Destination
5585 HRESULT WINAPI
VarBoolFromI4(LONG lIn
, VARIANT_BOOL
*pBoolOut
)
5587 *pBoolOut
= lIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5591 /************************************************************************
5592 * VarBoolFromR4 (OLEAUT32.121)
5594 * Convert a VT_R4 to a VT_BOOL.
5598 * pBoolOut [O] Destination
5603 HRESULT WINAPI
VarBoolFromR4(FLOAT fltIn
, VARIANT_BOOL
*pBoolOut
)
5605 *pBoolOut
= fltIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5609 /************************************************************************
5610 * VarBoolFromR8 (OLEAUT32.122)
5612 * Convert a VT_R8 to a VT_BOOL.
5616 * pBoolOut [O] Destination
5621 HRESULT WINAPI
VarBoolFromR8(double dblIn
, VARIANT_BOOL
*pBoolOut
)
5623 *pBoolOut
= dblIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5627 /************************************************************************
5628 * VarBoolFromDate (OLEAUT32.123)
5630 * Convert a VT_DATE to a VT_BOOL.
5634 * pBoolOut [O] Destination
5639 HRESULT WINAPI
VarBoolFromDate(DATE dateIn
, VARIANT_BOOL
*pBoolOut
)
5641 *pBoolOut
= dateIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5645 /************************************************************************
5646 * VarBoolFromCy (OLEAUT32.124)
5648 * Convert a VT_CY to a VT_BOOL.
5652 * pBoolOut [O] Destination
5657 HRESULT WINAPI
VarBoolFromCy(CY cyIn
, VARIANT_BOOL
*pBoolOut
)
5659 *pBoolOut
= cyIn
.int64
? VARIANT_TRUE
: VARIANT_FALSE
;
5663 static BOOL
VARIANT_GetLocalisedText(LANGID langId
, DWORD dwId
, WCHAR
*lpszDest
)
5667 hrsrc
= FindResourceExW( OLEAUT32_hModule
, (LPWSTR
)RT_STRING
,
5668 MAKEINTRESOURCEW((dwId
>> 4) + 1), langId
);
5671 HGLOBAL hmem
= LoadResource( OLEAUT32_hModule
, hrsrc
);
5678 p
= LockResource( hmem
);
5679 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
5681 memcpy( lpszDest
, p
+ 1, *p
* sizeof(WCHAR
) );
5682 lpszDest
[*p
] = '\0';
5683 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest
), langId
);
5690 /************************************************************************
5691 * VarBoolFromStr (OLEAUT32.125)
5693 * Convert a VT_BSTR to a VT_BOOL.
5697 * lcid [I] LCID for the conversion
5698 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5699 * pBoolOut [O] Destination
5703 * Failure: E_INVALIDARG, if pBoolOut is invalid.
5704 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5707 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
5708 * it may contain (in any case mapping) the text "true" or "false".
5709 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
5710 * localised text of "True" or "False" in the language specified by lcid.
5711 * - If none of these matches occur, the string is treated as a numeric string
5712 * and the boolean pBoolOut will be set according to whether the number is zero
5713 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
5714 * - If the text is not numeric and does not match any of the above, then
5715 * DISP_E_TYPEMISMATCH is returned.
5717 HRESULT WINAPI
VarBoolFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, VARIANT_BOOL
*pBoolOut
)
5719 /* Any VB/VBA programmers out there should recognise these strings... */
5720 static const WCHAR szFalse
[] = { '#','F','A','L','S','E','#','\0' };
5721 static const WCHAR szTrue
[] = { '#','T','R','U','E','#','\0' };
5723 LANGID langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
5724 HRESULT hRes
= S_OK
;
5726 if (!strIn
|| !pBoolOut
)
5727 return DISP_E_TYPEMISMATCH
;
5729 /* Check if we should be comparing against localised text */
5730 if (dwFlags
& VAR_LOCALBOOL
)
5732 /* Convert our LCID into a usable value */
5733 lcid
= ConvertDefaultLocale(lcid
);
5735 langId
= LANGIDFROMLCID(lcid
);
5737 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
5738 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
5740 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
5741 * I don't think this is needed unless any of the localised text strings
5742 * contain characters that can be so mapped. In the event that this is
5743 * true for a given language (possibly some Asian languages), then strIn
5744 * should be mapped here _only_ if langId is an Id for which this can occur.
5748 /* Note that if we are not comparing against localised strings, langId
5749 * will have its default value of LANG_ENGLISH. This allows us to mimic
5750 * the native behaviour of always checking against English strings even
5751 * after we've checked for localised ones.
5753 VarBoolFromStr_CheckLocalised
:
5754 if (VARIANT_GetLocalisedText(langId
, IDS_TRUE
, szBuff
))
5756 /* Compare against localised strings, ignoring case */
5757 if (!strcmpiW(strIn
, szBuff
))
5759 *pBoolOut
= VARIANT_TRUE
; /* Matched localised 'true' text */
5762 VARIANT_GetLocalisedText(langId
, IDS_FALSE
, szBuff
);
5763 if (!strcmpiW(strIn
, szBuff
))
5765 *pBoolOut
= VARIANT_FALSE
; /* Matched localised 'false' text */
5770 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
5772 /* We have checked the localised text, now check English */
5773 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
5774 goto VarBoolFromStr_CheckLocalised
;
5777 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
5778 if (!strcmpW(strIn
, szFalse
))
5779 *pBoolOut
= VARIANT_FALSE
;
5780 else if (!strcmpW(strIn
, szTrue
))
5781 *pBoolOut
= VARIANT_TRUE
;
5786 /* If this string is a number, convert it as one */
5787 hRes
= VarR8FromStr(strIn
, lcid
, dwFlags
, &d
);
5788 if (SUCCEEDED(hRes
)) *pBoolOut
= d
? VARIANT_TRUE
: VARIANT_FALSE
;
5793 /************************************************************************
5794 * VarBoolFromDisp (OLEAUT32.126)
5796 * Convert a VT_DISPATCH to a VT_BOOL.
5799 * pdispIn [I] Source
5800 * lcid [I] LCID for conversion
5801 * pBoolOut [O] Destination
5805 * Failure: E_INVALIDARG, if the source value is invalid
5806 * DISP_E_OVERFLOW, if the value will not fit in the destination
5807 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5809 HRESULT WINAPI
VarBoolFromDisp(IDispatch
* pdispIn
, LCID lcid
, VARIANT_BOOL
*pBoolOut
)
5811 return VARIANT_FromDisp(pdispIn
, lcid
, pBoolOut
, VT_BOOL
, 0);
5814 /************************************************************************
5815 * VarBoolFromI1 (OLEAUT32.233)
5817 * Convert a VT_I1 to a VT_BOOL.
5821 * pBoolOut [O] Destination
5826 HRESULT WINAPI
VarBoolFromI1(signed char cIn
, VARIANT_BOOL
*pBoolOut
)
5828 *pBoolOut
= cIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5832 /************************************************************************
5833 * VarBoolFromUI2 (OLEAUT32.234)
5835 * Convert a VT_UI2 to a VT_BOOL.
5839 * pBoolOut [O] Destination
5844 HRESULT WINAPI
VarBoolFromUI2(USHORT usIn
, VARIANT_BOOL
*pBoolOut
)
5846 *pBoolOut
= usIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5850 /************************************************************************
5851 * VarBoolFromUI4 (OLEAUT32.235)
5853 * Convert a VT_UI4 to a VT_BOOL.
5857 * pBoolOut [O] Destination
5862 HRESULT WINAPI
VarBoolFromUI4(ULONG ulIn
, VARIANT_BOOL
*pBoolOut
)
5864 *pBoolOut
= ulIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5868 /************************************************************************
5869 * VarBoolFromDec (OLEAUT32.236)
5871 * Convert a VT_DECIMAL to a VT_BOOL.
5875 * pBoolOut [O] Destination
5879 * Failure: E_INVALIDARG, if pDecIn is invalid.
5881 HRESULT WINAPI
VarBoolFromDec(DECIMAL
* pDecIn
, VARIANT_BOOL
*pBoolOut
)
5883 if (DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
|| (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
))
5884 return E_INVALIDARG
;
5886 if (DEC_HI32(pDecIn
) || DEC_MID32(pDecIn
) || DEC_LO32(pDecIn
))
5887 *pBoolOut
= VARIANT_TRUE
;
5889 *pBoolOut
= VARIANT_FALSE
;
5893 /************************************************************************
5894 * VarBoolFromI8 (OLEAUT32.370)
5896 * Convert a VT_I8 to a VT_BOOL.
5900 * pBoolOut [O] Destination
5905 HRESULT WINAPI
VarBoolFromI8(LONG64 llIn
, VARIANT_BOOL
*pBoolOut
)
5907 *pBoolOut
= llIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5911 /************************************************************************
5912 * VarBoolFromUI8 (OLEAUT32.371)
5914 * Convert a VT_UI8 to a VT_BOOL.
5918 * pBoolOut [O] Destination
5923 HRESULT WINAPI
VarBoolFromUI8(ULONG64 ullIn
, VARIANT_BOOL
*pBoolOut
)
5925 *pBoolOut
= ullIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5932 /* Write a number from a UI8 and sign */
5933 static WCHAR
*VARIANT_WriteNumber(ULONG64 ulVal
, WCHAR
* szOut
)
5937 WCHAR ulNextDigit
= ulVal
% 10;
5939 *szOut
-- = '0' + ulNextDigit
;
5940 ulVal
= (ulVal
- ulNextDigit
) / 10;
5947 /* Create a (possibly localised) BSTR from a UI8 and sign */
5948 static BSTR
VARIANT_MakeBstr(LCID lcid
, DWORD dwFlags
, WCHAR
*szOut
)
5950 WCHAR szConverted
[256];
5952 if (dwFlags
& VAR_NEGATIVE
)
5955 if (dwFlags
& LOCALE_USE_NLS
)
5957 /* Format the number for the locale */
5958 szConverted
[0] = '\0';
5959 GetNumberFormatW(lcid
,
5960 dwFlags
& LOCALE_NOUSEROVERRIDE
,
5961 szOut
, NULL
, szConverted
, sizeof(szConverted
)/sizeof(WCHAR
));
5962 szOut
= szConverted
;
5964 return SysAllocStringByteLen((LPCSTR
)szOut
, strlenW(szOut
) * sizeof(WCHAR
));
5967 /* Create a (possibly localised) BSTR from a UI8 and sign */
5968 static HRESULT
VARIANT_BstrFromUInt(ULONG64 ulVal
, LCID lcid
, DWORD dwFlags
, BSTR
*pbstrOut
)
5970 WCHAR szBuff
[64], *szOut
= szBuff
+ sizeof(szBuff
)/sizeof(WCHAR
) - 1;
5973 return E_INVALIDARG
;
5975 /* Create the basic number string */
5977 szOut
= VARIANT_WriteNumber(ulVal
, szOut
);
5979 *pbstrOut
= VARIANT_MakeBstr(lcid
, dwFlags
, szOut
);
5980 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
5981 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
5984 /******************************************************************************
5985 * VarBstrFromUI1 (OLEAUT32.108)
5987 * Convert a VT_UI1 to a VT_BSTR.
5991 * lcid [I] LCID for the conversion
5992 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5993 * pbstrOut [O] Destination
5997 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5998 * E_OUTOFMEMORY, if memory allocation fails.
6000 HRESULT WINAPI
VarBstrFromUI1(BYTE bIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6002 return VARIANT_BstrFromUInt(bIn
, lcid
, dwFlags
, pbstrOut
);
6005 /******************************************************************************
6006 * VarBstrFromI2 (OLEAUT32.109)
6008 * Convert a VT_I2 to a VT_BSTR.
6012 * lcid [I] LCID for the conversion
6013 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6014 * pbstrOut [O] Destination
6018 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6019 * E_OUTOFMEMORY, if memory allocation fails.
6021 HRESULT WINAPI
VarBstrFromI2(short sIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6028 dwFlags
|= VAR_NEGATIVE
;
6030 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6033 /******************************************************************************
6034 * VarBstrFromI4 (OLEAUT32.110)
6036 * Convert a VT_I4 to a VT_BSTR.
6040 * lcid [I] LCID for the conversion
6041 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6042 * pbstrOut [O] Destination
6046 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6047 * E_OUTOFMEMORY, if memory allocation fails.
6049 HRESULT WINAPI
VarBstrFromI4(LONG lIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6056 dwFlags
|= VAR_NEGATIVE
;
6058 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6061 static BSTR
VARIANT_BstrReplaceDecimal(WCHAR
* buff
, LCID lcid
, ULONG dwFlags
)
6064 WCHAR lpDecimalSep
[16];
6066 /* Native oleaut32 uses the locale-specific decimal separator even in the
6067 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6068 American locales will see "one thousand and one tenth" as "1000,1"
6069 instead of "1000.1" (notice the comma). The following code checks for
6070 the need to replace the decimal separator, and if so, will prepare an
6071 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6073 GetLocaleInfoW(lcid
, LOCALE_SDECIMAL
, lpDecimalSep
, sizeof(lpDecimalSep
) / sizeof(WCHAR
));
6074 if (lpDecimalSep
[0] == '.' && lpDecimalSep
[1] == '\0')
6076 /* locale is compatible with English - return original string */
6077 bstrOut
= SysAllocString(buff
);
6083 WCHAR empty
[1] = {'\0'};
6084 NUMBERFMTW minFormat
;
6086 minFormat
.NumDigits
= 0;
6087 minFormat
.LeadingZero
= 0;
6088 minFormat
.Grouping
= 0;
6089 minFormat
.lpDecimalSep
= lpDecimalSep
;
6090 minFormat
.lpThousandSep
= empty
;
6091 minFormat
.NegativeOrder
= 1; /* NLS_NEG_LEFT */
6093 /* count number of decimal digits in string */
6094 p
= strchrW( buff
, '.' );
6095 if (p
) minFormat
.NumDigits
= strlenW(p
+ 1);
6098 if (!GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6099 buff
, &minFormat
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
)))
6101 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6102 bstrOut
= SysAllocString(buff
);
6106 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff
));
6107 bstrOut
= SysAllocString(numbuff
);
6113 static HRESULT
VARIANT_BstrFromReal(DOUBLE dblIn
, LCID lcid
, ULONG dwFlags
,
6114 BSTR
* pbstrOut
, LPCWSTR lpszFormat
)
6119 return E_INVALIDARG
;
6121 sprintfW( buff
, lpszFormat
, dblIn
);
6123 /* Negative zeroes are disallowed (some applications depend on this).
6124 If buff starts with a minus, and then nothing follows but zeroes
6125 and/or a period, it is a negative zero and is replaced with a
6126 canonical zero. This duplicates native oleaut32 behavior.
6130 const WCHAR szAccept
[] = {'0', '.', '\0'};
6131 if (strlenW(buff
+ 1) == strspnW(buff
+ 1, szAccept
))
6132 { buff
[0] = '0'; buff
[1] = '\0'; }
6135 TRACE("created string %s\n", debugstr_w(buff
));
6136 if (dwFlags
& LOCALE_USE_NLS
)
6140 /* Format the number for the locale */
6142 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6143 buff
, NULL
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
));
6144 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
6145 *pbstrOut
= SysAllocString(numbuff
);
6149 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
6151 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6154 /******************************************************************************
6155 * VarBstrFromR4 (OLEAUT32.111)
6157 * Convert a VT_R4 to a VT_BSTR.
6161 * lcid [I] LCID for the conversion
6162 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6163 * pbstrOut [O] Destination
6167 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6168 * E_OUTOFMEMORY, if memory allocation fails.
6170 HRESULT WINAPI
VarBstrFromR4(FLOAT fltIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6172 return VARIANT_BstrFromReal(fltIn
, lcid
, dwFlags
, pbstrOut
, szFloatFormatW
);
6175 /******************************************************************************
6176 * VarBstrFromR8 (OLEAUT32.112)
6178 * Convert a VT_R8 to a VT_BSTR.
6182 * lcid [I] LCID for the conversion
6183 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6184 * pbstrOut [O] Destination
6188 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6189 * E_OUTOFMEMORY, if memory allocation fails.
6191 HRESULT WINAPI
VarBstrFromR8(double dblIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6193 return VARIANT_BstrFromReal(dblIn
, lcid
, dwFlags
, pbstrOut
, szDoubleFormatW
);
6196 /******************************************************************************
6197 * VarBstrFromCy [OLEAUT32.113]
6199 * Convert a VT_CY to a VT_BSTR.
6203 * lcid [I] LCID for the conversion
6204 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6205 * pbstrOut [O] Destination
6209 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6210 * E_OUTOFMEMORY, if memory allocation fails.
6212 HRESULT WINAPI
VarBstrFromCy(CY cyIn
, LCID lcid
, ULONG dwFlags
, BSTR
*pbstrOut
)
6218 return E_INVALIDARG
;
6220 VarR8FromCy(cyIn
, &dblVal
);
6221 sprintfW(buff
, szDoubleFormatW
, dblVal
);
6223 if (dwFlags
& LOCALE_USE_NLS
)
6227 /* Format the currency for the locale */
6229 GetCurrencyFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6230 buff
, NULL
, cybuff
, sizeof(cybuff
) / sizeof(WCHAR
));
6231 *pbstrOut
= SysAllocString(cybuff
);
6234 *pbstrOut
= SysAllocString(buff
);
6236 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6239 /******************************************************************************
6240 * VarBstrFromDate [OLEAUT32.114]
6242 * Convert a VT_DATE to a VT_BSTR.
6246 * lcid [I] LCID for the conversion
6247 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6248 * pbstrOut [O] Destination
6252 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6253 * E_OUTOFMEMORY, if memory allocation fails.
6255 HRESULT WINAPI
VarBstrFromDate(DATE dateIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6258 DWORD dwFormatFlags
= dwFlags
& LOCALE_NOUSEROVERRIDE
;
6259 WCHAR date
[128], *time
;
6261 TRACE("(%g,0x%08lx,0x%08lx,%p)\n", dateIn
, lcid
, dwFlags
, pbstrOut
);
6263 if (!pbstrOut
|| !VariantTimeToSystemTime(dateIn
, &st
))
6264 return E_INVALIDARG
;
6268 if (dwFlags
& VAR_CALENDAR_THAI
)
6269 st
.wYear
+= 553; /* Use the Thai buddhist calendar year */
6270 else if (dwFlags
& (VAR_CALENDAR_HIJRI
|VAR_CALENDAR_GREGORIAN
))
6271 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6273 if (dwFlags
& LOCALE_USE_NLS
)
6274 dwFlags
&= ~(VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
);
6277 double whole
= dateIn
< 0 ? ceil(dateIn
) : floor(dateIn
);
6278 double partial
= dateIn
- whole
;
6281 dwFlags
|= VAR_TIMEVALUEONLY
;
6282 else if (partial
< 1e-12)
6283 dwFlags
|= VAR_DATEVALUEONLY
;
6286 if (dwFlags
& VAR_TIMEVALUEONLY
)
6289 if (!GetDateFormatW(lcid
, dwFormatFlags
|DATE_SHORTDATE
, &st
, NULL
, date
,
6290 sizeof(date
)/sizeof(WCHAR
)))
6291 return E_INVALIDARG
;
6293 if (!(dwFlags
& VAR_DATEVALUEONLY
))
6295 time
= date
+ strlenW(date
);
6298 if (!GetTimeFormatW(lcid
, dwFormatFlags
, &st
, NULL
, time
,
6299 sizeof(date
)/sizeof(WCHAR
)-(time
-date
)))
6300 return E_INVALIDARG
;
6303 *pbstrOut
= SysAllocString(date
);
6305 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6306 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6309 /******************************************************************************
6310 * VarBstrFromBool (OLEAUT32.116)
6312 * Convert a VT_BOOL to a VT_BSTR.
6316 * lcid [I] LCID for the conversion
6317 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6318 * pbstrOut [O] Destination
6322 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6323 * E_OUTOFMEMORY, if memory allocation fails.
6326 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6327 * localised text of "True" or "False". To convert a bool into a
6328 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6330 HRESULT WINAPI
VarBstrFromBool(VARIANT_BOOL boolIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6333 DWORD dwResId
= IDS_TRUE
;
6336 TRACE("%d,0x%08lx,0x%08lx,%p\n", boolIn
, lcid
, dwFlags
, pbstrOut
);
6339 return E_INVALIDARG
;
6341 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6342 * for variant formatting */
6343 switch (dwFlags
& (VAR_LOCALBOOL
|VAR_BOOLONOFF
|VAR_BOOLYESNO
))
6354 lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
),SORT_DEFAULT
);
6357 lcid
= ConvertDefaultLocale(lcid
);
6358 langId
= LANGIDFROMLCID(lcid
);
6359 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6360 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6362 if (boolIn
== VARIANT_FALSE
)
6363 dwResId
++; /* Use negative form */
6365 VarBstrFromBool_GetLocalised
:
6366 if (VARIANT_GetLocalisedText(langId
, dwResId
, szBuff
))
6368 *pbstrOut
= SysAllocString(szBuff
);
6369 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6372 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6374 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6375 goto VarBstrFromBool_GetLocalised
;
6378 /* Should never get here */
6379 WARN("Failed to load bool text!\n");
6380 return E_OUTOFMEMORY
;
6383 /******************************************************************************
6384 * VarBstrFromI1 (OLEAUT32.229)
6386 * Convert a VT_I1 to a VT_BSTR.
6390 * lcid [I] LCID for the conversion
6391 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6392 * pbstrOut [O] Destination
6396 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6397 * E_OUTOFMEMORY, if memory allocation fails.
6399 HRESULT WINAPI
VarBstrFromI1(signed char cIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6406 dwFlags
|= VAR_NEGATIVE
;
6408 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6411 /******************************************************************************
6412 * VarBstrFromUI2 (OLEAUT32.230)
6414 * Convert a VT_UI2 to a VT_BSTR.
6418 * lcid [I] LCID for the conversion
6419 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6420 * pbstrOut [O] Destination
6424 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6425 * E_OUTOFMEMORY, if memory allocation fails.
6427 HRESULT WINAPI
VarBstrFromUI2(USHORT usIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6429 return VARIANT_BstrFromUInt(usIn
, lcid
, dwFlags
, pbstrOut
);
6432 /******************************************************************************
6433 * VarBstrFromUI4 (OLEAUT32.231)
6435 * Convert a VT_UI4 to a VT_BSTR.
6439 * lcid [I] LCID for the conversion
6440 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6441 * pbstrOut [O] Destination
6445 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6446 * E_OUTOFMEMORY, if memory allocation fails.
6448 HRESULT WINAPI
VarBstrFromUI4(ULONG ulIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6450 return VARIANT_BstrFromUInt(ulIn
, lcid
, dwFlags
, pbstrOut
);
6453 /******************************************************************************
6454 * VarBstrFromDec (OLEAUT32.232)
6456 * Convert a VT_DECIMAL to a VT_BSTR.
6460 * lcid [I] LCID for the conversion
6461 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6462 * pbstrOut [O] Destination
6466 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6467 * E_OUTOFMEMORY, if memory allocation fails.
6469 HRESULT WINAPI
VarBstrFromDec(DECIMAL
* pDecIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6475 return E_INVALIDARG
;
6477 VARIANT_DIFromDec(pDecIn
, &temp
);
6478 VARIANT_DI_tostringW(&temp
, buff
, 256);
6480 if (dwFlags
& LOCALE_USE_NLS
)
6484 /* Format the number for the locale */
6486 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6487 buff
, NULL
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
));
6488 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
6489 *pbstrOut
= SysAllocString(numbuff
);
6493 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
6496 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6497 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6500 /************************************************************************
6501 * VarBstrFromI8 (OLEAUT32.370)
6503 * Convert a VT_I8 to a VT_BSTR.
6507 * lcid [I] LCID for the conversion
6508 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6509 * pbstrOut [O] Destination
6513 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6514 * E_OUTOFMEMORY, if memory allocation fails.
6516 HRESULT WINAPI
VarBstrFromI8(LONG64 llIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6518 ULONG64 ul64
= llIn
;
6523 dwFlags
|= VAR_NEGATIVE
;
6525 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6528 /************************************************************************
6529 * VarBstrFromUI8 (OLEAUT32.371)
6531 * Convert a VT_UI8 to a VT_BSTR.
6535 * lcid [I] LCID for the conversion
6536 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6537 * pbstrOut [O] Destination
6541 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6542 * E_OUTOFMEMORY, if memory allocation fails.
6544 HRESULT WINAPI
VarBstrFromUI8(ULONG64 ullIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6546 return VARIANT_BstrFromUInt(ullIn
, lcid
, dwFlags
, pbstrOut
);
6549 /************************************************************************
6550 * VarBstrFromDisp (OLEAUT32.115)
6552 * Convert a VT_DISPATCH to a BSTR.
6555 * pdispIn [I] Source
6556 * lcid [I] LCID for conversion
6557 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6558 * pbstrOut [O] Destination
6562 * Failure: E_INVALIDARG, if the source value is invalid
6563 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6565 HRESULT WINAPI
VarBstrFromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6567 return VARIANT_FromDisp(pdispIn
, lcid
, pbstrOut
, VT_BSTR
, dwFlags
);
6570 /**********************************************************************
6571 * VarBstrCat (OLEAUT32.313)
6573 * Concatenate two BSTR values.
6576 * pbstrLeft [I] Source
6577 * pbstrRight [I] Value to concatenate
6578 * pbstrOut [O] Destination
6582 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6583 * E_OUTOFMEMORY, if memory allocation fails.
6585 HRESULT WINAPI
VarBstrCat(BSTR pbstrLeft
, BSTR pbstrRight
, BSTR
*pbstrOut
)
6590 return E_INVALIDARG
;
6592 len
= pbstrLeft
? strlenW(pbstrLeft
) : 0;
6594 len
+= strlenW(pbstrRight
);
6596 *pbstrOut
= SysAllocStringLen(NULL
, len
);
6598 return E_OUTOFMEMORY
;
6600 (*pbstrOut
)[0] = '\0';
6603 strcpyW(*pbstrOut
, pbstrLeft
);
6606 strcatW(*pbstrOut
, pbstrRight
);
6611 /**********************************************************************
6612 * VarBstrCmp (OLEAUT32.314)
6614 * Compare two BSTR values.
6617 * pbstrLeft [I] Source
6618 * pbstrRight [I] Value to compare
6619 * lcid [I] LCID for the comparison
6620 * dwFlags [I] Flags to pass directly to CompareStringW().
6623 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
6624 * than, equal to or greater than pbstrRight respectively.
6627 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
6628 * states. A NULL BSTR pointer is equivalent to an empty string.
6630 HRESULT WINAPI
VarBstrCmp(BSTR pbstrLeft
, BSTR pbstrRight
, LCID lcid
, DWORD dwFlags
)
6632 if (!pbstrLeft
|| !*pbstrLeft
)
6634 if (!pbstrRight
|| !*pbstrRight
)
6638 else if (!pbstrRight
|| !*pbstrRight
)
6641 return CompareStringW(lcid
, dwFlags
, pbstrLeft
, -1, pbstrRight
, -1) - 1;
6648 /******************************************************************************
6649 * VarDateFromUI1 (OLEAUT32.88)
6651 * Convert a VT_UI1 to a VT_DATE.
6655 * pdateOut [O] Destination
6660 HRESULT WINAPI
VarDateFromUI1(BYTE bIn
, DATE
* pdateOut
)
6662 return VarR8FromUI1(bIn
, pdateOut
);
6665 /******************************************************************************
6666 * VarDateFromI2 (OLEAUT32.89)
6668 * Convert a VT_I2 to a VT_DATE.
6672 * pdateOut [O] Destination
6677 HRESULT WINAPI
VarDateFromI2(short sIn
, DATE
* pdateOut
)
6679 return VarR8FromI2(sIn
, pdateOut
);
6682 /******************************************************************************
6683 * VarDateFromI4 (OLEAUT32.90)
6685 * Convert a VT_I4 to a VT_DATE.
6689 * pdateOut [O] Destination
6694 HRESULT WINAPI
VarDateFromI4(LONG lIn
, DATE
* pdateOut
)
6696 return VarDateFromR8(lIn
, pdateOut
);
6699 /******************************************************************************
6700 * VarDateFromR4 (OLEAUT32.91)
6702 * Convert a VT_R4 to a VT_DATE.
6706 * pdateOut [O] Destination
6711 HRESULT WINAPI
VarDateFromR4(FLOAT fltIn
, DATE
* pdateOut
)
6713 return VarR8FromR4(fltIn
, pdateOut
);
6716 /******************************************************************************
6717 * VarDateFromR8 (OLEAUT32.92)
6719 * Convert a VT_R8 to a VT_DATE.
6723 * pdateOut [O] Destination
6728 HRESULT WINAPI
VarDateFromR8(double dblIn
, DATE
* pdateOut
)
6730 if (dblIn
<= (DATE_MIN
- 1.0) || dblIn
>= (DATE_MAX
+ 1.0)) return DISP_E_OVERFLOW
;
6731 *pdateOut
= (DATE
)dblIn
;
6735 /**********************************************************************
6736 * VarDateFromDisp (OLEAUT32.95)
6738 * Convert a VT_DISPATCH to a VT_DATE.
6741 * pdispIn [I] Source
6742 * lcid [I] LCID for conversion
6743 * pdateOut [O] Destination
6747 * Failure: E_INVALIDARG, if the source value is invalid
6748 * DISP_E_OVERFLOW, if the value will not fit in the destination
6749 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6751 HRESULT WINAPI
VarDateFromDisp(IDispatch
* pdispIn
, LCID lcid
, DATE
* pdateOut
)
6753 return VARIANT_FromDisp(pdispIn
, lcid
, pdateOut
, VT_DATE
, 0);
6756 /******************************************************************************
6757 * VarDateFromBool (OLEAUT32.96)
6759 * Convert a VT_BOOL to a VT_DATE.
6763 * pdateOut [O] Destination
6768 HRESULT WINAPI
VarDateFromBool(VARIANT_BOOL boolIn
, DATE
* pdateOut
)
6770 return VarR8FromBool(boolIn
, pdateOut
);
6773 /**********************************************************************
6774 * VarDateFromCy (OLEAUT32.93)
6776 * Convert a VT_CY to a VT_DATE.
6780 * pdateOut [O] Destination
6785 HRESULT WINAPI
VarDateFromCy(CY cyIn
, DATE
* pdateOut
)
6787 return VarR8FromCy(cyIn
, pdateOut
);
6790 /* Date string parsing */
6791 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
6792 #define DP_DATESEP 0x02 /* Date separator */
6793 #define DP_MONTH 0x04 /* Month name */
6794 #define DP_AM 0x08 /* AM */
6795 #define DP_PM 0x10 /* PM */
6797 typedef struct tagDATEPARSE
6799 DWORD dwCount
; /* Number of fields found so far (maximum 6) */
6800 DWORD dwParseFlags
; /* Global parse flags (DP_ Flags above) */
6801 DWORD dwFlags
[6]; /* Flags for each field */
6802 DWORD dwValues
[6]; /* Value of each field */
6805 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
6807 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
6809 /* Determine if a day is valid in a given month of a given year */
6810 static BOOL
VARIANT_IsValidMonthDay(DWORD day
, DWORD month
, DWORD year
)
6812 static const BYTE days
[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
6814 if (day
&& month
&& month
< 13)
6816 if (day
<= days
[month
] || (month
== 2 && day
== 29 && IsLeapYear(year
)))
6822 /* Possible orders for 3 numbers making up a date */
6823 #define ORDER_MDY 0x01
6824 #define ORDER_YMD 0x02
6825 #define ORDER_YDM 0x04
6826 #define ORDER_DMY 0x08
6827 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
6829 /* Determine a date for a particular locale, from 3 numbers */
6830 static inline HRESULT
VARIANT_MakeDate(DATEPARSE
*dp
, DWORD iDate
,
6831 DWORD offset
, SYSTEMTIME
*st
)
6833 DWORD dwAllOrders
, dwTry
, dwCount
= 0, v1
, v2
, v3
;
6837 v1
= 30; /* Default to (Variant) 0 date part */
6840 goto VARIANT_MakeDate_OK
;
6843 v1
= dp
->dwValues
[offset
+ 0];
6844 v2
= dp
->dwValues
[offset
+ 1];
6845 if (dp
->dwCount
== 2)
6848 GetSystemTime(¤t
);
6852 v3
= dp
->dwValues
[offset
+ 2];
6854 TRACE("(%ld,%ld,%ld,%ld,%ld)\n", v1
, v2
, v3
, iDate
, offset
);
6856 /* If one number must be a month (Because a month name was given), then only
6857 * consider orders with the month in that position.
6858 * If we took the current year as 'v3', then only allow a year in that position.
6860 if (dp
->dwFlags
[offset
+ 0] & DP_MONTH
)
6862 dwAllOrders
= ORDER_MDY
;
6864 else if (dp
->dwFlags
[offset
+ 1] & DP_MONTH
)
6866 dwAllOrders
= ORDER_DMY
;
6867 if (dp
->dwCount
> 2)
6868 dwAllOrders
|= ORDER_YMD
;
6870 else if (dp
->dwCount
> 2 && dp
->dwFlags
[offset
+ 2] & DP_MONTH
)
6872 dwAllOrders
= ORDER_YDM
;
6876 dwAllOrders
= ORDER_MDY
|ORDER_DMY
;
6877 if (dp
->dwCount
> 2)
6878 dwAllOrders
|= (ORDER_YMD
|ORDER_YDM
);
6881 VARIANT_MakeDate_Start
:
6882 TRACE("dwAllOrders is 0x%08lx\n", dwAllOrders
);
6890 /* First: Try the order given by iDate */
6893 case 0: dwTry
= dwAllOrders
& ORDER_MDY
; break;
6894 case 1: dwTry
= dwAllOrders
& ORDER_DMY
; break;
6895 default: dwTry
= dwAllOrders
& ORDER_YMD
; break;
6898 else if (dwCount
== 1)
6900 /* Second: Try all the orders compatible with iDate */
6903 case 0: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
6904 case 1: dwTry
= dwAllOrders
& ~(ORDER_MDY
|ORDER_YMD
|ORDER_MYD
); break;
6905 default: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
6910 /* Finally: Try any remaining orders */
6911 dwTry
= dwAllOrders
;
6914 TRACE("Attempt %ld, dwTry is 0x%08lx\n", dwCount
, dwTry
);
6920 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
6922 if (dwTry
& ORDER_MDY
)
6924 if (VARIANT_IsValidMonthDay(v2
,v1
,v3
))
6927 goto VARIANT_MakeDate_OK
;
6929 dwAllOrders
&= ~ORDER_MDY
;
6931 if (dwTry
& ORDER_YMD
)
6933 if (VARIANT_IsValidMonthDay(v3
,v2
,v1
))
6936 goto VARIANT_MakeDate_OK
;
6938 dwAllOrders
&= ~ORDER_YMD
;
6940 if (dwTry
& ORDER_YDM
)
6942 if (VARIANT_IsValidMonthDay(v2
,v3
,v1
))
6946 goto VARIANT_MakeDate_OK
;
6948 dwAllOrders
&= ~ORDER_YDM
;
6950 if (dwTry
& ORDER_DMY
)
6952 if (VARIANT_IsValidMonthDay(v1
,v2
,v3
))
6953 goto VARIANT_MakeDate_OK
;
6954 dwAllOrders
&= ~ORDER_DMY
;
6956 if (dwTry
& ORDER_MYD
)
6958 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
6959 if (VARIANT_IsValidMonthDay(v3
,v1
,v2
))
6963 goto VARIANT_MakeDate_OK
;
6965 dwAllOrders
&= ~ORDER_MYD
;
6969 if (dp
->dwCount
== 2)
6971 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
6972 v3
= 1; /* 1st of the month */
6973 dwAllOrders
= ORDER_YMD
|ORDER_MYD
;
6974 dp
->dwCount
= 0; /* Don't return to this code path again */
6976 goto VARIANT_MakeDate_Start
;
6979 /* No valid dates were able to be constructed */
6980 return DISP_E_TYPEMISMATCH
;
6982 VARIANT_MakeDate_OK
:
6984 /* Check that the time part is ok */
6985 if (st
->wHour
> 23 || st
->wMinute
> 59 || st
->wSecond
> 59)
6986 return DISP_E_TYPEMISMATCH
;
6988 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
6989 if (st
->wHour
< 12 && (dp
->dwParseFlags
& DP_PM
))
6991 else if (st
->wHour
== 12 && (dp
->dwParseFlags
& DP_AM
))
6993 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
6997 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
6998 * be retrieved from:
6999 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7000 * But Wine doesn't have/use that key as at the time of writing.
7002 st
->wYear
= v3
< 30 ? 2000 + v3
: v3
< 100 ? 1900 + v3
: v3
;
7003 TRACE("Returning date %ld/%ld/%d\n", v1
, v2
, st
->wYear
);
7007 /******************************************************************************
7008 * VarDateFromStr [OLEAUT32.94]
7010 * Convert a VT_BSTR to at VT_DATE.
7013 * strIn [I] String to convert
7014 * lcid [I] Locale identifier for the conversion
7015 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7016 * pdateOut [O] Destination for the converted value
7019 * Success: S_OK. pdateOut contains the converted value.
7020 * FAILURE: An HRESULT error code indicating the prolem.
7023 * Any date format that can be created using the date formats from lcid
7024 * (Either from kernel Nls functions, variant conversion or formatting) is a
7025 * valid input to this function. In addition, a few more esoteric formats are
7026 * also supported for compatibility with the native version. The date is
7027 * interpreted according to the date settings in the control panel, unless
7028 * the date is invalid in that format, in which the most compatible format
7029 * that produces a valid date will be used.
7031 HRESULT WINAPI
VarDateFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DATE
* pdateOut
)
7033 static const USHORT ParseDateTokens
[] =
7035 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
7036 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
7037 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
,
7038 LOCALE_SMONTHNAME13
,
7039 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
7040 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
7041 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
7042 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
,
7043 LOCALE_SABBREVMONTHNAME13
,
7044 LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
, LOCALE_SDAYNAME4
,
7045 LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
, LOCALE_SDAYNAME7
,
7046 LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
, LOCALE_SABBREVDAYNAME3
,
7047 LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
, LOCALE_SABBREVDAYNAME6
,
7048 LOCALE_SABBREVDAYNAME7
,
7049 LOCALE_S1159
, LOCALE_S2359
7051 static const BYTE ParseDateMonths
[] =
7053 1,2,3,4,5,6,7,8,9,10,11,12,13,
7054 1,2,3,4,5,6,7,8,9,10,11,12,13
7057 BSTR tokens
[sizeof(ParseDateTokens
)/sizeof(ParseDateTokens
[0])];
7059 DWORD dwDateSeps
= 0, iDate
= 0;
7060 HRESULT hRet
= S_OK
;
7062 if ((dwFlags
& (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
)) ==
7063 (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
))
7064 return E_INVALIDARG
;
7067 return DISP_E_TYPEMISMATCH
;
7071 TRACE("(%s,0x%08lx,0x%08lx,%p)\n", debugstr_w(strIn
), lcid
, dwFlags
, pdateOut
);
7073 memset(&dp
, 0, sizeof(dp
));
7075 GetLocaleInfoW(lcid
, LOCALE_IDATE
|LOCALE_RETURN_NUMBER
|(dwFlags
& LOCALE_NOUSEROVERRIDE
),
7076 (LPWSTR
)&iDate
, sizeof(iDate
)/sizeof(WCHAR
));
7077 TRACE("iDate is %ld\n", iDate
);
7079 /* Get the month/day/am/pm tokens for this locale */
7080 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7083 LCTYPE lctype
= ParseDateTokens
[i
] | (dwFlags
& LOCALE_NOUSEROVERRIDE
);
7085 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7086 * GetAltMonthNames(). We should really cache these strings too.
7089 GetLocaleInfoW(lcid
, lctype
, buff
, sizeof(buff
)/sizeof(WCHAR
));
7090 tokens
[i
] = SysAllocString(buff
);
7091 TRACE("token %d is %s\n", i
, debugstr_w(tokens
[i
]));
7094 /* Parse the string into our structure */
7100 if (isdigitW(*strIn
))
7102 dp
.dwValues
[dp
.dwCount
] = strtoulW(strIn
, &strIn
, 10);
7106 else if (isalpha(*strIn
))
7108 BOOL bFound
= FALSE
;
7110 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7112 DWORD dwLen
= strlenW(tokens
[i
]);
7113 if (dwLen
&& !strncmpiW(strIn
, tokens
[i
], dwLen
))
7117 dp
.dwValues
[dp
.dwCount
] = ParseDateMonths
[i
];
7118 dp
.dwFlags
[dp
.dwCount
] |= (DP_MONTH
|DP_DATESEP
);
7123 if (!dp
.dwCount
|| dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7124 hRet
= DISP_E_TYPEMISMATCH
;
7127 dp
.dwFlags
[dp
.dwCount
- 1] |= (i
== 40 ? DP_AM
: DP_PM
);
7128 dp
.dwParseFlags
|= (i
== 40 ? DP_AM
: DP_PM
);
7131 strIn
+= (dwLen
- 1);
7139 if ((*strIn
== 'a' || *strIn
== 'A' || *strIn
== 'p' || *strIn
== 'P') &&
7140 (dp
.dwCount
&& !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7142 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7143 if (*strIn
== 'a' || *strIn
== 'A')
7145 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_AM
;
7146 dp
.dwParseFlags
|= DP_AM
;
7150 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_PM
;
7151 dp
.dwParseFlags
|= DP_PM
;
7157 TRACE("No matching token for %s\n", debugstr_w(strIn
));
7158 hRet
= DISP_E_TYPEMISMATCH
;
7163 else if (*strIn
== ':' || *strIn
== '.')
7165 if (!dp
.dwCount
|| !strIn
[1])
7166 hRet
= DISP_E_TYPEMISMATCH
;
7168 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_TIMESEP
;
7170 else if (*strIn
== '-' || *strIn
== '/')
7173 if (dwDateSeps
> 2 || !dp
.dwCount
|| !strIn
[1])
7174 hRet
= DISP_E_TYPEMISMATCH
;
7176 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7178 else if (*strIn
== ',' || isspaceW(*strIn
))
7180 if (*strIn
== ',' && !strIn
[1])
7181 hRet
= DISP_E_TYPEMISMATCH
;
7185 hRet
= DISP_E_TYPEMISMATCH
;
7190 if (!dp
.dwCount
|| dp
.dwCount
> 6 ||
7191 (dp
.dwCount
== 1 && !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7192 hRet
= DISP_E_TYPEMISMATCH
;
7194 if (SUCCEEDED(hRet
))
7197 DWORD dwOffset
= 0; /* Start of date fields in dp.dwValues */
7199 st
.wDayOfWeek
= st
.wHour
= st
.wMinute
= st
.wSecond
= st
.wMilliseconds
= 0;
7201 /* Figure out which numbers correspond to which fields.
7203 * This switch statement works based on the fact that native interprets any
7204 * fields that are not joined with a time separator ('.' or ':') as date
7205 * fields. Thus we construct a value from 0-32 where each set bit indicates
7206 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7207 * For valid permutations, we set dwOffset to point to the first date field
7208 * and shorten dp.dwCount by the number of time fields found. The real
7209 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7210 * each date number must represent in the context of iDate.
7212 TRACE("0x%08lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7214 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7216 case 0x1: /* TT TTDD TTDDD */
7217 if (dp
.dwCount
> 3 &&
7218 ((dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) ||
7219 (dp
.dwFlags
[4] & (DP_AM
|DP_PM
))))
7220 hRet
= DISP_E_TYPEMISMATCH
;
7221 else if (dp
.dwCount
!= 2 && dp
.dwCount
!= 4 && dp
.dwCount
!= 5)
7222 hRet
= DISP_E_TYPEMISMATCH
;
7223 st
.wHour
= dp
.dwValues
[0];
7224 st
.wMinute
= dp
.dwValues
[1];
7229 case 0x3: /* TTT TTTDD TTTDDD */
7230 if (dp
.dwCount
> 4 &&
7231 ((dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[4] & (DP_AM
|DP_PM
)) ||
7232 (dp
.dwFlags
[5] & (DP_AM
|DP_PM
))))
7233 hRet
= DISP_E_TYPEMISMATCH
;
7234 else if (dp
.dwCount
!= 3 && dp
.dwCount
!= 5 && dp
.dwCount
!= 6)
7235 hRet
= DISP_E_TYPEMISMATCH
;
7236 st
.wHour
= dp
.dwValues
[0];
7237 st
.wMinute
= dp
.dwValues
[1];
7238 st
.wSecond
= dp
.dwValues
[2];
7243 case 0x4: /* DDTT */
7244 if (dp
.dwCount
!= 4 ||
7245 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7246 hRet
= DISP_E_TYPEMISMATCH
;
7248 st
.wHour
= dp
.dwValues
[2];
7249 st
.wMinute
= dp
.dwValues
[3];
7253 case 0x0: /* T DD DDD TDDD TDDD */
7254 if (dp
.dwCount
== 1 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7256 st
.wHour
= dp
.dwValues
[0]; /* T */
7260 else if (dp
.dwCount
> 4 || (dp
.dwCount
< 3 && dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7262 hRet
= DISP_E_TYPEMISMATCH
;
7264 else if (dp
.dwCount
== 3)
7266 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDD */
7269 st
.wHour
= dp
.dwValues
[0];
7273 if (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) /* DDT */
7276 st
.wHour
= dp
.dwValues
[2];
7279 else if (dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7280 hRet
= DISP_E_TYPEMISMATCH
;
7282 else if (dp
.dwCount
== 4)
7285 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDDD */
7287 st
.wHour
= dp
.dwValues
[0];
7290 else if (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) /* DDDT */
7292 st
.wHour
= dp
.dwValues
[3];
7295 hRet
= DISP_E_TYPEMISMATCH
;
7298 /* .. fall through .. */
7300 case 0x8: /* DDDTT */
7301 if ((dp
.dwCount
== 2 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
))) ||
7302 (dp
.dwCount
== 5 && ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) ||
7303 (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))) ||
7304 dp
.dwCount
== 4 || dp
.dwCount
== 6)
7305 hRet
= DISP_E_TYPEMISMATCH
;
7306 st
.wHour
= dp
.dwValues
[3];
7307 st
.wMinute
= dp
.dwValues
[4];
7308 if (dp
.dwCount
== 5)
7312 case 0xC: /* DDTTT */
7313 if (dp
.dwCount
!= 5 ||
7314 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7315 hRet
= DISP_E_TYPEMISMATCH
;
7316 st
.wHour
= dp
.dwValues
[2];
7317 st
.wMinute
= dp
.dwValues
[3];
7318 st
.wSecond
= dp
.dwValues
[4];
7322 case 0x18: /* DDDTTT */
7323 if ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) ||
7324 (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))
7325 hRet
= DISP_E_TYPEMISMATCH
;
7326 st
.wHour
= dp
.dwValues
[3];
7327 st
.wMinute
= dp
.dwValues
[4];
7328 st
.wSecond
= dp
.dwValues
[5];
7333 hRet
= DISP_E_TYPEMISMATCH
;
7337 if (SUCCEEDED(hRet
))
7339 hRet
= VARIANT_MakeDate(&dp
, iDate
, dwOffset
, &st
);
7341 if (dwFlags
& VAR_TIMEVALUEONLY
)
7347 else if (dwFlags
& VAR_DATEVALUEONLY
)
7348 st
.wHour
= st
.wMinute
= st
.wSecond
= 0;
7350 /* Finally, convert the value to a VT_DATE */
7351 if (SUCCEEDED(hRet
))
7352 hRet
= SystemTimeToVariantTime(&st
, pdateOut
) ? S_OK
: DISP_E_TYPEMISMATCH
;
7356 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7357 SysFreeString(tokens
[i
]);
7361 /******************************************************************************
7362 * VarDateFromI1 (OLEAUT32.221)
7364 * Convert a VT_I1 to a VT_DATE.
7368 * pdateOut [O] Destination
7373 HRESULT WINAPI
VarDateFromI1(signed char cIn
, DATE
* pdateOut
)
7375 return VarR8FromI1(cIn
, pdateOut
);
7378 /******************************************************************************
7379 * VarDateFromUI2 (OLEAUT32.222)
7381 * Convert a VT_UI2 to a VT_DATE.
7385 * pdateOut [O] Destination
7390 HRESULT WINAPI
VarDateFromUI2(USHORT uiIn
, DATE
* pdateOut
)
7392 return VarR8FromUI2(uiIn
, pdateOut
);
7395 /******************************************************************************
7396 * VarDateFromUI4 (OLEAUT32.223)
7398 * Convert a VT_UI4 to a VT_DATE.
7402 * pdateOut [O] Destination
7407 HRESULT WINAPI
VarDateFromUI4(ULONG ulIn
, DATE
* pdateOut
)
7409 return VarDateFromR8(ulIn
, pdateOut
);
7412 /**********************************************************************
7413 * VarDateFromDec (OLEAUT32.224)
7415 * Convert a VT_DECIMAL to a VT_DATE.
7419 * pdateOut [O] Destination
7424 HRESULT WINAPI
VarDateFromDec(DECIMAL
*pdecIn
, DATE
* pdateOut
)
7426 return VarR8FromDec(pdecIn
, pdateOut
);
7429 /******************************************************************************
7430 * VarDateFromI8 (OLEAUT32.364)
7432 * Convert a VT_I8 to a VT_DATE.
7436 * pdateOut [O] Destination
7440 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7442 HRESULT WINAPI
VarDateFromI8(LONG64 llIn
, DATE
* pdateOut
)
7444 if (llIn
< DATE_MIN
|| llIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
7445 *pdateOut
= (DATE
)llIn
;
7449 /******************************************************************************
7450 * VarDateFromUI8 (OLEAUT32.365)
7452 * Convert a VT_UI8 to a VT_DATE.
7456 * pdateOut [O] Destination
7460 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7462 HRESULT WINAPI
VarDateFromUI8(ULONG64 ullIn
, DATE
* pdateOut
)
7464 if (ullIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
7465 *pdateOut
= (DATE
)ullIn
;