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)
6587 unsigned int lenLeft, lenRight;
6590 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
6591 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
6594 return E_INVALIDARG;
6596 lenLeft = pbstrLeft ? SysStringLen(pbstrLeft) : 0;
6597 lenRight = pbstrRight ? SysStringLen(pbstrRight) : 0;
6599 *pbstrOut = SysAllocStringLen(NULL, lenLeft + lenRight);
6601 return E_OUTOFMEMORY;
6603 (*pbstrOut)[0] = '\0';
6606 memcpy(*pbstrOut, pbstrLeft, lenLeft * sizeof(WCHAR));
6609 memcpy(*pbstrOut + lenLeft, pbstrRight, lenRight * sizeof(WCHAR));
6611 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
6615 /**********************************************************************
6616 * VarBstrCmp (OLEAUT32.314)
6618 * Compare two BSTR values.
6621 * pbstrLeft [I] Source
6622 * pbstrRight [I] Value to compare
6623 * lcid [I] LCID for the comparison
6624 * dwFlags [I] Flags to pass directly to CompareStringW().
6627 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
6628 * than, equal to or greater than pbstrRight respectively.
6631 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
6632 * states. A NULL BSTR pointer is equivalent to an empty string.
6634 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
6638 TRACE("%s,%s,%ld,%08lx\n",
6639 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
6640 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
6642 if (!pbstrLeft || !*pbstrLeft)
6644 if (!pbstrRight || !*pbstrRight)
6648 else if (!pbstrRight || !*pbstrRight)
6651 hres = CompareStringW(lcid, dwFlags, pbstrLeft, SysStringLen(pbstrLeft),
6652 pbstrRight, SysStringLen(pbstrRight)) - 1;
6653 TRACE("%ld\n", hres);
6661 /******************************************************************************
6662 * VarDateFromUI1 (OLEAUT32.88)
6664 * Convert a VT_UI1 to a VT_DATE.
6668 * pdateOut [O] Destination
6673 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
6675 return VarR8FromUI1(bIn, pdateOut);
6678 /******************************************************************************
6679 * VarDateFromI2 (OLEAUT32.89)
6681 * Convert a VT_I2 to a VT_DATE.
6685 * pdateOut [O] Destination
6690 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
6692 return VarR8FromI2(sIn, pdateOut);
6695 /******************************************************************************
6696 * VarDateFromI4 (OLEAUT32.90)
6698 * Convert a VT_I4 to a VT_DATE.
6702 * pdateOut [O] Destination
6707 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
6709 return VarDateFromR8(lIn, pdateOut);
6712 /******************************************************************************
6713 * VarDateFromR4 (OLEAUT32.91)
6715 * Convert a VT_R4 to a VT_DATE.
6719 * pdateOut [O] Destination
6724 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
6726 return VarR8FromR4(fltIn, pdateOut);
6729 /******************************************************************************
6730 * VarDateFromR8 (OLEAUT32.92)
6732 * Convert a VT_R8 to a VT_DATE.
6736 * pdateOut [O] Destination
6741 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
6743 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
6744 *pdateOut = (DATE)dblIn;
6748 /**********************************************************************
6749 * VarDateFromDisp (OLEAUT32.95)
6751 * Convert a VT_DISPATCH to a VT_DATE.
6754 * pdispIn [I] Source
6755 * lcid [I] LCID for conversion
6756 * pdateOut [O] Destination
6760 * Failure: E_INVALIDARG, if the source value is invalid
6761 * DISP_E_OVERFLOW, if the value will not fit in the destination
6762 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6764 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
6766 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
6769 /******************************************************************************
6770 * VarDateFromBool (OLEAUT32.96)
6772 * Convert a VT_BOOL to a VT_DATE.
6776 * pdateOut [O] Destination
6781 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
6783 return VarR8FromBool(boolIn, pdateOut);
6786 /**********************************************************************
6787 * VarDateFromCy (OLEAUT32.93)
6789 * Convert a VT_CY to a VT_DATE.
6793 * pdateOut [O] Destination
6798 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
6800 return VarR8FromCy(cyIn, pdateOut);
6803 /* Date string parsing */
6804 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
6805 #define DP_DATESEP 0x02 /* Date separator */
6806 #define DP_MONTH 0x04 /* Month name */
6807 #define DP_AM 0x08 /* AM */
6808 #define DP_PM 0x10 /* PM */
6810 typedef struct tagDATEPARSE
6812 DWORD dwCount; /* Number of fields found so far (maximum 6) */
6813 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
6814 DWORD dwFlags[6]; /* Flags for each field */
6815 DWORD dwValues[6]; /* Value of each field */
6818 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
6820 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
6822 /* Determine if a day is valid in a given month of a given year */
6823 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
6825 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
6827 if (day && month && month < 13)
6829 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
6835 /* Possible orders for 3 numbers making up a date */
6836 #define ORDER_MDY 0x01
6837 #define ORDER_YMD 0x02
6838 #define ORDER_YDM 0x04
6839 #define ORDER_DMY 0x08
6840 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
6842 /* Determine a date for a particular locale, from 3 numbers */
6843 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
6844 DWORD offset, SYSTEMTIME *st)
6846 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
6850 v1 = 30; /* Default to (Variant) 0 date part */
6853 goto VARIANT_MakeDate_OK;
6856 v1 = dp->dwValues[offset + 0];
6857 v2 = dp->dwValues[offset + 1];
6858 if (dp->dwCount == 2)
6861 GetSystemTime(¤t);
6865 v3 = dp->dwValues[offset + 2];
6867 TRACE("(%ld,%ld,%ld,%ld,%ld)\n", v1, v2, v3, iDate, offset);
6869 /* If one number must be a month (Because a month name was given), then only
6870 * consider orders with the month in that position.
6871 * If we took the current year as 'v3', then only allow a year in that position.
6873 if (dp->dwFlags[offset + 0] & DP_MONTH)
6875 dwAllOrders = ORDER_MDY;
6877 else if (dp->dwFlags[offset + 1] & DP_MONTH)
6879 dwAllOrders = ORDER_DMY;
6880 if (dp->dwCount > 2)
6881 dwAllOrders |= ORDER_YMD;
6883 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
6885 dwAllOrders = ORDER_YDM;
6889 dwAllOrders = ORDER_MDY|ORDER_DMY;
6890 if (dp->dwCount > 2)
6891 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
6894 VARIANT_MakeDate_Start:
6895 TRACE("dwAllOrders is 0x%08lx\n", dwAllOrders);
6903 /* First: Try the order given by iDate */
6906 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
6907 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
6908 default: dwTry = dwAllOrders & ORDER_YMD; break;
6911 else if (dwCount == 1)
6913 /* Second: Try all the orders compatible with iDate */
6916 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
6917 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break;
6918 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
6923 /* Finally: Try any remaining orders */
6924 dwTry = dwAllOrders;
6927 TRACE("Attempt %ld, dwTry is 0x%08lx\n", dwCount, dwTry);
6933 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
6935 if (dwTry & ORDER_MDY)
6937 if (VARIANT_IsValidMonthDay(v2,v1,v3))
6940 goto VARIANT_MakeDate_OK;
6942 dwAllOrders &= ~ORDER_MDY;
6944 if (dwTry & ORDER_YMD)
6946 if (VARIANT_IsValidMonthDay(v3,v2,v1))
6949 goto VARIANT_MakeDate_OK;
6951 dwAllOrders &= ~ORDER_YMD;
6953 if (dwTry & ORDER_YDM)
6955 if (VARIANT_IsValidMonthDay(v2,v3,v1))
6959 goto VARIANT_MakeDate_OK;
6961 dwAllOrders &= ~ORDER_YDM;
6963 if (dwTry & ORDER_DMY)
6965 if (VARIANT_IsValidMonthDay(v1,v2,v3))
6966 goto VARIANT_MakeDate_OK;
6967 dwAllOrders &= ~ORDER_DMY;
6969 if (dwTry & ORDER_MYD)
6971 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
6972 if (VARIANT_IsValidMonthDay(v3,v1,v2))
6976 goto VARIANT_MakeDate_OK;
6978 dwAllOrders &= ~ORDER_MYD;
6982 if (dp->dwCount == 2)
6984 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
6985 v3 = 1; /* 1st of the month */
6986 dwAllOrders = ORDER_YMD|ORDER_MYD;
6987 dp->dwCount = 0; /* Don't return to this code path again */
6989 goto VARIANT_MakeDate_Start;
6992 /* No valid dates were able to be constructed */
6993 return DISP_E_TYPEMISMATCH;
6995 VARIANT_MakeDate_OK:
6997 /* Check that the time part is ok */
6998 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
6999 return DISP_E_TYPEMISMATCH;
7001 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7002 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
7004 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
7006 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7010 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7011 * be retrieved from:
7012 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7013 * But Wine doesn't have/use that key as at the time of writing.
7015 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
7016 TRACE("Returning date %ld/%ld/%d\n", v1, v2, st->wYear);
7020 /******************************************************************************
7021 * VarDateFromStr [OLEAUT32.94]
7023 * Convert a VT_BSTR to at VT_DATE.
7026 * strIn [I] String to convert
7027 * lcid [I] Locale identifier for the conversion
7028 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7029 * pdateOut [O] Destination for the converted value
7032 * Success: S_OK. pdateOut contains the converted value.
7033 * FAILURE: An HRESULT error code indicating the prolem.
7036 * Any date format that can be created using the date formats from lcid
7037 * (Either from kernel Nls functions, variant conversion or formatting) is a
7038 * valid input to this function. In addition, a few more esoteric formats are
7039 * also supported for compatibility with the native version. The date is
7040 * interpreted according to the date settings in the control panel, unless
7041 * the date is invalid in that format, in which the most compatible format
7042 * that produces a valid date will be used.
7044 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7046 static const USHORT ParseDateTokens[] =
7048 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7049 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7050 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7051 LOCALE_SMONTHNAME13,
7052 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7053 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7054 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7055 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7056 LOCALE_SABBREVMONTHNAME13,
7057 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7058 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7059 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7060 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7061 LOCALE_SABBREVDAYNAME7,
7062 LOCALE_S1159, LOCALE_S2359
7064 static const BYTE ParseDateMonths[] =
7066 1,2,3,4,5,6,7,8,9,10,11,12,13,
7067 1,2,3,4,5,6,7,8,9,10,11,12,13
7070 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
7072 DWORD dwDateSeps = 0, iDate = 0;
7073 HRESULT hRet = S_OK;
7075 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7076 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7077 return E_INVALIDARG;
7080 return DISP_E_TYPEMISMATCH;
7084 TRACE("(%s,0x%08lx,0x%08lx,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7086 memset(&dp, 0, sizeof(dp));
7088 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7089 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7090 TRACE("iDate is %ld\n", iDate);
7092 /* Get the month/day/am/pm tokens for this locale */
7093 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7096 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7098 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7099 * GetAltMonthNames(). We should really cache these strings too.
7102 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
7103 tokens[i] = SysAllocString(buff);
7104 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7107 /* Parse the string into our structure */
7113 if (isdigitW(*strIn))
7115 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
7119 else if (isalpha(*strIn))
7121 BOOL bFound = FALSE;
7123 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7125 DWORD dwLen = strlenW(tokens[i]);
7126 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
7130 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7131 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7136 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7137 hRet = DISP_E_TYPEMISMATCH;
7140 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7141 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7144 strIn += (dwLen - 1);
7152 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7153 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7155 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7156 if (*strIn == 'a' || *strIn == 'A')
7158 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7159 dp.dwParseFlags |= DP_AM;
7163 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7164 dp.dwParseFlags |= DP_PM;
7170 TRACE("No matching token for %s\n", debugstr_w(strIn));
7171 hRet = DISP_E_TYPEMISMATCH;
7176 else if (*strIn == ':' || *strIn == '.')
7178 if (!dp.dwCount || !strIn[1])
7179 hRet = DISP_E_TYPEMISMATCH;
7181 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7183 else if (*strIn == '-' || *strIn == '/')
7186 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7187 hRet = DISP_E_TYPEMISMATCH;
7189 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7191 else if (*strIn == ',' || isspaceW(*strIn))
7193 if (*strIn == ',' && !strIn[1])
7194 hRet = DISP_E_TYPEMISMATCH;
7198 hRet = DISP_E_TYPEMISMATCH;
7203 if (!dp.dwCount || dp.dwCount > 6 ||
7204 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7205 hRet = DISP_E_TYPEMISMATCH;
7207 if (SUCCEEDED(hRet))
7210 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7212 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7214 /* Figure out which numbers correspond to which fields.
7216 * This switch statement works based on the fact that native interprets any
7217 * fields that are not joined with a time separator ('.' or ':') as date
7218 * fields. Thus we construct a value from 0-32 where each set bit indicates
7219 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7220 * For valid permutations, we set dwOffset to point to the first date field
7221 * and shorten dp.dwCount by the number of time fields found. The real
7222 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7223 * each date number must represent in the context of iDate.
7225 TRACE("0x%08lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7227 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7229 case 0x1: /* TT TTDD TTDDD */
7230 if (dp.dwCount > 3 &&
7231 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7232 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7233 hRet = DISP_E_TYPEMISMATCH;
7234 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7235 hRet = DISP_E_TYPEMISMATCH;
7236 st.wHour = dp.dwValues[0];
7237 st.wMinute = dp.dwValues[1];
7242 case 0x3: /* TTT TTTDD TTTDDD */
7243 if (dp.dwCount > 4 &&
7244 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7245 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7246 hRet = DISP_E_TYPEMISMATCH;
7247 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7248 hRet = DISP_E_TYPEMISMATCH;
7249 st.wHour = dp.dwValues[0];
7250 st.wMinute = dp.dwValues[1];
7251 st.wSecond = dp.dwValues[2];
7256 case 0x4: /* DDTT */
7257 if (dp.dwCount != 4 ||
7258 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7259 hRet = DISP_E_TYPEMISMATCH;
7261 st.wHour = dp.dwValues[2];
7262 st.wMinute = dp.dwValues[3];
7266 case 0x0: /* T DD DDD TDDD TDDD */
7267 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7269 st.wHour = dp.dwValues[0]; /* T */
7273 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7275 hRet = DISP_E_TYPEMISMATCH;
7277 else if (dp.dwCount == 3)
7279 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7282 st.wHour = dp.dwValues[0];
7286 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7289 st.wHour = dp.dwValues[2];
7292 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7293 hRet = DISP_E_TYPEMISMATCH;
7295 else if (dp.dwCount == 4)
7298 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7300 st.wHour = dp.dwValues[0];
7303 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7305 st.wHour = dp.dwValues[3];
7308 hRet = DISP_E_TYPEMISMATCH;
7311 /* .. fall through .. */
7313 case 0x8: /* DDDTT */
7314 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7315 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7316 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7317 dp.dwCount == 4 || dp.dwCount == 6)
7318 hRet = DISP_E_TYPEMISMATCH;
7319 st.wHour = dp.dwValues[3];
7320 st.wMinute = dp.dwValues[4];
7321 if (dp.dwCount == 5)
7325 case 0xC: /* DDTTT */
7326 if (dp.dwCount != 5 ||
7327 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7328 hRet = DISP_E_TYPEMISMATCH;
7329 st.wHour = dp.dwValues[2];
7330 st.wMinute = dp.dwValues[3];
7331 st.wSecond = dp.dwValues[4];
7335 case 0x18: /* DDDTTT */
7336 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7337 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7338 hRet = DISP_E_TYPEMISMATCH;
7339 st.wHour = dp.dwValues[3];
7340 st.wMinute = dp.dwValues[4];
7341 st.wSecond = dp.dwValues[5];
7346 hRet = DISP_E_TYPEMISMATCH;
7350 if (SUCCEEDED(hRet))
7352 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7354 if (dwFlags & VAR_TIMEVALUEONLY)
7360 else if (dwFlags & VAR_DATEVALUEONLY)
7361 st.wHour = st.wMinute = st.wSecond = 0;
7363 /* Finally, convert the value to a VT_DATE */
7364 if (SUCCEEDED(hRet))
7365 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7369 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7370 SysFreeString(tokens[i]);
7374 /******************************************************************************
7375 * VarDateFromI1 (OLEAUT32.221)
7377 * Convert a VT_I1 to a VT_DATE.
7381 * pdateOut [O] Destination
7386 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7388 return VarR8FromI1(cIn, pdateOut);
7391 /******************************************************************************
7392 * VarDateFromUI2 (OLEAUT32.222)
7394 * Convert a VT_UI2 to a VT_DATE.
7398 * pdateOut [O] Destination
7403 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7405 return VarR8FromUI2(uiIn, pdateOut);
7408 /******************************************************************************
7409 * VarDateFromUI4 (OLEAUT32.223)
7411 * Convert a VT_UI4 to a VT_DATE.
7415 * pdateOut [O] Destination
7420 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7422 return VarDateFromR8(ulIn, pdateOut);
7425 /**********************************************************************
7426 * VarDateFromDec (OLEAUT32.224)
7428 * Convert a VT_DECIMAL to a VT_DATE.
7432 * pdateOut [O] Destination
7437 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
7439 return VarR8FromDec(pdecIn, pdateOut);
7442 /******************************************************************************
7443 * VarDateFromI8 (OLEAUT32.364)
7445 * Convert a VT_I8 to a VT_DATE.
7449 * pdateOut [O] Destination
7453 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7455 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
7457 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
7458 *pdateOut = (DATE)llIn;
7462 /******************************************************************************
7463 * VarDateFromUI8 (OLEAUT32.365)
7465 * Convert a VT_UI8 to a VT_DATE.
7469 * pdateOut [O] Destination
7473 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7475 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
7477 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
7478 *pdateOut = (DATE)ullIn;