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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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;
68 FIXME("VT_ type %d unhandled, please report!\n", vt);
72 /* Macro to inline conversion from a float or double to any integer type,
73 * rounding according to the 'dutch' convention.
75 #define VARIANT_DutchRound(typ, value, res) do { \
76 double whole = value < 0 ? ceil(value) : floor(value); \
77 double fract = value - whole; \
78 if (fract > 0.5) res = (typ)whole + (typ)1; \
79 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
80 else if (fract >= 0.0) res = (typ)whole; \
81 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
82 else if (fract > -0.5) res = (typ)whole; \
83 else res = (typ)whole - (typ)1; \
87 /* Coerce VT_BSTR to a numeric type */
88 static HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
89 void* pOut, VARTYPE vt)
96 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
97 np.cDig = sizeof(rgb) / sizeof(BYTE);
98 np.dwInFlags = NUMPRS_STD;
100 hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
104 /* 1 << vt gives us the VTBIT constant for the destination number type */
105 hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
107 VARIANT_CopyData(&dstVar, vt, pOut);
112 /* Coerce VT_DISPATCH to another type */
113 static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, VARTYPE vt)
115 static const DISPPARAMS emptyParams = { NULL, NULL, 0, 0 };
116 VARIANTARG srcVar, dstVar;
120 return DISP_E_BADVARTYPE;
122 /* Get the default 'value' property from the IDispatch */
123 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
124 (DISPPARAMS*)&emptyParams, &srcVar, NULL, NULL);
128 /* Convert the property to the requested type */
129 V_VT(&dstVar) = VT_EMPTY;
130 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, 0, vt);
131 VariantClear(&srcVar);
135 VARIANT_CopyData(&dstVar, vt, pOut);
136 VariantClear(&srcVar);
140 hRet = DISP_E_TYPEMISMATCH;
144 /* Inline return type */
145 #define RETTYP inline static HRESULT
148 /* Simple compiler cast from one type to another */
149 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
150 *out = in; return S_OK; }
152 /* Compiler cast where input cannot be negative */
153 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
154 if (in < (src)0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
156 /* Compiler cast where input cannot be > some number */
157 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
158 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
160 /* Compiler cast where input cannot be < some number or >= some other number */
161 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
162 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
165 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX);
166 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX);
167 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX);
168 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool);
169 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX);
170 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX);
171 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX);
172 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX);
175 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX);
176 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool);
177 NEGTST(BYTE, signed char, VarUI1FromI1);
178 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX);
179 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX);
180 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX);
181 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX);
182 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX);
185 SIMPLE(SHORT, BYTE, VarI2FromUI1);
186 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX);
187 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool);
188 SIMPLE(SHORT, signed char, VarI2FromI1);
189 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX);
190 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX);
191 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX);
192 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX);
195 SIMPLE(USHORT, BYTE, VarUI2FromUI1);
196 NEGTST(USHORT, SHORT, VarUI2FromI2);
197 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX);
198 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool);
199 NEGTST(USHORT, signed char, VarUI2FromI1);
200 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX);
201 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX);
202 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX);
205 SIMPLE(LONG, BYTE, VarI4FromUI1);
206 SIMPLE(LONG, SHORT, VarI4FromI2);
207 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool);
208 SIMPLE(LONG, signed char, VarI4FromI1);
209 SIMPLE(LONG, USHORT, VarI4FromUI2);
210 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX);
211 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX);
212 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX);
215 SIMPLE(ULONG, BYTE, VarUI4FromUI1);
216 NEGTST(ULONG, SHORT, VarUI4FromI2);
217 NEGTST(ULONG, LONG, VarUI4FromI4);
218 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool);
219 NEGTST(ULONG, signed char, VarUI4FromI1);
220 SIMPLE(ULONG, USHORT, VarUI4FromUI2);
221 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX);
222 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX);
225 SIMPLE(LONG64, BYTE, VarI8FromUI1);
226 SIMPLE(LONG64, SHORT, VarI8FromI2);
227 SIMPLE(LONG64, signed char, VarI8FromI1);
228 SIMPLE(LONG64, USHORT, VarI8FromUI2);
229 SIMPLE(LONG64, LONG, VarI8FromI4);
230 SIMPLE(LONG64, ULONG, VarI8FromUI4);
231 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX);
234 SIMPLE(ULONG64, BYTE, VarUI8FromUI1);
235 NEGTST(ULONG64, SHORT, VarUI8FromI2);
236 NEGTST(ULONG64, signed char, VarUI8FromI1);
237 SIMPLE(ULONG64, USHORT, VarUI8FromUI2);
238 NEGTST(ULONG64, LONG, VarUI8FromI4);
239 SIMPLE(ULONG64, ULONG, VarUI8FromUI4);
240 NEGTST(ULONG64, LONG64, VarUI8FromI8);
243 SIMPLE(float, BYTE, VarR4FromUI1);
244 SIMPLE(float, SHORT, VarR4FromI2);
245 SIMPLE(float, signed char, VarR4FromI1);
246 SIMPLE(float, USHORT, VarR4FromUI2);
247 SIMPLE(float, LONG, VarR4FromI4);
248 SIMPLE(float, ULONG, VarR4FromUI4);
249 SIMPLE(float, LONG64, VarR4FromI8);
250 SIMPLE(float, ULONG64, VarR4FromUI8);
253 SIMPLE(double, BYTE, VarR8FromUI1);
254 SIMPLE(double, SHORT, VarR8FromI2);
255 SIMPLE(double, float, VarR8FromR4);
256 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
257 SIMPLE(double, DATE, VarR8FromDate);
258 SIMPLE(double, signed char, VarR8FromI1);
259 SIMPLE(double, USHORT, VarR8FromUI2);
260 SIMPLE(double, LONG, VarR8FromI4);
261 SIMPLE(double, ULONG, VarR8FromUI4);
262 SIMPLE(double, LONG64, VarR8FromI8);
263 SIMPLE(double, ULONG64, VarR8FromUI8);
269 /************************************************************************
270 * VarI1FromUI1 (OLEAUT32.244)
272 * Convert a VT_UI1 to a VT_I1.
276 * pcOut [O] Destination
280 * Failure: E_INVALIDARG, if the source value is invalid
281 * DISP_E_OVERFLOW, if the value will not fit in the destination
283 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
285 return _VarI1FromUI1(bIn, pcOut);
288 /************************************************************************
289 * VarI1FromI2 (OLEAUT32.245)
291 * Convert a VT_I2 to a VT_I1.
295 * pcOut [O] Destination
299 * Failure: E_INVALIDARG, if the source value is invalid
300 * DISP_E_OVERFLOW, if the value will not fit in the destination
302 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
304 return _VarI1FromI2(sIn, pcOut);
307 /************************************************************************
308 * VarI1FromI4 (OLEAUT32.246)
310 * Convert a VT_I4 to a VT_I1.
314 * pcOut [O] Destination
318 * Failure: E_INVALIDARG, if the source value is invalid
319 * DISP_E_OVERFLOW, if the value will not fit in the destination
321 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
323 return _VarI1FromI4(iIn, pcOut);
326 /************************************************************************
327 * VarI1FromR4 (OLEAUT32.247)
329 * Convert a VT_R4 to a VT_I1.
333 * pcOut [O] Destination
337 * Failure: E_INVALIDARG, if the source value is invalid
338 * DISP_E_OVERFLOW, if the value will not fit in the destination
340 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
342 return VarI1FromR8(fltIn, pcOut);
345 /************************************************************************
346 * VarI1FromR8 (OLEAUT32.248)
348 * Convert a VT_R8 to a VT_I1.
352 * pcOut [O] Destination
356 * Failure: E_INVALIDARG, if the source value is invalid
357 * DISP_E_OVERFLOW, if the value will not fit in the destination
360 * See VarI8FromR8() for details concerning rounding.
362 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
364 if (dblIn < (double)I1_MIN || dblIn > (double)I1_MAX)
365 return DISP_E_OVERFLOW;
366 VARIANT_DutchRound(CHAR, dblIn, *pcOut);
370 /************************************************************************
371 * VarI1FromDate (OLEAUT32.249)
373 * Convert a VT_DATE to a VT_I1.
377 * pcOut [O] Destination
381 * Failure: E_INVALIDARG, if the source value is invalid
382 * DISP_E_OVERFLOW, if the value will not fit in the destination
384 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
386 return VarI1FromR8(dateIn, pcOut);
389 /************************************************************************
390 * VarI1FromCy (OLEAUT32.250)
392 * Convert a VT_CY to a VT_I1.
396 * pcOut [O] Destination
400 * Failure: E_INVALIDARG, if the source value is invalid
401 * DISP_E_OVERFLOW, if the value will not fit in the destination
403 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
407 VarI4FromCy(cyIn, &i);
408 return _VarI1FromI4(i, pcOut);
411 /************************************************************************
412 * VarI1FromStr (OLEAUT32.251)
414 * Convert a VT_BSTR to a VT_I1.
418 * lcid [I] LCID for the conversion
419 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
420 * pcOut [O] Destination
424 * Failure: E_INVALIDARG, if the source value is invalid
425 * DISP_E_OVERFLOW, if the value will not fit in the destination
426 * DISP_E_TYPEMISMATCH, if the type cannot be converted
428 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
430 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
433 /************************************************************************
434 * VarI1FromDisp (OLEAUT32.252)
436 * Convert a VT_DISPATCH to a VT_I1.
440 * lcid [I] LCID for conversion
441 * pcOut [O] Destination
445 * Failure: E_INVALIDARG, if the source value is invalid
446 * DISP_E_OVERFLOW, if the value will not fit in the destination
447 * DISP_E_TYPEMISMATCH, if the type cannot be converted
449 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
451 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1);
454 /************************************************************************
455 * VarI1FromBool (OLEAUT32.253)
457 * Convert a VT_BOOL to a VT_I1.
461 * pcOut [O] Destination
466 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
468 return _VarI1FromBool(boolIn, pcOut);
471 /************************************************************************
472 * VarI1FromUI2 (OLEAUT32.254)
474 * Convert a VT_UI2 to a VT_I1.
478 * pcOut [O] Destination
482 * Failure: E_INVALIDARG, if the source value is invalid
483 * DISP_E_OVERFLOW, if the value will not fit in the destination
485 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
487 return _VarI1FromUI2(usIn, pcOut);
490 /************************************************************************
491 * VarI1FromUI4 (OLEAUT32.255)
493 * Convert a VT_UI4 to a VT_I1.
497 * pcOut [O] Destination
501 * Failure: E_INVALIDARG, if the source value is invalid
502 * DISP_E_OVERFLOW, if the value will not fit in the destination
503 * DISP_E_TYPEMISMATCH, if the type cannot be converted
505 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
507 return _VarI1FromUI4(ulIn, pcOut);
510 /************************************************************************
511 * VarI1FromDec (OLEAUT32.256)
513 * Convert a VT_DECIMAL to a VT_I1.
517 * pcOut [O] Destination
521 * Failure: E_INVALIDARG, if the source value is invalid
522 * DISP_E_OVERFLOW, if the value will not fit in the destination
524 HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut)
529 hRet = VarI8FromDec(pdecIn, &i64);
532 hRet = _VarI1FromI8(i64, pcOut);
536 /************************************************************************
537 * VarI1FromI8 (OLEAUT32.376)
539 * Convert a VT_I8 to a VT_I1.
543 * pcOut [O] Destination
547 * Failure: E_INVALIDARG, if the source value is invalid
548 * DISP_E_OVERFLOW, if the value will not fit in the destination
550 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
552 return _VarI1FromI8(llIn, pcOut);
555 /************************************************************************
556 * VarI1FromUI8 (OLEAUT32.377)
558 * Convert a VT_UI8 to a VT_I1.
562 * pcOut [O] Destination
566 * Failure: E_INVALIDARG, if the source value is invalid
567 * DISP_E_OVERFLOW, if the value will not fit in the destination
569 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
571 return _VarI1FromUI8(ullIn, pcOut);
577 /************************************************************************
578 * VarUI1FromI2 (OLEAUT32.130)
580 * Convert a VT_I2 to a VT_UI1.
584 * pbOut [O] Destination
588 * Failure: E_INVALIDARG, if the source value is invalid
589 * DISP_E_OVERFLOW, if the value will not fit in the destination
591 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
593 return _VarUI1FromI2(sIn, pbOut);
596 /************************************************************************
597 * VarUI1FromI4 (OLEAUT32.131)
599 * Convert a VT_I4 to a VT_UI1.
603 * pbOut [O] Destination
607 * Failure: E_INVALIDARG, if the source value is invalid
608 * DISP_E_OVERFLOW, if the value will not fit in the destination
610 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
612 return _VarUI1FromI4(iIn, pbOut);
615 /************************************************************************
616 * VarUI1FromR4 (OLEAUT32.132)
618 * Convert a VT_R4 to a VT_UI1.
622 * pbOut [O] Destination
626 * Failure: E_INVALIDARG, if the source value is invalid
627 * DISP_E_OVERFLOW, if the value will not fit in the destination
628 * DISP_E_TYPEMISMATCH, if the type cannot be converted
630 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
632 return VarUI1FromR8(fltIn, pbOut);
635 /************************************************************************
636 * VarUI1FromR8 (OLEAUT32.133)
638 * Convert a VT_R8 to a VT_UI1.
642 * pbOut [O] Destination
646 * Failure: E_INVALIDARG, if the source value is invalid
647 * DISP_E_OVERFLOW, if the value will not fit in the destination
650 * See VarI8FromR8() for details concerning rounding.
652 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
654 if (dblIn < -0.5 || dblIn > (double)UI1_MAX)
655 return DISP_E_OVERFLOW;
656 VARIANT_DutchRound(BYTE, dblIn, *pbOut);
660 /************************************************************************
661 * VarUI1FromCy (OLEAUT32.134)
663 * Convert a VT_CY to a VT_UI1.
667 * pbOut [O] Destination
671 * Failure: E_INVALIDARG, if the source value is invalid
672 * DISP_E_OVERFLOW, if the value will not fit in the destination
675 * Negative values >= -5000 will be converted to 0.
677 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
679 ULONG i = UI1_MAX + 1;
681 VarUI4FromCy(cyIn, &i);
682 return _VarUI1FromUI4(i, pbOut);
685 /************************************************************************
686 * VarUI1FromDate (OLEAUT32.135)
688 * Convert a VT_DATE to a VT_UI1.
692 * pbOut [O] Destination
696 * Failure: E_INVALIDARG, if the source value is invalid
697 * DISP_E_OVERFLOW, if the value will not fit in the destination
699 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
701 return VarUI1FromR8(dateIn, pbOut);
704 /************************************************************************
705 * VarUI1FromStr (OLEAUT32.136)
707 * Convert a VT_BSTR to a VT_UI1.
711 * lcid [I] LCID for the conversion
712 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
713 * pbOut [O] Destination
717 * Failure: E_INVALIDARG, if the source value is invalid
718 * DISP_E_OVERFLOW, if the value will not fit in the destination
719 * DISP_E_TYPEMISMATCH, if the type cannot be converted
721 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
723 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
726 /************************************************************************
727 * VarUI1FromDisp (OLEAUT32.137)
729 * Convert a VT_DISPATCH to a VT_UI1.
733 * lcid [I] LCID for conversion
734 * pbOut [O] Destination
738 * Failure: E_INVALIDARG, if the source value is invalid
739 * DISP_E_OVERFLOW, if the value will not fit in the destination
740 * DISP_E_TYPEMISMATCH, if the type cannot be converted
742 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
744 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1);
747 /************************************************************************
748 * VarUI1FromBool (OLEAUT32.138)
750 * Convert a VT_BOOL to a VT_UI1.
754 * pbOut [O] Destination
759 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
761 return _VarUI1FromBool(boolIn, pbOut);
764 /************************************************************************
765 * VarUI1FromI1 (OLEAUT32.237)
767 * Convert a VT_I1 to a VT_UI1.
771 * pbOut [O] Destination
775 * Failure: E_INVALIDARG, if the source value is invalid
776 * DISP_E_OVERFLOW, if the value will not fit in the destination
778 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
780 return _VarUI1FromI1(cIn, pbOut);
783 /************************************************************************
784 * VarUI1FromUI2 (OLEAUT32.238)
786 * Convert a VT_UI2 to a VT_UI1.
790 * pbOut [O] Destination
794 * Failure: E_INVALIDARG, if the source value is invalid
795 * DISP_E_OVERFLOW, if the value will not fit in the destination
797 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
799 return _VarUI1FromUI2(usIn, pbOut);
802 /************************************************************************
803 * VarUI1FromUI4 (OLEAUT32.239)
805 * Convert a VT_UI4 to a VT_UI1.
809 * pbOut [O] Destination
813 * Failure: E_INVALIDARG, if the source value is invalid
814 * DISP_E_OVERFLOW, if the value will not fit in the destination
816 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
818 return _VarUI1FromUI4(ulIn, pbOut);
821 /************************************************************************
822 * VarUI1FromDec (OLEAUT32.240)
824 * Convert a VT_DECIMAL to a VT_UI1.
828 * pbOut [O] Destination
832 * Failure: E_INVALIDARG, if the source value is invalid
833 * DISP_E_OVERFLOW, if the value will not fit in the destination
835 HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut)
840 hRet = VarI8FromDec(pdecIn, &i64);
843 hRet = _VarUI1FromI8(i64, pbOut);
847 /************************************************************************
848 * VarUI1FromI8 (OLEAUT32.372)
850 * Convert a VT_I8 to a VT_UI1.
854 * pbOut [O] Destination
858 * Failure: E_INVALIDARG, if the source value is invalid
859 * DISP_E_OVERFLOW, if the value will not fit in the destination
861 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
863 return _VarUI1FromI8(llIn, pbOut);
866 /************************************************************************
867 * VarUI1FromUI8 (OLEAUT32.373)
869 * Convert a VT_UI8 to a VT_UI1.
873 * pbOut [O] Destination
877 * Failure: E_INVALIDARG, if the source value is invalid
878 * DISP_E_OVERFLOW, if the value will not fit in the destination
880 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
882 return _VarUI1FromUI8(ullIn, pbOut);
889 /************************************************************************
890 * VarI2FromUI1 (OLEAUT32.48)
892 * Convert a VT_UI2 to a VT_I2.
896 * psOut [O] Destination
901 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
903 return _VarI2FromUI1(bIn, psOut);
906 /************************************************************************
907 * VarI2FromI4 (OLEAUT32.49)
909 * Convert a VT_I4 to a VT_I2.
913 * psOut [O] Destination
917 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
919 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
921 return _VarI2FromI4(iIn, psOut);
924 /************************************************************************
925 * VarI2FromR4 (OLEAUT32.50)
927 * Convert a VT_R4 to a VT_I2.
931 * psOut [O] Destination
935 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
937 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
939 return VarI2FromR8(fltIn, psOut);
942 /************************************************************************
943 * VarI2FromR8 (OLEAUT32.51)
945 * Convert a VT_R8 to a VT_I2.
949 * psOut [O] Destination
953 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
956 * See VarI8FromR8() for details concerning rounding.
958 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
960 if (dblIn < (double)I2_MIN || dblIn > (double)I2_MAX)
961 return DISP_E_OVERFLOW;
962 VARIANT_DutchRound(SHORT, dblIn, *psOut);
966 /************************************************************************
967 * VarI2FromCy (OLEAUT32.52)
969 * Convert a VT_CY to a VT_I2.
973 * psOut [O] Destination
977 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
979 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
983 VarI4FromCy(cyIn, &i);
984 return _VarI2FromI4(i, psOut);
987 /************************************************************************
988 * VarI2FromDate (OLEAUT32.53)
990 * Convert a VT_DATE to a VT_I2.
994 * psOut [O] Destination
998 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1000 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
1002 return VarI2FromR8(dateIn, psOut);
1005 /************************************************************************
1006 * VarI2FromStr (OLEAUT32.54)
1008 * Convert a VT_BSTR to a VT_I2.
1012 * lcid [I] LCID for the conversion
1013 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1014 * psOut [O] Destination
1018 * Failure: E_INVALIDARG, if any parameter is invalid
1019 * DISP_E_OVERFLOW, if the value will not fit in the destination
1020 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1022 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
1024 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
1027 /************************************************************************
1028 * VarI2FromDisp (OLEAUT32.55)
1030 * Convert a VT_DISPATCH to a VT_I2.
1033 * pdispIn [I] Source
1034 * lcid [I] LCID for conversion
1035 * psOut [O] Destination
1039 * Failure: E_INVALIDARG, if pdispIn is invalid,
1040 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1041 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1043 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
1045 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2);
1048 /************************************************************************
1049 * VarI2FromBool (OLEAUT32.56)
1051 * Convert a VT_BOOL to a VT_I2.
1055 * psOut [O] Destination
1060 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
1062 return _VarI2FromBool(boolIn, psOut);
1065 /************************************************************************
1066 * VarI2FromI1 (OLEAUT32.205)
1068 * Convert a VT_I1 to a VT_I2.
1072 * psOut [O] Destination
1077 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
1079 return _VarI2FromI1(cIn, psOut);
1082 /************************************************************************
1083 * VarI2FromUI2 (OLEAUT32.206)
1085 * Convert a VT_UI2 to a VT_I2.
1089 * psOut [O] Destination
1093 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1095 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
1097 return _VarI2FromUI2(usIn, psOut);
1100 /************************************************************************
1101 * VarI2FromUI4 (OLEAUT32.207)
1103 * Convert a VT_UI4 to a VT_I2.
1107 * psOut [O] Destination
1111 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1113 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
1115 return _VarI2FromUI4(ulIn, psOut);
1118 /************************************************************************
1119 * VarI2FromDec (OLEAUT32.208)
1121 * Convert a VT_DECIMAL to a VT_I2.
1125 * psOut [O] Destination
1129 * Failure: E_INVALIDARG, if the source value is invalid
1130 * DISP_E_OVERFLOW, if the value will not fit in the destination
1132 HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut)
1137 hRet = VarI8FromDec(pdecIn, &i64);
1139 if (SUCCEEDED(hRet))
1140 hRet = _VarI2FromI8(i64, psOut);
1144 /************************************************************************
1145 * VarI2FromI8 (OLEAUT32.346)
1147 * Convert a VT_I8 to a VT_I2.
1151 * psOut [O] Destination
1155 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1157 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
1159 return _VarI2FromI8(llIn, psOut);
1162 /************************************************************************
1163 * VarI2FromUI8 (OLEAUT32.347)
1165 * Convert a VT_UI8 to a VT_I2.
1169 * psOut [O] Destination
1173 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1175 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
1177 return _VarI2FromUI8(ullIn, psOut);
1183 /************************************************************************
1184 * VarUI2FromUI1 (OLEAUT32.257)
1186 * Convert a VT_UI1 to a VT_UI2.
1190 * pusOut [O] Destination
1195 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
1197 return _VarUI2FromUI1(bIn, pusOut);
1200 /************************************************************************
1201 * VarUI2FromI2 (OLEAUT32.258)
1203 * Convert a VT_I2 to a VT_UI2.
1207 * pusOut [O] Destination
1211 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1213 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
1215 return _VarUI2FromI2(sIn, pusOut);
1218 /************************************************************************
1219 * VarUI2FromI4 (OLEAUT32.259)
1221 * Convert a VT_I4 to a VT_UI2.
1225 * pusOut [O] Destination
1229 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1231 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
1233 return _VarUI2FromI4(iIn, pusOut);
1236 /************************************************************************
1237 * VarUI2FromR4 (OLEAUT32.260)
1239 * Convert a VT_R4 to a VT_UI2.
1243 * pusOut [O] Destination
1247 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1249 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
1251 return VarUI2FromR8(fltIn, pusOut);
1254 /************************************************************************
1255 * VarUI2FromR8 (OLEAUT32.261)
1257 * Convert a VT_R8 to a VT_UI2.
1261 * pusOut [O] Destination
1265 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1268 * See VarI8FromR8() for details concerning rounding.
1270 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
1272 if (dblIn < -0.5 || dblIn > (double)UI2_MAX)
1273 return DISP_E_OVERFLOW;
1274 VARIANT_DutchRound(USHORT, dblIn, *pusOut);
1278 /************************************************************************
1279 * VarUI2FromDate (OLEAUT32.262)
1281 * Convert a VT_DATE to a VT_UI2.
1285 * pusOut [O] Destination
1289 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1291 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
1293 return VarUI2FromR8(dateIn, pusOut);
1296 /************************************************************************
1297 * VarUI2FromCy (OLEAUT32.263)
1299 * Convert a VT_CY to a VT_UI2.
1303 * pusOut [O] Destination
1307 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1310 * Negative values >= -5000 will be converted to 0.
1312 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
1314 ULONG i = UI2_MAX + 1;
1316 VarUI4FromCy(cyIn, &i);
1317 return _VarUI2FromUI4(i, pusOut);
1320 /************************************************************************
1321 * VarUI2FromStr (OLEAUT32.264)
1323 * Convert a VT_BSTR to a VT_UI2.
1327 * lcid [I] LCID for the conversion
1328 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1329 * pusOut [O] Destination
1333 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1334 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1336 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
1338 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
1341 /************************************************************************
1342 * VarUI2FromDisp (OLEAUT32.265)
1344 * Convert a VT_DISPATCH to a VT_UI2.
1347 * pdispIn [I] Source
1348 * lcid [I] LCID for conversion
1349 * pusOut [O] Destination
1353 * Failure: E_INVALIDARG, if the source value is invalid
1354 * DISP_E_OVERFLOW, if the value will not fit in the destination
1355 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1357 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
1359 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2);
1362 /************************************************************************
1363 * VarUI2FromBool (OLEAUT32.266)
1365 * Convert a VT_BOOL to a VT_UI2.
1369 * pusOut [O] Destination
1374 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
1376 return _VarUI2FromBool(boolIn, pusOut);
1379 /************************************************************************
1380 * VarUI2FromI1 (OLEAUT32.267)
1382 * Convert a VT_I1 to a VT_UI2.
1386 * pusOut [O] Destination
1390 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1392 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
1394 return _VarUI2FromI1(cIn, pusOut);
1397 /************************************************************************
1398 * VarUI2FromUI4 (OLEAUT32.268)
1400 * Convert a VT_UI4 to a VT_UI2.
1404 * pusOut [O] Destination
1408 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1410 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
1412 return _VarUI2FromUI4(ulIn, pusOut);
1415 /************************************************************************
1416 * VarUI2FromDec (OLEAUT32.269)
1418 * Convert a VT_DECIMAL to a VT_UI2.
1422 * pusOut [O] Destination
1426 * Failure: E_INVALIDARG, if the source value is invalid
1427 * DISP_E_OVERFLOW, if the value will not fit in the destination
1429 HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut)
1434 hRet = VarI8FromDec(pdecIn, &i64);
1436 if (SUCCEEDED(hRet))
1437 hRet = _VarUI2FromI8(i64, pusOut);
1441 /************************************************************************
1442 * VarUI2FromI8 (OLEAUT32.378)
1444 * Convert a VT_I8 to a VT_UI2.
1448 * pusOut [O] Destination
1452 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1454 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
1456 return _VarUI2FromI8(llIn, pusOut);
1459 /************************************************************************
1460 * VarUI2FromUI8 (OLEAUT32.379)
1462 * Convert a VT_UI8 to a VT_UI2.
1466 * pusOut [O] Destination
1470 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1472 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
1474 return _VarUI2FromUI8(ullIn, pusOut);
1480 /************************************************************************
1481 * VarI4FromUI1 (OLEAUT32.58)
1483 * Convert a VT_UI1 to a VT_I4.
1487 * piOut [O] Destination
1492 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
1494 return _VarI4FromUI1(bIn, piOut);
1497 /************************************************************************
1498 * VarI4FromI2 (OLEAUT32.59)
1500 * Convert a VT_I2 to a VT_I4.
1504 * piOut [O] Destination
1508 * Failure: E_INVALIDARG, if the source value is invalid
1509 * DISP_E_OVERFLOW, if the value will not fit in the destination
1511 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
1513 return _VarI4FromI2(sIn, piOut);
1516 /************************************************************************
1517 * VarI4FromR4 (OLEAUT32.60)
1519 * Convert a VT_R4 to a VT_I4.
1523 * piOut [O] Destination
1527 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1529 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
1531 return VarI4FromR8(fltIn, piOut);
1534 /************************************************************************
1535 * VarI4FromR8 (OLEAUT32.61)
1537 * Convert a VT_R8 to a VT_I4.
1541 * piOut [O] Destination
1545 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1548 * See VarI8FromR8() for details concerning rounding.
1550 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
1552 if (dblIn < (double)I4_MIN || dblIn > (double)I4_MAX)
1553 return DISP_E_OVERFLOW;
1554 VARIANT_DutchRound(LONG, dblIn, *piOut);
1558 /************************************************************************
1559 * VarI4FromCy (OLEAUT32.62)
1561 * Convert a VT_CY to a VT_I4.
1565 * piOut [O] Destination
1569 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1571 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
1573 double d = cyIn.int64 / CY_MULTIPLIER_F;
1574 return VarI4FromR8(d, piOut);
1577 /************************************************************************
1578 * VarI4FromDate (OLEAUT32.63)
1580 * Convert a VT_DATE to a VT_I4.
1584 * piOut [O] Destination
1588 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1590 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
1592 return VarI4FromR8(dateIn, piOut);
1595 /************************************************************************
1596 * VarI4FromStr (OLEAUT32.64)
1598 * Convert a VT_BSTR to a VT_I4.
1602 * lcid [I] LCID for the conversion
1603 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1604 * piOut [O] Destination
1608 * Failure: E_INVALIDARG, if any parameter is invalid
1609 * DISP_E_OVERFLOW, if the value will not fit in the destination
1610 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1612 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
1614 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
1617 /************************************************************************
1618 * VarI4FromDisp (OLEAUT32.65)
1620 * Convert a VT_DISPATCH to a VT_I4.
1623 * pdispIn [I] Source
1624 * lcid [I] LCID for conversion
1625 * piOut [O] Destination
1629 * Failure: E_INVALIDARG, if the source value is invalid
1630 * DISP_E_OVERFLOW, if the value will not fit in the destination
1631 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1633 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
1635 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4);
1638 /************************************************************************
1639 * VarI4FromBool (OLEAUT32.66)
1641 * Convert a VT_BOOL to a VT_I4.
1645 * piOut [O] Destination
1650 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
1652 return _VarI4FromBool(boolIn, piOut);
1655 /************************************************************************
1656 * VarI4FromI1 (OLEAUT32.209)
1658 * Convert a VT_I4 to a VT_I4.
1662 * piOut [O] Destination
1667 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
1669 return _VarI4FromI1(cIn, piOut);
1672 /************************************************************************
1673 * VarI4FromUI2 (OLEAUT32.210)
1675 * Convert a VT_UI2 to a VT_I4.
1679 * piOut [O] Destination
1684 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
1686 return _VarI4FromUI2(usIn, piOut);
1689 /************************************************************************
1690 * VarI4FromUI4 (OLEAUT32.211)
1692 * Convert a VT_UI4 to a VT_I4.
1696 * piOut [O] Destination
1700 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1702 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
1704 return _VarI4FromUI4(ulIn, piOut);
1707 /************************************************************************
1708 * VarI4FromDec (OLEAUT32.212)
1710 * Convert a VT_DECIMAL to a VT_I4.
1714 * piOut [O] Destination
1718 * Failure: E_INVALIDARG, if pdecIn is invalid
1719 * DISP_E_OVERFLOW, if the value will not fit in the destination
1721 HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut)
1726 hRet = VarI8FromDec(pdecIn, &i64);
1728 if (SUCCEEDED(hRet))
1729 hRet = _VarI4FromI8(i64, piOut);
1733 /************************************************************************
1734 * VarI4FromI8 (OLEAUT32.348)
1736 * Convert a VT_I8 to a VT_I4.
1740 * piOut [O] Destination
1744 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1746 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
1748 return _VarI4FromI8(llIn, piOut);
1751 /************************************************************************
1752 * VarI4FromUI8 (OLEAUT32.349)
1754 * Convert a VT_UI8 to a VT_I4.
1758 * piOut [O] Destination
1762 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1764 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
1766 return _VarI4FromUI8(ullIn, piOut);
1772 /************************************************************************
1773 * VarUI4FromUI1 (OLEAUT32.270)
1775 * Convert a VT_UI1 to a VT_UI4.
1779 * pulOut [O] Destination
1784 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
1786 return _VarUI4FromUI1(bIn, pulOut);
1789 /************************************************************************
1790 * VarUI4FromI2 (OLEAUT32.271)
1792 * Convert a VT_I2 to a VT_UI4.
1796 * pulOut [O] Destination
1800 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1802 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
1804 return _VarUI4FromI2(sIn, pulOut);
1807 /************************************************************************
1808 * VarUI4FromI4 (OLEAUT32.272)
1810 * Convert a VT_I4 to a VT_UI4.
1814 * pulOut [O] Destination
1818 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1820 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
1822 return _VarUI4FromI4(iIn, pulOut);
1825 /************************************************************************
1826 * VarUI4FromR4 (OLEAUT32.273)
1828 * Convert a VT_R4 to a VT_UI4.
1832 * pulOut [O] Destination
1836 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1838 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
1840 return VarUI4FromR8(fltIn, pulOut);
1843 /************************************************************************
1844 * VarUI4FromR8 (OLEAUT32.274)
1846 * Convert a VT_R8 to a VT_UI4.
1850 * pulOut [O] Destination
1854 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1857 * See VarI8FromR8() for details concerning rounding.
1859 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
1861 if (dblIn < -0.5 || dblIn > (double)UI4_MAX)
1862 return DISP_E_OVERFLOW;
1863 VARIANT_DutchRound(ULONG, dblIn, *pulOut);
1867 /************************************************************************
1868 * VarUI4FromDate (OLEAUT32.275)
1870 * Convert a VT_DATE to a VT_UI4.
1874 * pulOut [O] Destination
1878 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1880 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
1882 return VarUI4FromR8(dateIn, pulOut);
1885 /************************************************************************
1886 * VarUI4FromCy (OLEAUT32.276)
1888 * Convert a VT_CY to a VT_UI4.
1892 * pulOut [O] Destination
1896 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1898 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
1900 double d = cyIn.int64 / CY_MULTIPLIER_F;
1901 return VarUI4FromR8(d, pulOut);
1904 /************************************************************************
1905 * VarUI4FromStr (OLEAUT32.277)
1907 * Convert a VT_BSTR to a VT_UI4.
1911 * lcid [I] LCID for the conversion
1912 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1913 * pulOut [O] Destination
1917 * Failure: E_INVALIDARG, if any parameter is invalid
1918 * DISP_E_OVERFLOW, if the value will not fit in the destination
1919 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1921 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
1923 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
1926 /************************************************************************
1927 * VarUI4FromDisp (OLEAUT32.278)
1929 * Convert a VT_DISPATCH to a VT_UI4.
1932 * pdispIn [I] Source
1933 * lcid [I] LCID for conversion
1934 * pulOut [O] Destination
1938 * Failure: E_INVALIDARG, if the source value is invalid
1939 * DISP_E_OVERFLOW, if the value will not fit in the destination
1940 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1942 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
1944 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4);
1947 /************************************************************************
1948 * VarUI4FromBool (OLEAUT32.279)
1950 * Convert a VT_BOOL to a VT_UI4.
1954 * pulOut [O] Destination
1959 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
1961 return _VarUI4FromBool(boolIn, pulOut);
1964 /************************************************************************
1965 * VarUI4FromI1 (OLEAUT32.280)
1967 * Convert a VT_I1 to a VT_UI4.
1971 * pulOut [O] Destination
1975 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1977 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
1979 return _VarUI4FromI1(cIn, pulOut);
1982 /************************************************************************
1983 * VarUI4FromUI2 (OLEAUT32.281)
1985 * Convert a VT_UI2 to a VT_UI4.
1989 * pulOut [O] Destination
1994 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
1996 return _VarUI4FromUI2(usIn, pulOut);
1999 /************************************************************************
2000 * VarUI4FromDec (OLEAUT32.282)
2002 * Convert a VT_DECIMAL to a VT_UI4.
2006 * pulOut [O] Destination
2010 * Failure: E_INVALIDARG, if pdecIn is invalid
2011 * DISP_E_OVERFLOW, if the value will not fit in the destination
2013 HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut)
2018 hRet = VarI8FromDec(pdecIn, &i64);
2020 if (SUCCEEDED(hRet))
2021 hRet = _VarUI4FromI8(i64, pulOut);
2025 /************************************************************************
2026 * VarUI4FromI8 (OLEAUT32.425)
2028 * Convert a VT_I8 to a VT_UI4.
2032 * pulOut [O] Destination
2036 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2038 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
2040 return _VarUI4FromI8(llIn, pulOut);
2043 /************************************************************************
2044 * VarUI4FromUI8 (OLEAUT32.426)
2046 * Convert a VT_UI8 to a VT_UI4.
2050 * pulOut [O] Destination
2054 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2056 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
2058 return _VarUI4FromUI8(ullIn, pulOut);
2064 /************************************************************************
2065 * VarI8FromUI1 (OLEAUT32.333)
2067 * Convert a VT_UI1 to a VT_I8.
2071 * pi64Out [O] Destination
2076 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
2078 return _VarI8FromUI1(bIn, pi64Out);
2082 /************************************************************************
2083 * VarI8FromI2 (OLEAUT32.334)
2085 * Convert a VT_I2 to a VT_I8.
2089 * pi64Out [O] Destination
2094 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
2096 return _VarI8FromI2(sIn, pi64Out);
2099 /************************************************************************
2100 * VarI8FromR4 (OLEAUT32.335)
2102 * Convert a VT_R4 to a VT_I8.
2106 * pi64Out [O] Destination
2110 * Failure: E_INVALIDARG, if the source value is invalid
2111 * DISP_E_OVERFLOW, if the value will not fit in the destination
2113 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
2115 return VarI8FromR8(fltIn, pi64Out);
2118 /************************************************************************
2119 * VarI8FromR8 (OLEAUT32.336)
2121 * Convert a VT_R8 to a VT_I8.
2125 * pi64Out [O] Destination
2129 * Failure: E_INVALIDARG, if the source value is invalid
2130 * DISP_E_OVERFLOW, if the value will not fit in the destination
2133 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2134 * very high or low values will not be accurately converted.
2136 * Numbers are rounded using Dutch rounding, as follows:
2138 *| Fractional Part Sign Direction Example
2139 *| --------------- ---- --------- -------
2140 *| < 0.5 + Down 0.4 -> 0.0
2141 *| < 0.5 - Up -0.4 -> 0.0
2142 *| > 0.5 + Up 0.6 -> 1.0
2143 *| < 0.5 - Up -0.6 -> -1.0
2144 *| = 0.5 + Up/Down Down if even, Up if odd
2145 *| = 0.5 - Up/Down Up if even, Down if odd
2147 * This system is often used in supermarkets.
2149 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
2151 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
2152 return DISP_E_OVERFLOW;
2153 VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
2157 /************************************************************************
2158 * VarI8FromCy (OLEAUT32.337)
2160 * Convert a VT_CY to a VT_I8.
2164 * pi64Out [O] Destination
2170 * All negative numbers are rounded down by 1, including those that are
2171 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2172 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2175 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
2177 *pi64Out = cyIn.int64 / CY_MULTIPLIER;
2180 (*pi64Out)--; /* Mimic Win32 bug */
2183 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2185 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1)))
2191 /************************************************************************
2192 * VarI8FromDate (OLEAUT32.338)
2194 * Convert a VT_DATE to a VT_I8.
2198 * pi64Out [O] Destination
2202 * Failure: E_INVALIDARG, if the source value is invalid
2203 * DISP_E_OVERFLOW, if the value will not fit in the destination
2204 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2206 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
2208 return VarI8FromR8(dateIn, pi64Out);
2211 /************************************************************************
2212 * VarI8FromStr (OLEAUT32.339)
2214 * Convert a VT_BSTR to a VT_I8.
2218 * lcid [I] LCID for the conversion
2219 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2220 * pi64Out [O] Destination
2224 * Failure: E_INVALIDARG, if the source value is invalid
2225 * DISP_E_OVERFLOW, if the value will not fit in the destination
2226 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2228 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
2230 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
2233 /************************************************************************
2234 * VarI8FromDisp (OLEAUT32.340)
2236 * Convert a VT_DISPATCH to a VT_I8.
2239 * pdispIn [I] Source
2240 * lcid [I] LCID for conversion
2241 * pi64Out [O] Destination
2245 * Failure: E_INVALIDARG, if the source value is invalid
2246 * DISP_E_OVERFLOW, if the value will not fit in the destination
2247 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2249 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
2251 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8);
2254 /************************************************************************
2255 * VarI8FromBool (OLEAUT32.341)
2257 * Convert a VT_BOOL to a VT_I8.
2261 * pi64Out [O] Destination
2266 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
2268 return VarI8FromI2(boolIn, pi64Out);
2271 /************************************************************************
2272 * VarI8FromI1 (OLEAUT32.342)
2274 * Convert a VT_I1 to a VT_I8.
2278 * pi64Out [O] Destination
2283 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
2285 return _VarI8FromI1(cIn, pi64Out);
2288 /************************************************************************
2289 * VarI8FromUI2 (OLEAUT32.343)
2291 * Convert a VT_UI2 to a VT_I8.
2295 * pi64Out [O] Destination
2300 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
2302 return _VarI8FromUI2(usIn, pi64Out);
2305 /************************************************************************
2306 * VarI8FromUI4 (OLEAUT32.344)
2308 * Convert a VT_UI4 to a VT_I8.
2312 * pi64Out [O] Destination
2317 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
2319 return _VarI8FromUI4(ulIn, pi64Out);
2322 /************************************************************************
2323 * VarI8FromDec (OLEAUT32.345)
2325 * Convert a VT_DECIMAL to a VT_I8.
2329 * pi64Out [O] Destination
2333 * Failure: E_INVALIDARG, if the source value is invalid
2334 * DISP_E_OVERFLOW, if the value will not fit in the destination
2336 HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out)
2338 if (!DEC_SCALE(pdecIn))
2340 /* This decimal is just a 96 bit integer */
2341 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2342 return E_INVALIDARG;
2344 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000)
2345 return DISP_E_OVERFLOW;
2347 if (DEC_SIGN(pdecIn))
2348 *pi64Out = -DEC_LO64(pdecIn);
2350 *pi64Out = DEC_LO64(pdecIn);
2355 /* Decimal contains a floating point number */
2359 hRet = VarR8FromDec(pdecIn, &dbl);
2360 if (SUCCEEDED(hRet))
2361 hRet = VarI8FromR8(dbl, pi64Out);
2366 /************************************************************************
2367 * VarI8FromUI8 (OLEAUT32.427)
2369 * Convert a VT_UI8 to a VT_I8.
2373 * pi64Out [O] Destination
2377 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2379 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
2381 return _VarI8FromUI8(ullIn, pi64Out);
2387 /************************************************************************
2388 * VarUI8FromI8 (OLEAUT32.428)
2390 * Convert a VT_I8 to a VT_UI8.
2394 * pui64Out [O] Destination
2398 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2400 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
2402 return _VarUI8FromI8(llIn, pui64Out);
2405 /************************************************************************
2406 * VarUI8FromUI1 (OLEAUT32.429)
2408 * Convert a VT_UI1 to a VT_UI8.
2412 * pui64Out [O] Destination
2417 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
2419 return _VarUI8FromUI1(bIn, pui64Out);
2422 /************************************************************************
2423 * VarUI8FromI2 (OLEAUT32.430)
2425 * Convert a VT_I2 to a VT_UI8.
2429 * pui64Out [O] Destination
2434 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
2436 return _VarUI8FromI2(sIn, pui64Out);
2439 /************************************************************************
2440 * VarUI8FromR4 (OLEAUT32.431)
2442 * Convert a VT_R4 to a VT_UI8.
2446 * pui64Out [O] Destination
2450 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2452 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
2454 return VarUI8FromR8(fltIn, pui64Out);
2457 /************************************************************************
2458 * VarUI8FromR8 (OLEAUT32.432)
2460 * Convert a VT_R8 to a VT_UI8.
2464 * pui64Out [O] Destination
2468 * Failure: E_INVALIDARG, if the source value is invalid
2469 * DISP_E_OVERFLOW, if the value will not fit in the destination
2472 * See VarI8FromR8() for details concerning rounding.
2474 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
2476 if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
2477 return DISP_E_OVERFLOW;
2478 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
2482 /************************************************************************
2483 * VarUI8FromCy (OLEAUT32.433)
2485 * Convert a VT_CY to a VT_UI8.
2489 * pui64Out [O] Destination
2493 * Failure: E_INVALIDARG, if the source value is invalid
2494 * DISP_E_OVERFLOW, if the value will not fit in the destination
2497 * Negative values >= -5000 will be converted to 0.
2499 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
2503 if (cyIn.int64 < -CY_HALF)
2504 return DISP_E_OVERFLOW;
2509 *pui64Out = cyIn.int64 / CY_MULTIPLIER;
2511 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2513 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1)))
2519 /************************************************************************
2520 * VarUI8FromDate (OLEAUT32.434)
2522 * Convert a VT_DATE to a VT_UI8.
2526 * pui64Out [O] Destination
2530 * Failure: E_INVALIDARG, if the source value is invalid
2531 * DISP_E_OVERFLOW, if the value will not fit in the destination
2532 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2534 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
2536 return VarUI8FromR8(dateIn, pui64Out);
2539 /************************************************************************
2540 * VarUI8FromStr (OLEAUT32.435)
2542 * Convert a VT_BSTR to a VT_UI8.
2546 * lcid [I] LCID for the conversion
2547 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2548 * pui64Out [O] Destination
2552 * Failure: E_INVALIDARG, if the source value is invalid
2553 * DISP_E_OVERFLOW, if the value will not fit in the destination
2554 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2556 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
2558 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
2561 /************************************************************************
2562 * VarUI8FromDisp (OLEAUT32.436)
2564 * Convert a VT_DISPATCH to a VT_UI8.
2567 * pdispIn [I] Source
2568 * lcid [I] LCID for conversion
2569 * pui64Out [O] Destination
2573 * Failure: E_INVALIDARG, if the source value is invalid
2574 * DISP_E_OVERFLOW, if the value will not fit in the destination
2575 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2577 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
2579 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8);
2582 /************************************************************************
2583 * VarUI8FromBool (OLEAUT32.437)
2585 * Convert a VT_BOOL to a VT_UI8.
2589 * pui64Out [O] Destination
2593 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2595 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
2597 return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
2599 /************************************************************************
2600 * VarUI8FromI1 (OLEAUT32.438)
2602 * Convert a VT_I1 to a VT_UI8.
2606 * pui64Out [O] Destination
2610 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2612 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
2614 return _VarUI8FromI1(cIn, pui64Out);
2617 /************************************************************************
2618 * VarUI8FromUI2 (OLEAUT32.439)
2620 * Convert a VT_UI2 to a VT_UI8.
2624 * pui64Out [O] Destination
2629 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
2631 return _VarUI8FromUI2(usIn, pui64Out);
2634 /************************************************************************
2635 * VarUI8FromUI4 (OLEAUT32.440)
2637 * Convert a VT_UI4 to a VT_UI8.
2641 * pui64Out [O] Destination
2646 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
2648 return _VarUI8FromUI4(ulIn, pui64Out);
2651 /************************************************************************
2652 * VarUI8FromDec (OLEAUT32.441)
2654 * Convert a VT_DECIMAL to a VT_UI8.
2658 * pui64Out [O] Destination
2662 * Failure: E_INVALIDARG, if the source value is invalid
2663 * DISP_E_OVERFLOW, if the value will not fit in the destination
2666 * Under native Win32, if the source value has a scale of 0, its sign is
2667 * ignored, i.e. this function takes the absolute value rather than fail
2668 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2669 * (use VarAbs() on pDecIn first if you really want this behaviour).
2671 HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out)
2673 if (!DEC_SCALE(pdecIn))
2675 /* This decimal is just a 96 bit integer */
2676 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2677 return E_INVALIDARG;
2679 if (DEC_HI32(pdecIn))
2680 return DISP_E_OVERFLOW;
2682 if (DEC_SIGN(pdecIn))
2684 WARN("Sign would be ignored under Win32!\n");
2685 return DISP_E_OVERFLOW;
2688 *pui64Out = DEC_LO64(pdecIn);
2693 /* Decimal contains a floating point number */
2697 hRet = VarR8FromDec(pdecIn, &dbl);
2698 if (SUCCEEDED(hRet))
2699 hRet = VarUI8FromR8(dbl, pui64Out);
2707 /************************************************************************
2708 * VarR4FromUI1 (OLEAUT32.68)
2710 * Convert a VT_UI1 to a VT_R4.
2714 * pFltOut [O] Destination
2719 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
2721 return _VarR4FromUI1(bIn, pFltOut);
2724 /************************************************************************
2725 * VarR4FromI2 (OLEAUT32.69)
2727 * Convert a VT_I2 to a VT_R4.
2731 * pFltOut [O] Destination
2736 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
2738 return _VarR4FromI2(sIn, pFltOut);
2741 /************************************************************************
2742 * VarR4FromI4 (OLEAUT32.70)
2744 * Convert a VT_I4 to a VT_R4.
2748 * pFltOut [O] Destination
2753 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
2755 return _VarR4FromI4(lIn, pFltOut);
2758 /************************************************************************
2759 * VarR4FromR8 (OLEAUT32.71)
2761 * Convert a VT_R8 to a VT_R4.
2765 * pFltOut [O] Destination
2769 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2771 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
2773 double d = dblIn < 0.0 ? -dblIn : dblIn;
2774 if (d > R4_MAX) return DISP_E_OVERFLOW;
2779 /************************************************************************
2780 * VarR4FromCy (OLEAUT32.72)
2782 * Convert a VT_CY to a VT_R4.
2786 * pFltOut [O] Destination
2791 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
2793 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
2797 /************************************************************************
2798 * VarR4FromDate (OLEAUT32.73)
2800 * Convert a VT_DATE to a VT_R4.
2804 * pFltOut [O] Destination
2808 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2810 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
2812 return VarR4FromR8(dateIn, pFltOut);
2815 /************************************************************************
2816 * VarR4FromStr (OLEAUT32.74)
2818 * Convert a VT_BSTR to a VT_R4.
2822 * lcid [I] LCID for the conversion
2823 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2824 * pFltOut [O] Destination
2828 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2829 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2831 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
2833 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
2836 /************************************************************************
2837 * VarR4FromDisp (OLEAUT32.75)
2839 * Convert a VT_DISPATCH to a VT_R4.
2842 * pdispIn [I] Source
2843 * lcid [I] LCID for conversion
2844 * pFltOut [O] Destination
2848 * Failure: E_INVALIDARG, if the source value is invalid
2849 * DISP_E_OVERFLOW, if the value will not fit in the destination
2850 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2852 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
2854 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4);
2857 /************************************************************************
2858 * VarR4FromBool (OLEAUT32.76)
2860 * Convert a VT_BOOL to a VT_R4.
2864 * pFltOut [O] Destination
2869 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2871 return VarR4FromI2(boolIn, pFltOut);
2874 /************************************************************************
2875 * VarR4FromI1 (OLEAUT32.213)
2877 * Convert a VT_I1 to a VT_R4.
2881 * pFltOut [O] Destination
2885 * Failure: E_INVALIDARG, if the source value is invalid
2886 * DISP_E_OVERFLOW, if the value will not fit in the destination
2887 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2889 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2891 return _VarR4FromI1(cIn, pFltOut);
2894 /************************************************************************
2895 * VarR4FromUI2 (OLEAUT32.214)
2897 * Convert a VT_UI2 to a VT_R4.
2901 * pFltOut [O] Destination
2905 * Failure: E_INVALIDARG, if the source value is invalid
2906 * DISP_E_OVERFLOW, if the value will not fit in the destination
2907 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2909 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2911 return _VarR4FromUI2(usIn, pFltOut);
2914 /************************************************************************
2915 * VarR4FromUI4 (OLEAUT32.215)
2917 * Convert a VT_UI4 to a VT_R4.
2921 * pFltOut [O] Destination
2925 * Failure: E_INVALIDARG, if the source value is invalid
2926 * DISP_E_OVERFLOW, if the value will not fit in the destination
2927 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2929 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2931 return _VarR4FromUI4(ulIn, pFltOut);
2934 /************************************************************************
2935 * VarR4FromDec (OLEAUT32.216)
2937 * Convert a VT_DECIMAL to a VT_R4.
2941 * pFltOut [O] Destination
2945 * Failure: E_INVALIDARG, if the source value is invalid.
2947 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
2949 BYTE scale = DEC_SCALE(pDecIn);
2953 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2954 return E_INVALIDARG;
2959 if (DEC_SIGN(pDecIn))
2962 if (DEC_HI32(pDecIn))
2964 highPart = (double)DEC_HI32(pDecIn) / (double)divisor;
2965 highPart *= 4294967296.0F;
2966 highPart *= 4294967296.0F;
2971 *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart;
2975 /************************************************************************
2976 * VarR4FromI8 (OLEAUT32.360)
2978 * Convert a VT_I8 to a VT_R4.
2982 * pFltOut [O] Destination
2987 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2989 return _VarR4FromI8(llIn, pFltOut);
2992 /************************************************************************
2993 * VarR4FromUI8 (OLEAUT32.361)
2995 * Convert a VT_UI8 to a VT_R4.
2999 * pFltOut [O] Destination
3004 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
3006 return _VarR4FromUI8(ullIn, pFltOut);
3009 /************************************************************************
3010 * VarR4CmpR8 (OLEAUT32.316)
3012 * Compare a VT_R4 to a VT_R8.
3015 * fltLeft [I] Source
3016 * dblRight [I] Value to compare
3019 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3020 * equal to or greater than dblRight respectively.
3022 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3024 if (fltLeft < dblRight)
3026 else if (fltLeft > dblRight)
3034 /************************************************************************
3035 * VarR8FromUI1 (OLEAUT32.78)
3037 * Convert a VT_UI1 to a VT_R8.
3041 * pDblOut [O] Destination
3046 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3048 return _VarR8FromUI1(bIn, pDblOut);
3051 /************************************************************************
3052 * VarR8FromI2 (OLEAUT32.79)
3054 * Convert a VT_I2 to a VT_R8.
3058 * pDblOut [O] Destination
3063 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3065 return _VarR8FromI2(sIn, pDblOut);
3068 /************************************************************************
3069 * VarR8FromI4 (OLEAUT32.80)
3071 * Convert a VT_I4 to a VT_R8.
3075 * pDblOut [O] Destination
3080 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3082 return _VarR8FromI4(lIn, pDblOut);
3085 /************************************************************************
3086 * VarR8FromR4 (OLEAUT32.81)
3088 * Convert a VT_R4 to a VT_R8.
3092 * pDblOut [O] Destination
3097 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3099 return _VarR8FromR4(fltIn, pDblOut);
3102 /************************************************************************
3103 * VarR8FromCy (OLEAUT32.82)
3105 * Convert a VT_CY to a VT_R8.
3109 * pDblOut [O] Destination
3114 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3116 return _VarR8FromCy(cyIn, pDblOut);
3119 /************************************************************************
3120 * VarR8FromDate (OLEAUT32.83)
3122 * Convert a VT_DATE to a VT_R8.
3126 * pDblOut [O] Destination
3131 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3133 return _VarR8FromDate(dateIn, pDblOut);
3136 /************************************************************************
3137 * VarR8FromStr (OLEAUT32.84)
3139 * Convert a VT_BSTR to a VT_R8.
3143 * lcid [I] LCID for the conversion
3144 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3145 * pDblOut [O] Destination
3149 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3150 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3152 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3154 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3157 /************************************************************************
3158 * VarR8FromDisp (OLEAUT32.85)
3160 * Convert a VT_DISPATCH to a VT_R8.
3163 * pdispIn [I] Source
3164 * lcid [I] LCID for conversion
3165 * pDblOut [O] Destination
3169 * Failure: E_INVALIDARG, if the source value is invalid
3170 * DISP_E_OVERFLOW, if the value will not fit in the destination
3171 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3173 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3175 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8);
3178 /************************************************************************
3179 * VarR8FromBool (OLEAUT32.86)
3181 * Convert a VT_BOOL to a VT_R8.
3185 * pDblOut [O] Destination
3190 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3192 return VarR8FromI2(boolIn, pDblOut);
3195 /************************************************************************
3196 * VarR8FromI1 (OLEAUT32.217)
3198 * Convert a VT_I1 to a VT_R8.
3202 * pDblOut [O] Destination
3206 * Failure: E_INVALIDARG, if the source value is invalid
3207 * DISP_E_OVERFLOW, if the value will not fit in the destination
3208 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3210 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3212 return _VarR8FromI1(cIn, pDblOut);
3215 /************************************************************************
3216 * VarR8FromUI2 (OLEAUT32.218)
3218 * Convert a VT_UI2 to a VT_R8.
3222 * pDblOut [O] Destination
3226 * Failure: E_INVALIDARG, if the source value is invalid
3227 * DISP_E_OVERFLOW, if the value will not fit in the destination
3228 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3230 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3232 return _VarR8FromUI2(usIn, pDblOut);
3235 /************************************************************************
3236 * VarR8FromUI4 (OLEAUT32.219)
3238 * Convert a VT_UI4 to a VT_R8.
3242 * pDblOut [O] Destination
3246 * Failure: E_INVALIDARG, if the source value is invalid
3247 * DISP_E_OVERFLOW, if the value will not fit in the destination
3248 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3250 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3252 return _VarR8FromUI4(ulIn, pDblOut);
3255 /************************************************************************
3256 * VarR8FromDec (OLEAUT32.220)
3258 * Convert a VT_DECIMAL to a VT_R8.
3262 * pDblOut [O] Destination
3266 * Failure: E_INVALIDARG, if the source value is invalid.
3268 HRESULT WINAPI VarR8FromDec(DECIMAL* pDecIn, double *pDblOut)
3270 BYTE scale = DEC_SCALE(pDecIn);
3271 double divisor = 1.0, highPart;
3273 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3274 return E_INVALIDARG;
3279 if (DEC_SIGN(pDecIn))
3282 if (DEC_HI32(pDecIn))
3284 highPart = (double)DEC_HI32(pDecIn) / divisor;
3285 highPart *= 4294967296.0F;
3286 highPart *= 4294967296.0F;
3291 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3295 /************************************************************************
3296 * VarR8FromI8 (OLEAUT32.362)
3298 * Convert a VT_I8 to a VT_R8.
3302 * pDblOut [O] Destination
3307 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3309 return _VarR8FromI8(llIn, pDblOut);
3312 /************************************************************************
3313 * VarR8FromUI8 (OLEAUT32.363)
3315 * Convert a VT_UI8 to a VT_R8.
3319 * pDblOut [O] Destination
3324 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3326 return _VarR8FromUI8(ullIn, pDblOut);
3329 /************************************************************************
3330 * VarR8Pow (OLEAUT32.315)
3332 * Raise a VT_R8 to a power.
3335 * dblLeft [I] Source
3336 * dblPow [I] Power to raise dblLeft by
3337 * pDblOut [O] Destination
3340 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3342 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3344 *pDblOut = pow(dblLeft, dblPow);
3348 /************************************************************************
3349 * VarR8Round (OLEAUT32.317)
3351 * Round a VT_R8 to a given number of decimal points.
3355 * nDig [I] Number of decimal points to round to
3356 * pDblOut [O] Destination for rounded number
3359 * Success: S_OK. pDblOut is rounded to nDig digits.
3360 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3363 * The native version of this function rounds using the internal
3364 * binary representation of the number. Wine uses the dutch rounding
3365 * convention, so therefore small differences can occur in the value returned.
3366 * MSDN says that you should use your own rounding function if you want
3367 * rounding to be predictable in your application.
3369 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3371 double scale, whole, fract;
3374 return E_INVALIDARG;
3376 scale = pow(10.0, nDig);
3379 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3380 fract = dblIn - whole;
3383 dblIn = whole + 1.0;
3384 else if (fract == 0.5)
3385 dblIn = whole + fmod(whole, 2.0);
3386 else if (fract >= 0.0)
3388 else if (fract == -0.5)
3389 dblIn = whole - fmod(whole, 2.0);
3390 else if (fract > -0.5)
3393 dblIn = whole - 1.0;
3395 *pDblOut = dblIn / scale;
3402 /* Powers of 10 from 0..4 D.P. */
3403 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3404 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3406 /************************************************************************
3407 * VarCyFromUI1 (OLEAUT32.98)
3409 * Convert a VT_UI1 to a VT_CY.
3413 * pCyOut [O] Destination
3417 * Failure: E_INVALIDARG, if the source value is invalid
3418 * DISP_E_OVERFLOW, if the value will not fit in the destination
3419 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3421 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3423 return VarCyFromR8(bIn, pCyOut);
3426 /************************************************************************
3427 * VarCyFromI2 (OLEAUT32.99)
3429 * Convert a VT_I2 to a VT_CY.
3433 * pCyOut [O] Destination
3437 * Failure: E_INVALIDARG, if the source value is invalid
3438 * DISP_E_OVERFLOW, if the value will not fit in the destination
3439 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3441 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3443 return VarCyFromR8(sIn, pCyOut);
3446 /************************************************************************
3447 * VarCyFromI4 (OLEAUT32.100)
3449 * Convert a VT_I4 to a VT_CY.
3453 * pCyOut [O] Destination
3457 * Failure: E_INVALIDARG, if the source value is invalid
3458 * DISP_E_OVERFLOW, if the value will not fit in the destination
3459 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3461 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3463 return VarCyFromR8(lIn, pCyOut);
3466 /************************************************************************
3467 * VarCyFromR4 (OLEAUT32.101)
3469 * Convert a VT_R4 to a VT_CY.
3473 * pCyOut [O] Destination
3477 * Failure: E_INVALIDARG, if the source value is invalid
3478 * DISP_E_OVERFLOW, if the value will not fit in the destination
3479 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3481 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3483 return VarCyFromR8(fltIn, pCyOut);
3486 /************************************************************************
3487 * VarCyFromR8 (OLEAUT32.102)
3489 * Convert a VT_R8 to a VT_CY.
3493 * pCyOut [O] Destination
3497 * Failure: E_INVALIDARG, if the source value is invalid
3498 * DISP_E_OVERFLOW, if the value will not fit in the destination
3499 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3501 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3503 #if defined(__GNUC__) && defined(__i386__)
3504 /* This code gives identical results to Win32 on Intel.
3505 * Here we use fp exceptions to catch overflows when storing the value.
3507 static const unsigned short r8_fpcontrol = 0x137f;
3508 static const double r8_multiplier = CY_MULTIPLIER_F;
3509 unsigned short old_fpcontrol, result_fpstatus;
3511 /* Clear exceptions, save the old fp state and load the new state */
3512 __asm__ __volatile__( "fnclex" );
3513 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3514 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3515 /* Perform the conversion. */
3516 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3517 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3518 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3519 /* Save the resulting fp state, load the old state and clear exceptions */
3520 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3521 __asm__ __volatile__( "fnclex" );
3522 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3524 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3525 return DISP_E_OVERFLOW;
3528 /* This version produces slightly different results for boundary cases */
3529 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3530 return DISP_E_OVERFLOW;
3531 dblIn *= CY_MULTIPLIER_F;
3532 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3537 /************************************************************************
3538 * VarCyFromDate (OLEAUT32.103)
3540 * Convert a VT_DATE to a VT_CY.
3544 * pCyOut [O] Destination
3548 * Failure: E_INVALIDARG, if the source value is invalid
3549 * DISP_E_OVERFLOW, if the value will not fit in the destination
3550 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3552 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3554 return VarCyFromR8(dateIn, pCyOut);
3557 /************************************************************************
3558 * VarCyFromStr (OLEAUT32.104)
3560 * Convert a VT_BSTR to a VT_CY.
3564 * lcid [I] LCID for the conversion
3565 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3566 * pCyOut [O] Destination
3570 * Failure: E_INVALIDARG, if the source value is invalid
3571 * DISP_E_OVERFLOW, if the value will not fit in the destination
3572 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3574 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3576 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3579 /************************************************************************
3580 * VarCyFromDisp (OLEAUT32.105)
3582 * Convert a VT_DISPATCH to a VT_CY.
3585 * pdispIn [I] Source
3586 * lcid [I] LCID for conversion
3587 * pCyOut [O] Destination
3591 * Failure: E_INVALIDARG, if the source value is invalid
3592 * DISP_E_OVERFLOW, if the value will not fit in the destination
3593 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3595 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3597 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY);
3600 /************************************************************************
3601 * VarCyFromBool (OLEAUT32.106)
3603 * Convert a VT_BOOL to a VT_CY.
3607 * pCyOut [O] Destination
3611 * Failure: E_INVALIDARG, if the source value is invalid
3612 * DISP_E_OVERFLOW, if the value will not fit in the destination
3613 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3616 * While the sign of the boolean is stored in the currency, the value is
3617 * converted to either 0 or 1.
3619 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3621 return VarCyFromR8(boolIn, pCyOut);
3624 /************************************************************************
3625 * VarCyFromI1 (OLEAUT32.225)
3627 * Convert a VT_I1 to a VT_CY.
3631 * pCyOut [O] Destination
3635 * Failure: E_INVALIDARG, if the source value is invalid
3636 * DISP_E_OVERFLOW, if the value will not fit in the destination
3637 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3639 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3641 return VarCyFromR8(cIn, pCyOut);
3644 /************************************************************************
3645 * VarCyFromUI2 (OLEAUT32.226)
3647 * Convert a VT_UI2 to a VT_CY.
3651 * pCyOut [O] Destination
3655 * Failure: E_INVALIDARG, if the source value is invalid
3656 * DISP_E_OVERFLOW, if the value will not fit in the destination
3657 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3659 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3661 return VarCyFromR8(usIn, pCyOut);
3664 /************************************************************************
3665 * VarCyFromUI4 (OLEAUT32.227)
3667 * Convert a VT_UI4 to a VT_CY.
3671 * pCyOut [O] Destination
3675 * Failure: E_INVALIDARG, if the source value is invalid
3676 * DISP_E_OVERFLOW, if the value will not fit in the destination
3677 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3679 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3681 return VarCyFromR8(ulIn, pCyOut);
3684 /************************************************************************
3685 * VarCyFromDec (OLEAUT32.228)
3687 * Convert a VT_DECIMAL to a VT_CY.
3691 * pCyOut [O] Destination
3695 * Failure: E_INVALIDARG, if the source value is invalid
3696 * DISP_E_OVERFLOW, if the value will not fit in the destination
3697 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3699 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
3704 hRet = VarDecRound(pdecIn, 4, &rounded);
3706 if (SUCCEEDED(hRet))
3710 if (DEC_HI32(&rounded))
3711 return DISP_E_OVERFLOW;
3713 /* Note: Without the casts this promotes to int64 which loses precision */
3714 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3715 if (DEC_SIGN(&rounded))
3717 return VarCyFromR8(d, pCyOut);
3722 /************************************************************************
3723 * VarCyFromI8 (OLEAUT32.366)
3725 * Convert a VT_I8 to a VT_CY.
3729 * pCyOut [O] Destination
3733 * Failure: E_INVALIDARG, if the source value is invalid
3734 * DISP_E_OVERFLOW, if the value will not fit in the destination
3735 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3737 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3739 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3740 pCyOut->int64 = llIn * CY_MULTIPLIER;
3744 /************************************************************************
3745 * VarCyFromUI8 (OLEAUT32.375)
3747 * Convert a VT_UI8 to a VT_CY.
3751 * pCyOut [O] Destination
3755 * Failure: E_INVALIDARG, if the source value is invalid
3756 * DISP_E_OVERFLOW, if the value will not fit in the destination
3757 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3759 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3761 return VarCyFromR8(ullIn, pCyOut);
3764 /************************************************************************
3765 * VarCyAdd (OLEAUT32.299)
3767 * Add one CY to another.
3771 * cyRight [I] Value to add
3772 * pCyOut [O] Destination
3776 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3778 HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut)
3781 _VarR8FromCy(cyLeft, &l);
3782 _VarR8FromCy(cyRight, &r);
3784 return VarCyFromR8(l, pCyOut);
3787 /************************************************************************
3788 * VarCyMul (OLEAUT32.303)
3790 * Multiply one CY by another.
3794 * cyRight [I] Value to multiply by
3795 * pCyOut [O] Destination
3799 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3801 HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut)
3804 _VarR8FromCy(cyLeft, &l);
3805 _VarR8FromCy(cyRight, &r);
3807 return VarCyFromR8(l, pCyOut);
3810 /************************************************************************
3811 * VarCyMulI4 (OLEAUT32.304)
3813 * Multiply one CY by a VT_I4.
3817 * lRight [I] Value to multiply by
3818 * pCyOut [O] Destination
3822 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3824 HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut)
3828 _VarR8FromCy(cyLeft, &d);
3830 return VarCyFromR8(d, pCyOut);
3833 /************************************************************************
3834 * VarCySub (OLEAUT32.305)
3836 * Subtract one CY from another.
3840 * cyRight [I] Value to subtract
3841 * pCyOut [O] Destination
3845 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3847 HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut)
3850 _VarR8FromCy(cyLeft, &l);
3851 _VarR8FromCy(cyRight, &r);
3853 return VarCyFromR8(l, pCyOut);
3856 /************************************************************************
3857 * VarCyAbs (OLEAUT32.306)
3859 * Convert a VT_CY into its absolute value.
3863 * pCyOut [O] Destination
3866 * Success: S_OK. pCyOut contains the absolute value.
3867 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3869 HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut)
3871 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3872 return DISP_E_OVERFLOW;
3874 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3878 /************************************************************************
3879 * VarCyFix (OLEAUT32.307)
3881 * Return the integer part of a VT_CY.
3885 * pCyOut [O] Destination
3889 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3892 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3893 * negative numbers away from 0, while this function rounds them towards zero.
3895 HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut)
3897 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3898 pCyOut->int64 *= CY_MULTIPLIER;
3902 /************************************************************************
3903 * VarCyInt (OLEAUT32.308)
3905 * Return the integer part of a VT_CY.
3909 * pCyOut [O] Destination
3913 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3916 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3917 * negative numbers towards 0, while this function rounds them away from zero.
3919 HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut)
3921 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3922 pCyOut->int64 *= CY_MULTIPLIER;
3924 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3926 pCyOut->int64 -= CY_MULTIPLIER;
3931 /************************************************************************
3932 * VarCyNeg (OLEAUT32.309)
3934 * Change the sign of a VT_CY.
3938 * pCyOut [O] Destination
3942 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3944 HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut)
3946 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3947 return DISP_E_OVERFLOW;
3949 pCyOut->int64 = -cyIn.int64;
3953 /************************************************************************
3954 * VarCyRound (OLEAUT32.310)
3956 * Change the precision of a VT_CY.
3960 * cDecimals [I] New number of decimals to keep
3961 * pCyOut [O] Destination
3965 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3967 HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
3970 return E_INVALIDARG;
3974 /* Rounding to more precision than we have */
3980 double d, div = CY_Divisors[cDecimals];
3982 _VarR8FromCy(cyIn, &d);
3984 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3985 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3986 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3991 /************************************************************************
3992 * VarCyCmp (OLEAUT32.311)
3994 * Compare two VT_CY values.
3998 * cyRight [I] Value to compare
4001 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4002 * compare is less, equal or greater than source respectively.
4003 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4005 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
4010 /* Subtract right from left, and compare the result to 0 */
4011 hRet = VarCySub(cyLeft, cyRight, &result);
4013 if (SUCCEEDED(hRet))
4015 if (result.int64 < 0)
4016 hRet = (HRESULT)VARCMP_LT;
4017 else if (result.int64 > 0)
4018 hRet = (HRESULT)VARCMP_GT;
4020 hRet = (HRESULT)VARCMP_EQ;
4025 /************************************************************************
4026 * VarCyCmpR8 (OLEAUT32.312)
4028 * Compare a VT_CY to a double
4031 * cyLeft [I] Currency Source
4032 * dblRight [I] double to compare to cyLeft
4035 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4036 * less than, equal to or greater than cyLeft respectively.
4037 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4039 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight)
4044 hRet = VarCyFromR8(dblRight, &cyRight);
4046 if (SUCCEEDED(hRet))
4047 hRet = VarCyCmp(cyLeft, cyRight);
4052 /************************************************************************
4053 * VarCyMulI8 (OLEAUT32.329)
4055 * Multiply a VT_CY by a VT_I8.
4059 * llRight [I] Value to multiply by
4060 * pCyOut [O] Destination
4064 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4066 HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
4070 _VarR8FromCy(cyLeft, &d);
4071 d = d * (double)llRight;
4072 return VarCyFromR8(d, pCyOut);
4078 /************************************************************************
4079 * VarDecFromUI1 (OLEAUT32.190)
4081 * Convert a VT_UI1 to a DECIMAL.
4085 * pDecOut [O] Destination
4090 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4092 return VarDecFromUI4(bIn, pDecOut);
4095 /************************************************************************
4096 * VarDecFromI2 (OLEAUT32.191)
4098 * Convert a VT_I2 to a DECIMAL.
4102 * pDecOut [O] Destination
4107 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4109 return VarDecFromI4(sIn, pDecOut);
4112 /************************************************************************
4113 * VarDecFromI4 (OLEAUT32.192)
4115 * Convert a VT_I4 to a DECIMAL.
4119 * pDecOut [O] Destination
4124 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4126 DEC_HI32(pDecOut) = 0;
4127 DEC_MID32(pDecOut) = 0;
4131 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4132 DEC_LO32(pDecOut) = -lIn;
4136 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4137 DEC_LO32(pDecOut) = lIn;
4142 #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT))
4144 /************************************************************************
4145 * VarDecFromR4 (OLEAUT32.193)
4147 * Convert a VT_R4 to a DECIMAL.
4151 * pDecOut [O] Destination
4156 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4160 sprintfW( buff, szFloatFormatW, fltIn );
4161 return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut);
4164 /************************************************************************
4165 * VarDecFromR8 (OLEAUT32.194)
4167 * Convert a VT_R8 to a DECIMAL.
4171 * pDecOut [O] Destination
4176 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4180 sprintfW( buff, szDoubleFormatW, dblIn );
4181 return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut);
4184 /************************************************************************
4185 * VarDecFromDate (OLEAUT32.195)
4187 * Convert a VT_DATE to a DECIMAL.
4191 * pDecOut [O] Destination
4196 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4198 return VarDecFromR8(dateIn, pDecOut);
4201 /************************************************************************
4202 * VarDecFromCy (OLEAUT32.196)
4204 * Convert a VT_CY to a DECIMAL.
4208 * pDecOut [O] Destination
4213 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4215 DEC_HI32(pDecOut) = 0;
4217 /* Note: This assumes 2s complement integer representation */
4218 if (cyIn.s.Hi & 0x80000000)
4220 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4221 DEC_LO64(pDecOut) = -cyIn.int64;
4225 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4226 DEC_MID32(pDecOut) = cyIn.s.Hi;
4227 DEC_LO32(pDecOut) = cyIn.s.Lo;
4232 /************************************************************************
4233 * VarDecFromStr (OLEAUT32.197)
4235 * Convert a VT_BSTR to a DECIMAL.
4239 * lcid [I] LCID for the conversion
4240 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4241 * pDecOut [O] Destination
4245 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4247 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4249 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4252 /************************************************************************
4253 * VarDecFromDisp (OLEAUT32.198)
4255 * Convert a VT_DISPATCH to a DECIMAL.
4258 * pdispIn [I] Source
4259 * lcid [I] LCID for conversion
4260 * pDecOut [O] Destination
4264 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4266 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4268 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL);
4271 /************************************************************************
4272 * VarDecFromBool (OLEAUT32.199)
4274 * Convert a VT_BOOL to a DECIMAL.
4278 * pDecOut [O] Destination
4284 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4286 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4288 DEC_HI32(pDecOut) = 0;
4289 DEC_MID32(pDecOut) = 0;
4292 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4293 DEC_LO32(pDecOut) = 1;
4297 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4298 DEC_LO32(pDecOut) = 0;
4303 /************************************************************************
4304 * VarDecFromI1 (OLEAUT32.241)
4306 * Convert a VT_I1 to a DECIMAL.
4310 * pDecOut [O] Destination
4315 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4317 return VarDecFromI4(cIn, pDecOut);
4320 /************************************************************************
4321 * VarDecFromUI2 (OLEAUT32.242)
4323 * Convert a VT_UI2 to a DECIMAL.
4327 * pDecOut [O] Destination
4332 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4334 return VarDecFromUI4(usIn, pDecOut);
4337 /************************************************************************
4338 * VarDecFromUI4 (OLEAUT32.243)
4340 * Convert a VT_UI4 to a DECIMAL.
4344 * pDecOut [O] Destination
4349 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4351 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4352 DEC_HI32(pDecOut) = 0;
4353 DEC_MID32(pDecOut) = 0;
4354 DEC_LO32(pDecOut) = ulIn;
4358 /************************************************************************
4359 * VarDecFromI8 (OLEAUT32.374)
4361 * Convert a VT_I8 to a DECIMAL.
4365 * pDecOut [O] Destination
4370 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4372 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4374 DEC_HI32(pDecOut) = 0;
4376 /* Note: This assumes 2s complement integer representation */
4377 if (pLi->u.HighPart & 0x80000000)
4379 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4380 DEC_LO64(pDecOut) = -pLi->QuadPart;
4384 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4385 DEC_MID32(pDecOut) = pLi->u.HighPart;
4386 DEC_LO32(pDecOut) = pLi->u.LowPart;
4391 /************************************************************************
4392 * VarDecFromUI8 (OLEAUT32.375)
4394 * Convert a VT_UI8 to a DECIMAL.
4398 * pDecOut [O] Destination
4403 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4405 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4406 DEC_HI32(pDecOut) = 0;
4407 DEC_LO64(pDecOut) = ullIn;
4411 /* Make two DECIMALS the same scale; used by math functions below */
4412 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4413 const DECIMAL** ppDecRight,
4416 static DECIMAL scaleFactor;
4419 HRESULT hRet = S_OK;
4421 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4422 return E_INVALIDARG;
4424 DEC_LO32(&scaleFactor) = 10;
4426 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4429 return S_OK; /* Same scale */
4431 if (scaleAmount > 0)
4433 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4434 *ppDecRight = pDecOut;
4438 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4439 *ppDecLeft = pDecOut;
4440 i = scaleAmount = -scaleAmount;
4443 if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE)
4444 return DISP_E_OVERFLOW; /* Can't scale up */
4446 /* Multiply up the value to be scaled by the correct amount */
4447 while (SUCCEEDED(hRet) && i--)
4449 /* Note we are multiplying by a value with a scale of 0, so we don't recurse */
4450 hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut);
4453 DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */
4457 /* Add two unsigned 32 bit values with overflow */
4458 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4460 ULARGE_INTEGER ul64;
4462 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4463 *pulHigh = ul64.u.HighPart;
4464 return ul64.u.LowPart;
4467 /* Subtract two unsigned 32 bit values with underflow */
4468 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4471 ULARGE_INTEGER ul64;
4473 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4474 if (ulLeft < ulRight)
4477 if (ul64.QuadPart > (ULONG64)*pulHigh)
4478 ul64.QuadPart -= (ULONG64)*pulHigh;
4481 ul64.QuadPart -= (ULONG64)*pulHigh;
4485 ul64.u.HighPart = -ul64.u.HighPart ;
4487 *pulHigh = ul64.u.HighPart;
4488 return ul64.u.LowPart;
4491 /* Multiply two unsigned 32 bit values with overflow */
4492 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4494 ULARGE_INTEGER ul64;
4496 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4497 *pulHigh = ul64.u.HighPart;
4498 return ul64.u.LowPart;
4501 /* Compare two decimals that have the same scale */
4502 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4504 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4505 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4507 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4512 /************************************************************************
4513 * VarDecAdd (OLEAUT32.177)
4515 * Add one DECIMAL to another.
4518 * pDecLeft [I] Source
4519 * pDecRight [I] Value to add
4520 * pDecOut [O] Destination
4524 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4526 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4531 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled);
4533 if (SUCCEEDED(hRet))
4535 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4537 BYTE sign = DECIMAL_POS;
4539 /* Correct for the sign of the result */
4540 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4542 /* -x + -y : Negative */
4544 goto VarDecAdd_AsPositive;
4546 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4548 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4550 /* -x + y : Negative if x > y */
4554 VarDecAdd_AsNegative:
4555 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4556 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4557 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4561 VarDecAdd_AsInvertedNegative:
4562 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4563 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4564 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4567 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4569 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4571 /* x + -y : Negative if x <= y */
4575 goto VarDecAdd_AsInvertedNegative;
4577 goto VarDecAdd_AsNegative;
4581 /* x + y : Positive */
4582 VarDecAdd_AsPositive:
4583 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4584 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4585 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4589 return DISP_E_OVERFLOW; /* overflowed */
4591 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4592 DEC_SIGN(pDecOut) = sign;
4597 /* internal representation of the value stored in a DECIMAL. The bytes are
4598 stored from LSB at index 0 to MSB at index 11
4600 typedef struct DECIMAL_internal
4602 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4603 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4604 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4607 /* translate from external DECIMAL format into an internal representation */
4608 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4610 to->scale = DEC_SCALE(from);
4611 to->sign = DEC_SIGN(from) ? 1 : 0;
4613 to->bitsnum[0] = DEC_LO32(from);
4614 to->bitsnum[1] = DEC_MID32(from);
4615 to->bitsnum[2] = DEC_HI32(from);
4618 static void VARIANT_DecFromDI(VARIANT_DI * from, DECIMAL * to)
4621 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4623 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4626 DEC_LO32(to) = from->bitsnum[0];
4627 DEC_MID32(to) = from->bitsnum[1];
4628 DEC_HI32(to) = from->bitsnum[2];
4631 /* clear an internal representation of a DECIMAL */
4632 static void VARIANT_DI_clear(VARIANT_DI * i)
4634 memset(i, 0, sizeof(VARIANT_DI));
4637 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4638 size is supported. The value in p is replaced by the quotient of the division, and
4639 the remainder is returned as a result. This routine is most often used with a divisor
4640 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4642 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4647 } else if (divisor == 1) {
4648 /* dividend remains unchanged */
4651 unsigned char remainder = 0;
4652 ULONGLONG iTempDividend;
4655 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4656 for (; i >= 0; i--) {
4657 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4658 remainder = iTempDividend % divisor;
4659 p[i] = iTempDividend / divisor;
4666 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4667 static int VARIANT_int_iszero(DWORD * p, unsigned int n)
4669 for (; n > 0; n--) if (*p++ != 0) return 0;
4673 /* multiply two DECIMALS, without changing either one, and place result in third
4674 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4675 digits when scale > 0 in order to fit an overflowing result. Final overflow
4678 static int VARIANT_DI_mul(VARIANT_DI * a, VARIANT_DI * b, VARIANT_DI * result)
4682 signed int mulstart;
4684 VARIANT_DI_clear(result);
4685 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4687 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4688 of the result is formed by adding the scales of the operands.
4690 result->scale = a->scale + b->scale;
4691 memset(running, 0, sizeof(running));
4693 /* count number of leading zero-bytes in operand A */
4694 for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4696 /* result is 0, because operand A is 0 */
4700 unsigned char remainder = 0;
4703 /* perform actual multiplication */
4704 for (iA = 0; iA <= mulstart; iA++) {
4708 for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
4712 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4715 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4721 /* Too bad - native oleaut does not do this, so we should not either */
4723 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4724 This operation should not lose significant digits, and gives an
4725 opportunity to reduce the possibility of overflows in future
4726 operations issued by the application.
4728 while (result->scale > 0) {
4729 memcpy(quotient, running, sizeof(quotient));
4730 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4731 if (remainder > 0) break;
4732 memcpy(running, quotient, sizeof(quotient));
4736 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4737 This operation *will* lose significant digits of the result because
4738 all the factors of 10 were consumed by the previous operation.
4740 while (result->scale > 0 && !VARIANT_int_iszero(
4741 running + sizeof(result->bitsnum) / sizeof(DWORD),
4742 (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
4744 remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
4745 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4749 /* round up the result - native oleaut32 does this */
4750 if (remainder >= 5) {
4752 for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
4753 ULONGLONG digit = running[i] + 1;
4754 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4755 running[i] = digit & 0xFFFFFFFF;
4759 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4760 and copy result bits into result structure
4762 r_overflow = !VARIANT_int_iszero(
4763 running + sizeof(result->bitsnum)/sizeof(DWORD),
4764 (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
4765 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4770 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4771 hardcoded (period for decimal separator, dash as negative sign). Returns 0 for
4772 success, nonzero if insufficient space in output buffer.
4774 static int VARIANT_DI_tostringW(VARIANT_DI * a, WCHAR * s, unsigned int n)
4778 unsigned char remainder;
4781 /* place negative sign */
4782 if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
4790 /* prepare initial 0 */
4795 } else overflow = 1;
4799 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4800 while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
4801 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4805 s[i++] = '0' + remainder;
4810 if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
4812 /* reverse order of digits */
4813 WCHAR * x = s; WCHAR * y = s + i - 1;
4820 /* check for decimal point. "i" now has string length */
4821 if (i <= a->scale) {
4822 unsigned int numzeroes = a->scale + 1 - i;
4823 if (i + 1 + numzeroes >= n) {
4826 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4828 while (numzeroes > 0) {
4829 s[--numzeroes] = '0';
4834 /* place decimal point */
4836 unsigned int periodpos = i - a->scale;
4840 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4841 s[periodpos] = '.'; i++;
4843 /* remove extra zeros at the end, if any */
4844 while (s[i - 1] == '0') s[--i] = '\0';
4845 if (s[i - 1] == '.') s[--i] = '\0';
4853 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4854 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4859 /* shift whole DWORDs to the left */
4862 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4863 *p = 0; shift -= 32;
4866 /* shift remainder (1..31 bits) */
4868 if (shift > 0) for (i = 0; i < n; i++)
4871 b = p[i] >> (32 - shift);
4872 p[i] = (p[i] << shift) | shifted;
4877 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4878 Value at v is incremented by the value at p. Any size is supported, provided
4879 that v is not shorter than p. Any unapplied carry is returned as a result.
4881 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, DWORD * p,
4884 unsigned char carry = 0;
4890 for (i = 0; i < np; i++) {
4891 sum = (ULONGLONG)v[i]
4894 v[i] = sum & 0xffffffff;
4897 for (; i < nv && carry; i++) {
4898 sum = (ULONGLONG)v[i]
4900 v[i] = sum & 0xffffffff;
4907 /* perform integral division with operand p as dividend. Parameter n indicates
4908 number of available DWORDs in divisor p, but available space in p must be
4909 actually at least 2 * n DWORDs, because the remainder of the integral
4910 division is built in the next n DWORDs past the start of the quotient. This
4911 routine replaces the dividend in p with the quotient, and appends n
4912 additional DWORDs for the remainder.
4914 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4915 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4916 source code to the VLI (Very Large Integer) division operator. This algorithm
4917 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4918 variably-scaled integers such as the MS DECIMAL representation.
4920 static void VARIANT_int_div(DWORD * p, unsigned int n, DWORD * divisor,
4925 DWORD * negdivisor = tempsub + n;
4927 /* build 2s-complement of divisor */
4928 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
4930 VARIANT_int_add(negdivisor, n, p + n, 1);
4931 memset(p + n, 0, n * sizeof(DWORD));
4933 /* skip all leading zero DWORDs in quotient */
4934 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
4935 /* i is now number of DWORDs left to process */
4936 for (i <<= 5; i < (n << 5); i++) {
4937 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
4939 /* trial subtraction */
4940 memcpy(tempsub, p + n, n * sizeof(DWORD));
4941 VARIANT_int_add(tempsub, n, negdivisor, n);
4943 /* check whether result of subtraction was negative */
4944 if ((tempsub[n - 1] & 0x80000000) == 0) {
4945 memcpy(p + n, tempsub, n * sizeof(DWORD));
4951 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4952 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
4957 for (iOverflowMul = 0, i = 0; i < n; i++)
4958 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
4959 return (unsigned char)iOverflowMul;
4962 /* increment value in A by the value indicated in B, with scale adjusting.
4963 Modifies parameters by adjusting scales. Returns 0 if addition was
4964 successful, nonzero if a parameter underflowed before it could be
4965 successfully used in the addition.
4967 static int VARIANT_int_addlossy(
4968 DWORD * a, int * ascale, unsigned int an,
4969 DWORD * b, int * bscale, unsigned int bn)
4973 if (VARIANT_int_iszero(a, an)) {
4974 /* if A is zero, copy B into A, after removing digits */
4975 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
4976 VARIANT_int_divbychar(b, bn, 10);
4979 memcpy(a, b, an * sizeof(DWORD));
4981 } else if (!VARIANT_int_iszero(b, bn)) {
4982 unsigned int tn = an + 1;
4985 if (bn + 1 > tn) tn = bn + 1;
4986 if (*ascale != *bscale) {
4987 /* first (optimistic) try - try to scale down the one with the bigger
4988 scale, while this number is divisible by 10 */
4989 DWORD * digitchosen;
4990 unsigned int nchosen;
4994 if (*ascale < *bscale) {
4995 targetscale = *ascale;
4996 scalechosen = bscale;
5000 targetscale = *bscale;
5001 scalechosen = ascale;
5005 memset(t, 0, tn * sizeof(DWORD));
5006 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5008 /* divide by 10 until target scale is reached */
5009 while (*scalechosen > targetscale) {
5010 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5013 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5018 if (*ascale != *bscale) {
5019 DWORD * digitchosen;
5020 unsigned int nchosen;
5024 /* try to scale up the one with the smaller scale */
5025 if (*ascale > *bscale) {
5026 targetscale = *ascale;
5027 scalechosen = bscale;
5031 targetscale = *bscale;
5032 scalechosen = ascale;
5036 memset(t, 0, tn * sizeof(DWORD));
5037 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5039 /* multiply by 10 until target scale is reached, or
5040 significant bytes overflow the number
5042 while (*scalechosen < targetscale && t[nchosen] == 0) {
5043 VARIANT_int_mulbychar(t, tn, 10);
5044 if (t[nchosen] == 0) {
5045 /* still does not overflow */
5047 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5052 if (*ascale != *bscale) {
5053 /* still different? try to scale down the one with the bigger scale
5054 (this *will* lose significant digits) */
5055 DWORD * digitchosen;
5056 unsigned int nchosen;
5060 if (*ascale < *bscale) {
5061 targetscale = *ascale;
5062 scalechosen = bscale;
5066 targetscale = *bscale;
5067 scalechosen = ascale;
5071 memset(t, 0, tn * sizeof(DWORD));
5072 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5074 /* divide by 10 until target scale is reached */
5075 while (*scalechosen > targetscale) {
5076 VARIANT_int_divbychar(t, tn, 10);
5078 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5082 /* check whether any of the operands still has significant digits
5085 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5088 /* at this step, both numbers have the same scale and can be added
5089 as integers. However, the result might not fit in A, so further
5090 scaling down might be necessary.
5092 while (!underflow) {
5093 memset(t, 0, tn * sizeof(DWORD));
5094 memcpy(t, a, an * sizeof(DWORD));
5096 VARIANT_int_add(t, tn, b, bn);
5097 if (VARIANT_int_iszero(t + an, tn - an)) {
5098 /* addition was successful */
5099 memcpy(a, t, an * sizeof(DWORD));
5102 /* addition overflowed - remove significant digits
5103 from both operands and try again */
5104 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5105 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5106 /* check whether any operand keeps significant digits after
5107 scaledown (underflow case 2)
5109 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5117 /* perform complete DECIMAL division in the internal representation. Returns
5118 0 if the division was completed (even if quotient is set to 0), or nonzero
5119 in case of quotient overflow.
5121 static HRESULT VARIANT_DI_div(VARIANT_DI * dividend, VARIANT_DI * divisor, VARIANT_DI * quotient)
5123 HRESULT r_overflow = S_OK;
5125 if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
5127 r_overflow = DISP_E_DIVBYZERO;
5128 } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
5129 VARIANT_DI_clear(quotient);
5131 int quotientscale, remainderscale, tempquotientscale;
5132 DWORD remainderplusquotient[8];
5135 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5136 tempquotientscale = quotientscale;
5137 VARIANT_DI_clear(quotient);
5138 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5140 /* The following strategy is used for division
5141 1) if there was a nonzero remainder from previous iteration, use it as
5142 dividend for this iteration, else (for first iteration) use intended
5144 2) perform integer division in temporary buffer, develop quotient in
5145 low-order part, remainder in high-order part
5146 3) add quotient from step 2 to final result, with possible loss of
5148 4) multiply integer part of remainder by 10, while incrementing the
5149 scale of the remainder. This operation preserves the intended value
5151 5) loop to step 1 until one of the following is true:
5152 a) remainder is zero (exact division achieved)
5153 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5155 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5156 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5159 remainderplusquotient, 4,
5160 divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
5161 underflow = VARIANT_int_addlossy(
5162 quotient->bitsnum, "ientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
5163 remainderplusquotient, &tempquotientscale, 4);
5164 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5165 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5166 tempquotientscale = ++remainderscale;
5167 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5169 /* quotient scale might now be negative (extremely big number). If, so, try
5170 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5171 until scale is 0. If this cannot be done, it is a real overflow.
5173 while (!r_overflow && quotientscale < 0) {
5174 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5175 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5176 VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
5177 if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
5178 (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
5180 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5181 } else r_overflow = DISP_E_OVERFLOW;
5184 if (quotientscale <= 255) quotient->scale = quotientscale;
5185 else VARIANT_DI_clear(quotient);
5191 /************************************************************************
5192 * VarDecDiv (OLEAUT32.178)
5194 * Divide one DECIMAL by another.
5197 * pDecLeft [I] Source
5198 * pDecRight [I] Value to divide by
5199 * pDecOut [O] Destination
5203 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5205 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5207 HRESULT hRet = S_OK;
5208 VARIANT_DI di_left, di_right, di_result;
5211 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5213 VARIANT_DIFromDec(pDecLeft, &di_left);
5214 VARIANT_DIFromDec(pDecRight, &di_right);
5215 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result);
5218 /* division actually overflowed */
5225 if (di_result.scale > DEC_MAX_SCALE)
5227 unsigned char remainder = 0;
5229 /* division underflowed. In order to comply with the MSDN
5230 specifications for DECIMAL ranges, some significant digits
5233 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5235 while (di_result.scale > DEC_MAX_SCALE &&
5236 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
5238 remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
5241 if (di_result.scale > DEC_MAX_SCALE)
5243 WARN("result underflowed, setting to 0\n");
5244 di_result.scale = 0;
5247 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5250 for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
5251 ULONGLONG digit = di_result.bitsnum[i] + 1;
5252 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5253 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5257 VARIANT_DecFromDI(&di_result, pDecOut);
5262 /************************************************************************
5263 * VarDecMul (OLEAUT32.179)
5265 * Multiply one DECIMAL by another.
5268 * pDecLeft [I] Source
5269 * pDecRight [I] Value to multiply by
5270 * pDecOut [O] Destination
5274 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5276 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5278 HRESULT hRet = S_OK;
5279 VARIANT_DI di_left, di_right, di_result;
5282 VARIANT_DIFromDec(pDecLeft, &di_left);
5283 VARIANT_DIFromDec(pDecRight, &di_right);
5284 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5287 /* multiplication actually overflowed */
5288 hRet = DISP_E_OVERFLOW;
5292 if (di_result.scale > DEC_MAX_SCALE)
5294 /* multiplication underflowed. In order to comply with the MSDN
5295 specifications for DECIMAL ranges, some significant digits
5298 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5300 while (di_result.scale > DEC_MAX_SCALE &&
5301 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
5303 VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
5306 if (di_result.scale > DEC_MAX_SCALE)
5308 WARN("result underflowed, setting to 0\n");
5309 di_result.scale = 0;
5313 VARIANT_DecFromDI(&di_result, pDecOut);
5318 /************************************************************************
5319 * VarDecSub (OLEAUT32.181)
5321 * Subtract one DECIMAL from another.
5324 * pDecLeft [I] Source
5325 * pDecRight [I] DECIMAL to subtract from pDecLeft
5326 * pDecOut [O] Destination
5329 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5331 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5335 /* Implement as addition of the negative */
5336 VarDecNeg(pDecRight, &decRight);
5337 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5340 /************************************************************************
5341 * VarDecAbs (OLEAUT32.182)
5343 * Convert a DECIMAL into its absolute value.
5347 * pDecOut [O] Destination
5350 * S_OK. This function does not fail.
5352 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5355 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5359 /************************************************************************
5360 * VarDecFix (OLEAUT32.187)
5362 * Return the integer portion of a DECIMAL.
5366 * pDecOut [O] Destination
5370 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5373 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5374 * negative numbers away from 0, while this function rounds them towards zero.
5376 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5378 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5379 return E_INVALIDARG;
5381 if (!DEC_SCALE(pDecIn))
5383 *pDecOut = *pDecIn; /* Already an integer */
5387 FIXME("semi-stub!\n");
5388 return DISP_E_OVERFLOW;
5391 /************************************************************************
5392 * VarDecInt (OLEAUT32.188)
5394 * Return the integer portion of a DECIMAL.
5398 * pDecOut [O] Destination
5402 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5405 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5406 * negative numbers towards 0, while this function rounds them away from zero.
5408 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5410 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5411 return E_INVALIDARG;
5413 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5414 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5416 FIXME("semi-stub!\n");
5417 return DISP_E_OVERFLOW;
5420 /************************************************************************
5421 * VarDecNeg (OLEAUT32.189)
5423 * Change the sign of a DECIMAL.
5427 * pDecOut [O] Destination
5430 * S_OK. This function does not fail.
5432 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5435 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5439 /************************************************************************
5440 * VarDecRound (OLEAUT32.203)
5442 * Change the precision of a DECIMAL.
5446 * cDecimals [I] New number of decimals to keep
5447 * pDecOut [O] Destination
5450 * Success: S_OK. pDecOut contains the rounded value.
5451 * Failure: E_INVALIDARG if any argument is invalid.
5453 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5455 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5456 return E_INVALIDARG;
5458 if (cDecimals >= DEC_SCALE(pDecIn))
5460 *pDecOut = *pDecIn; /* More precision than we have */
5464 FIXME("semi-stub!\n");
5466 return DISP_E_OVERFLOW;
5469 /************************************************************************
5470 * VarDecCmp (OLEAUT32.204)
5472 * Compare two DECIMAL values.
5475 * pDecLeft [I] Source
5476 * pDecRight [I] Value to compare
5479 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5480 * is less than, equal to or greater than pDecRight respectively.
5481 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5483 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5488 /* Subtract right from left, and compare the result to 0 */
5489 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5491 if (SUCCEEDED(hRet))
5493 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5495 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5496 hRet = (HRESULT)VARCMP_LT;
5498 hRet = (HRESULT)VARCMP_GT;
5500 hRet = (HRESULT)VARCMP_EQ;
5505 /************************************************************************
5506 * VarDecCmpR8 (OLEAUT32.298)
5508 * Compare a DECIMAL to a double
5511 * pDecLeft [I] DECIMAL Source
5512 * dblRight [I] double to compare to pDecLeft
5515 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5516 * is less than, equal to or greater than pDecLeft respectively.
5517 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5519 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5524 hRet = VarDecFromR8(dblRight, &decRight);
5526 if (SUCCEEDED(hRet))
5527 hRet = VarDecCmp(pDecLeft, &decRight);
5535 /************************************************************************
5536 * VarBoolFromUI1 (OLEAUT32.118)
5538 * Convert a VT_UI1 to a VT_BOOL.
5542 * pBoolOut [O] Destination
5547 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5549 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5553 /************************************************************************
5554 * VarBoolFromI2 (OLEAUT32.119)
5556 * Convert a VT_I2 to a VT_BOOL.
5560 * pBoolOut [O] Destination
5565 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5567 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5571 /************************************************************************
5572 * VarBoolFromI4 (OLEAUT32.120)
5574 * Convert a VT_I4 to a VT_BOOL.
5578 * pBoolOut [O] Destination
5583 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
5585 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
5589 /************************************************************************
5590 * VarBoolFromR4 (OLEAUT32.121)
5592 * Convert a VT_R4 to a VT_BOOL.
5596 * pBoolOut [O] Destination
5601 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
5603 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
5607 /************************************************************************
5608 * VarBoolFromR8 (OLEAUT32.122)
5610 * Convert a VT_R8 to a VT_BOOL.
5614 * pBoolOut [O] Destination
5619 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
5621 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
5625 /************************************************************************
5626 * VarBoolFromDate (OLEAUT32.123)
5628 * Convert a VT_DATE to a VT_BOOL.
5632 * pBoolOut [O] Destination
5637 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
5639 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
5643 /************************************************************************
5644 * VarBoolFromCy (OLEAUT32.124)
5646 * Convert a VT_CY to a VT_BOOL.
5650 * pBoolOut [O] Destination
5655 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
5657 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
5661 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
5665 hrsrc = FindResourceExW( OLEAUT32_hModule, (LPWSTR)RT_STRING,
5666 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
5669 HGLOBAL hmem = LoadResource( OLEAUT32_hModule, hrsrc );
5676 p = LockResource( hmem );
5677 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
5679 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
5680 lpszDest[*p] = '\0';
5681 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
5688 /************************************************************************
5689 * VarBoolFromStr (OLEAUT32.125)
5691 * Convert a VT_BSTR to a VT_BOOL.
5695 * lcid [I] LCID for the conversion
5696 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5697 * pBoolOut [O] Destination
5701 * Failure: E_INVALIDARG, if pBoolOut is invalid.
5702 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5705 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
5706 * it may contain (in any case mapping) the text "true" or "false".
5707 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
5708 * localised text of "True" or "False" in the language specified by lcid.
5709 * - If none of these matches occur, the string is treated as a numeric string
5710 * and the boolean pBoolOut will be set according to whether the number is zero
5711 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
5712 * - If the text is not numeric and does not match any of the above, then
5713 * DISP_E_TYPEMISMATCH is returned.
5715 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
5717 /* Any VB/VBA programmers out there should recognise these strings... */
5718 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
5719 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
5721 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5722 HRESULT hRes = S_OK;
5724 if (!strIn || !pBoolOut)
5725 return DISP_E_TYPEMISMATCH;
5727 /* Check if we should be comparing against localised text */
5728 if (dwFlags & VAR_LOCALBOOL)
5730 /* Convert our LCID into a usable value */
5731 lcid = ConvertDefaultLocale(lcid);
5733 langId = LANGIDFROMLCID(lcid);
5735 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
5736 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5738 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
5739 * I don't think this is needed unless any of the localised text strings
5740 * contain characters that can be so mapped. In the event that this is
5741 * true for a given language (possibly some Asian languages), then strIn
5742 * should be mapped here _only_ if langId is an Id for which this can occur.
5746 /* Note that if we are not comparing against localised strings, langId
5747 * will have its default value of LANG_ENGLISH. This allows us to mimic
5748 * the native behaviour of always checking against English strings even
5749 * after we've checked for localised ones.
5751 VarBoolFromStr_CheckLocalised:
5752 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
5754 /* Compare against localised strings, ignoring case */
5755 if (!strcmpiW(strIn, szBuff))
5757 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
5760 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
5761 if (!strcmpiW(strIn, szBuff))
5763 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
5768 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
5770 /* We have checked the localised text, now check English */
5771 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5772 goto VarBoolFromStr_CheckLocalised;
5775 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
5776 if (!strcmpW(strIn, szFalse))
5777 *pBoolOut = VARIANT_FALSE;
5778 else if (!strcmpW(strIn, szTrue))
5779 *pBoolOut = VARIANT_TRUE;
5784 /* If this string is a number, convert it as one */
5785 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
5786 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
5791 /************************************************************************
5792 * VarBoolFromDisp (OLEAUT32.126)
5794 * Convert a VT_DISPATCH to a VT_BOOL.
5797 * pdispIn [I] Source
5798 * lcid [I] LCID for conversion
5799 * pBoolOut [O] Destination
5803 * Failure: E_INVALIDARG, if the source value is invalid
5804 * DISP_E_OVERFLOW, if the value will not fit in the destination
5805 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5807 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
5809 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL);
5812 /************************************************************************
5813 * VarBoolFromI1 (OLEAUT32.233)
5815 * Convert a VT_I1 to a VT_BOOL.
5819 * pBoolOut [O] Destination
5824 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
5826 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
5830 /************************************************************************
5831 * VarBoolFromUI2 (OLEAUT32.234)
5833 * Convert a VT_UI2 to a VT_BOOL.
5837 * pBoolOut [O] Destination
5842 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
5844 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
5848 /************************************************************************
5849 * VarBoolFromUI4 (OLEAUT32.235)
5851 * Convert a VT_UI4 to a VT_BOOL.
5855 * pBoolOut [O] Destination
5860 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
5862 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
5866 /************************************************************************
5867 * VarBoolFromDec (OLEAUT32.236)
5869 * Convert a VT_DECIMAL to a VT_BOOL.
5873 * pBoolOut [O] Destination
5877 * Failure: E_INVALIDARG, if pDecIn is invalid.
5879 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
5881 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
5882 return E_INVALIDARG;
5884 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
5885 *pBoolOut = VARIANT_TRUE;
5887 *pBoolOut = VARIANT_FALSE;
5891 /************************************************************************
5892 * VarBoolFromI8 (OLEAUT32.370)
5894 * Convert a VT_I8 to a VT_BOOL.
5898 * pBoolOut [O] Destination
5903 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
5905 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
5909 /************************************************************************
5910 * VarBoolFromUI8 (OLEAUT32.371)
5912 * Convert a VT_UI8 to a VT_BOOL.
5916 * pBoolOut [O] Destination
5921 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
5923 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
5930 /* Write a number from a UI8 and sign */
5931 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
5935 WCHAR ulNextDigit = ulVal % 10;
5937 *szOut-- = '0' + ulNextDigit;
5938 ulVal = (ulVal - ulNextDigit) / 10;
5945 /* Create a (possibly localised) BSTR from a UI8 and sign */
5946 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
5948 WCHAR szConverted[256];
5950 if (dwFlags & VAR_NEGATIVE)
5953 if (dwFlags & LOCALE_USE_NLS)
5955 /* Format the number for the locale */
5956 szConverted[0] = '\0';
5957 GetNumberFormatW(lcid,
5958 dwFlags & LOCALE_NOUSEROVERRIDE,
5959 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
5960 szOut = szConverted;
5962 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
5965 /* Create a (possibly localised) BSTR from a UI8 and sign */
5966 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
5968 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
5971 return E_INVALIDARG;
5973 /* Create the basic number string */
5975 szOut = VARIANT_WriteNumber(ulVal, szOut);
5977 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
5978 TRACE("returning %s\n", debugstr_w(*pbstrOut));
5979 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
5982 /******************************************************************************
5983 * VarBstrFromUI1 (OLEAUT32.108)
5985 * Convert a VT_UI1 to a VT_BSTR.
5989 * lcid [I] LCID for the conversion
5990 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5991 * pbstrOut [O] Destination
5995 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5996 * E_OUTOFMEMORY, if memory allocation fails.
5998 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6000 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6003 /******************************************************************************
6004 * VarBstrFromI2 (OLEAUT32.109)
6006 * Convert a VT_I2 to a VT_BSTR.
6010 * lcid [I] LCID for the conversion
6011 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6012 * pbstrOut [O] Destination
6016 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6017 * E_OUTOFMEMORY, if memory allocation fails.
6019 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6026 dwFlags |= VAR_NEGATIVE;
6028 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6031 /******************************************************************************
6032 * VarBstrFromI4 (OLEAUT32.110)
6034 * Convert a VT_I4 to a VT_BSTR.
6038 * lcid [I] LCID for the conversion
6039 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6040 * pbstrOut [O] Destination
6044 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6045 * E_OUTOFMEMORY, if memory allocation fails.
6047 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6054 dwFlags |= VAR_NEGATIVE;
6056 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6059 static BSTR VARIANT_BstrReplaceDecimal(WCHAR * buff, LCID lcid, ULONG dwFlags)
6062 WCHAR lpDecimalSep[16];
6064 /* Native oleaut32 uses the locale-specific decimal separator even in the
6065 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6066 American locales will see "one thousand and one tenth" as "1000,1"
6067 instead of "1000.1" (notice the comma). The following code checks for
6068 the need to replace the decimal separator, and if so, will prepare an
6069 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6071 GetLocaleInfoW(lcid, LOCALE_SDECIMAL, lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
6072 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6074 /* locale is compatible with English - return original string */
6075 bstrOut = SysAllocString(buff);
6081 WCHAR empty[1] = {'\0'};
6082 NUMBERFMTW minFormat;
6084 minFormat.NumDigits = 0;
6085 minFormat.LeadingZero = 0;
6086 minFormat.Grouping = 0;
6087 minFormat.lpDecimalSep = lpDecimalSep;
6088 minFormat.lpThousandSep = empty;
6089 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6091 /* count number of decimal digits in string */
6092 p = strchrW( buff, '.' );
6093 if (p) minFormat.NumDigits = strlenW(p + 1);
6096 if (!GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6097 buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
6099 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6100 bstrOut = SysAllocString(buff);
6104 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6105 bstrOut = SysAllocString(numbuff);
6111 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6112 BSTR* pbstrOut, LPCWSTR lpszFormat)
6117 return E_INVALIDARG;
6119 sprintfW( buff, lpszFormat, dblIn );
6121 /* Negative zeroes are disallowed (some applications depend on this).
6122 If buff starts with a minus, and then nothing follows but zeroes
6123 and/or a period, it is a negative zero and is replaced with a
6124 canonical zero. This duplicates native oleaut32 behavior.
6128 const WCHAR szAccept[] = {'0', '.', '\0'};
6129 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
6130 { buff[0] = '0'; buff[1] = '\0'; }
6133 TRACE("created string %s\n", debugstr_w(buff));
6134 if (dwFlags & LOCALE_USE_NLS)
6138 /* Format the number for the locale */
6140 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6141 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6142 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6143 *pbstrOut = SysAllocString(numbuff);
6147 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6149 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6152 /******************************************************************************
6153 * VarBstrFromR4 (OLEAUT32.111)
6155 * Convert a VT_R4 to a VT_BSTR.
6159 * lcid [I] LCID for the conversion
6160 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6161 * pbstrOut [O] Destination
6165 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6166 * E_OUTOFMEMORY, if memory allocation fails.
6168 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6170 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
6173 /******************************************************************************
6174 * VarBstrFromR8 (OLEAUT32.112)
6176 * Convert a VT_R8 to a VT_BSTR.
6180 * lcid [I] LCID for the conversion
6181 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6182 * pbstrOut [O] Destination
6186 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6187 * E_OUTOFMEMORY, if memory allocation fails.
6189 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6191 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
6194 /******************************************************************************
6195 * VarBstrFromCy [OLEAUT32.113]
6197 * Convert a VT_CY to a VT_BSTR.
6201 * lcid [I] LCID for the conversion
6202 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6203 * pbstrOut [O] Destination
6207 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6208 * E_OUTOFMEMORY, if memory allocation fails.
6210 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6216 return E_INVALIDARG;
6218 VarR8FromCy(cyIn, &dblVal);
6219 sprintfW(buff, szDoubleFormatW, dblVal);
6221 if (dwFlags & LOCALE_USE_NLS)
6225 /* Format the currency for the locale */
6227 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6228 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR));
6229 *pbstrOut = SysAllocString(cybuff);
6232 *pbstrOut = SysAllocString(buff);
6234 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6237 /******************************************************************************
6238 * VarBstrFromDate [OLEAUT32.114]
6240 * Convert a VT_DATE to a VT_BSTR.
6244 * lcid [I] LCID for the conversion
6245 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6246 * pbstrOut [O] Destination
6250 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6251 * E_OUTOFMEMORY, if memory allocation fails.
6253 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6256 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6257 WCHAR date[128], *time;
6259 TRACE("(%g,0x%08lx,0x%08lx,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
6261 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6262 return E_INVALIDARG;
6266 if (dwFlags & VAR_CALENDAR_THAI)
6267 st.wYear += 553; /* Use the Thai buddhist calendar year */
6268 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6269 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6271 if (dwFlags & LOCALE_USE_NLS)
6272 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6275 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6276 double partial = dateIn - whole;
6279 dwFlags |= VAR_TIMEVALUEONLY;
6280 else if (partial < 1e-12)
6281 dwFlags |= VAR_DATEVALUEONLY;
6284 if (dwFlags & VAR_TIMEVALUEONLY)
6287 if (!GetDateFormatW(lcid, dwFormatFlags|DATE_SHORTDATE, &st, NULL, date,
6288 sizeof(date)/sizeof(WCHAR)))
6289 return E_INVALIDARG;
6291 if (!(dwFlags & VAR_DATEVALUEONLY))
6293 time = date + strlenW(date);
6296 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
6297 sizeof(date)/sizeof(WCHAR)-(time-date)))
6298 return E_INVALIDARG;
6301 *pbstrOut = SysAllocString(date);
6303 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6304 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6307 /******************************************************************************
6308 * VarBstrFromBool (OLEAUT32.116)
6310 * Convert a VT_BOOL to a VT_BSTR.
6314 * lcid [I] LCID for the conversion
6315 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6316 * pbstrOut [O] Destination
6320 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6321 * E_OUTOFMEMORY, if memory allocation fails.
6324 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6325 * localised text of "True" or "False". To convert a bool into a
6326 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6328 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6331 DWORD dwResId = IDS_TRUE;
6334 TRACE("%d,0x%08lx,0x%08lx,%p\n", boolIn, lcid, dwFlags, pbstrOut);
6337 return E_INVALIDARG;
6339 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6340 * for variant formatting */
6341 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6352 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6355 lcid = ConvertDefaultLocale(lcid);
6356 langId = LANGIDFROMLCID(lcid);
6357 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6358 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6360 if (boolIn == VARIANT_FALSE)
6361 dwResId++; /* Use negative form */
6363 VarBstrFromBool_GetLocalised:
6364 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6366 *pbstrOut = SysAllocString(szBuff);
6367 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6370 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6372 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6373 goto VarBstrFromBool_GetLocalised;
6376 /* Should never get here */
6377 WARN("Failed to load bool text!\n");
6378 return E_OUTOFMEMORY;
6381 /******************************************************************************
6382 * VarBstrFromI1 (OLEAUT32.229)
6384 * Convert a VT_I1 to a VT_BSTR.
6388 * lcid [I] LCID for the conversion
6389 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6390 * pbstrOut [O] Destination
6394 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6395 * E_OUTOFMEMORY, if memory allocation fails.
6397 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6404 dwFlags |= VAR_NEGATIVE;
6406 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6409 /******************************************************************************
6410 * VarBstrFromUI2 (OLEAUT32.230)
6412 * Convert a VT_UI2 to a VT_BSTR.
6416 * lcid [I] LCID for the conversion
6417 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6418 * pbstrOut [O] Destination
6422 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6423 * E_OUTOFMEMORY, if memory allocation fails.
6425 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6427 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6430 /******************************************************************************
6431 * VarBstrFromUI4 (OLEAUT32.231)
6433 * Convert a VT_UI4 to a VT_BSTR.
6437 * lcid [I] LCID for the conversion
6438 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6439 * pbstrOut [O] Destination
6443 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6444 * E_OUTOFMEMORY, if memory allocation fails.
6446 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6448 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
6451 /******************************************************************************
6452 * VarBstrFromDec (OLEAUT32.232)
6454 * Convert a VT_DECIMAL to a VT_BSTR.
6458 * lcid [I] LCID for the conversion
6459 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6460 * pbstrOut [O] Destination
6464 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6465 * E_OUTOFMEMORY, if memory allocation fails.
6467 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6473 return E_INVALIDARG;
6475 VARIANT_DIFromDec(pDecIn, &temp);
6476 VARIANT_DI_tostringW(&temp, buff, 256);
6478 if (dwFlags & LOCALE_USE_NLS)
6482 /* Format the number for the locale */
6484 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6485 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6486 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6487 *pbstrOut = SysAllocString(numbuff);
6491 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6494 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6495 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6498 /************************************************************************
6499 * VarBstrFromI8 (OLEAUT32.370)
6501 * Convert a VT_I8 to a VT_BSTR.
6505 * lcid [I] LCID for the conversion
6506 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6507 * pbstrOut [O] Destination
6511 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6512 * E_OUTOFMEMORY, if memory allocation fails.
6514 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6516 ULONG64 ul64 = llIn;
6521 dwFlags |= VAR_NEGATIVE;
6523 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6526 /************************************************************************
6527 * VarBstrFromUI8 (OLEAUT32.371)
6529 * Convert a VT_UI8 to a VT_BSTR.
6533 * lcid [I] LCID for the conversion
6534 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6535 * pbstrOut [O] Destination
6539 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6540 * E_OUTOFMEMORY, if memory allocation fails.
6542 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6544 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
6547 /**********************************************************************
6548 * VarBstrCat (OLEAUT32.313)
6550 * Concatenate two BSTR values.
6553 * pbstrLeft [I] Source
6554 * pbstrRight [I] Value to concatenate
6555 * pbstrOut [O] Destination
6559 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6560 * E_OUTOFMEMORY, if memory allocation fails.
6562 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
6567 return E_INVALIDARG;
6569 len = pbstrLeft ? strlenW(pbstrLeft) : 0;
6571 len += strlenW(pbstrRight);
6573 *pbstrOut = SysAllocStringLen(NULL, len);
6575 return E_OUTOFMEMORY;
6577 (*pbstrOut)[0] = '\0';
6580 strcpyW(*pbstrOut, pbstrLeft);
6583 strcatW(*pbstrOut, pbstrRight);
6588 /**********************************************************************
6589 * VarBstrCmp (OLEAUT32.314)
6591 * Compare two BSTR values.
6594 * pbstrLeft [I] Source
6595 * pbstrRight [I] Value to compare
6596 * lcid [I] LCID for the comparison
6597 * dwFlags [I] Flags to pass directly to CompareStringW().
6600 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
6601 * than, equal to or greater than pbstrRight respectively.
6602 * VARCMP_NULL is returned if either string is NULL, unless both are NULL
6603 * in which case VARCMP_EQ is returned.
6605 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
6609 if (!pbstrRight || !*pbstrRight)
6613 else if (!pbstrRight)
6620 return CompareStringW(lcid, dwFlags, pbstrLeft, -1, pbstrRight, -1) - 1;
6627 /******************************************************************************
6628 * VarDateFromUI1 (OLEAUT32.88)
6630 * Convert a VT_UI1 to a VT_DATE.
6634 * pdateOut [O] Destination
6639 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
6641 return VarR8FromUI1(bIn, pdateOut);
6644 /******************************************************************************
6645 * VarDateFromI2 (OLEAUT32.89)
6647 * Convert a VT_I2 to a VT_DATE.
6651 * pdateOut [O] Destination
6656 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
6658 return VarR8FromI2(sIn, pdateOut);
6661 /******************************************************************************
6662 * VarDateFromI4 (OLEAUT32.90)
6664 * Convert a VT_I4 to a VT_DATE.
6668 * pdateOut [O] Destination
6673 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
6675 return VarDateFromR8(lIn, pdateOut);
6678 /******************************************************************************
6679 * VarDateFromR4 (OLEAUT32.91)
6681 * Convert a VT_R4 to a VT_DATE.
6685 * pdateOut [O] Destination
6690 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
6692 return VarR8FromR4(fltIn, pdateOut);
6695 /******************************************************************************
6696 * VarDateFromR8 (OLEAUT32.92)
6698 * Convert a VT_R8 to a VT_DATE.
6702 * pdateOut [O] Destination
6707 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
6709 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
6710 *pdateOut = (DATE)dblIn;
6714 /**********************************************************************
6715 * VarDateFromDisp (OLEAUT32.95)
6717 * Convert a VT_DISPATCH to a VT_DATE.
6720 * pdispIn [I] Source
6721 * lcid [I] LCID for conversion
6722 * pdateOut [O] Destination
6726 * Failure: E_INVALIDARG, if the source value is invalid
6727 * DISP_E_OVERFLOW, if the value will not fit in the destination
6728 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6730 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
6732 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE);
6735 /******************************************************************************
6736 * VarDateFromBool (OLEAUT32.96)
6738 * Convert a VT_BOOL to a VT_DATE.
6742 * pdateOut [O] Destination
6747 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
6749 return VarR8FromBool(boolIn, pdateOut);
6752 /**********************************************************************
6753 * VarDateFromCy (OLEAUT32.93)
6755 * Convert a VT_CY to a VT_DATE.
6759 * pdateOut [O] Destination
6764 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
6766 return VarR8FromCy(cyIn, pdateOut);
6769 /* Date string parsing */
6770 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
6771 #define DP_DATESEP 0x02 /* Date separator */
6772 #define DP_MONTH 0x04 /* Month name */
6773 #define DP_AM 0x08 /* AM */
6774 #define DP_PM 0x10 /* PM */
6776 typedef struct tagDATEPARSE
6778 DWORD dwCount; /* Number of fields found so far (maximum 6) */
6779 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
6780 DWORD dwFlags[6]; /* Flags for each field */
6781 DWORD dwValues[6]; /* Value of each field */
6784 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
6786 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
6788 /* Determine if a day is valid in a given month of a given year */
6789 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
6791 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
6793 if (day && month && month < 13)
6795 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
6801 /* Possible orders for 3 numbers making up a date */
6802 #define ORDER_MDY 0x01
6803 #define ORDER_YMD 0x02
6804 #define ORDER_YDM 0x04
6805 #define ORDER_DMY 0x08
6806 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
6808 /* Determine a date for a particular locale, from 3 numbers */
6809 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
6810 DWORD offset, SYSTEMTIME *st)
6812 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
6816 v1 = 30; /* Default to (Variant) 0 date part */
6819 goto VARIANT_MakeDate_OK;
6822 v1 = dp->dwValues[offset + 0];
6823 v2 = dp->dwValues[offset + 1];
6824 if (dp->dwCount == 2)
6827 GetSystemTime(¤t);
6831 v3 = dp->dwValues[offset + 2];
6833 TRACE("(%ld,%ld,%ld,%ld,%ld)\n", v1, v2, v3, iDate, offset);
6835 /* If one number must be a month (Because a month name was given), then only
6836 * consider orders with the month in that position.
6837 * If we took the current year as 'v3', then only allow a year in that position.
6839 if (dp->dwFlags[offset + 0] & DP_MONTH)
6841 dwAllOrders = ORDER_MDY;
6843 else if (dp->dwFlags[offset + 1] & DP_MONTH)
6845 dwAllOrders = ORDER_DMY;
6846 if (dp->dwCount > 2)
6847 dwAllOrders |= ORDER_YMD;
6849 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
6851 dwAllOrders = ORDER_YDM;
6855 dwAllOrders = ORDER_MDY|ORDER_DMY;
6856 if (dp->dwCount > 2)
6857 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
6860 VARIANT_MakeDate_Start:
6861 TRACE("dwAllOrders is 0x%08lx\n", dwAllOrders);
6869 /* First: Try the order given by iDate */
6872 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
6873 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
6874 default: dwTry = dwAllOrders & ORDER_YMD; break;
6877 else if (dwCount == 1)
6879 /* Second: Try all the orders compatible with iDate */
6882 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
6883 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break;
6884 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
6889 /* Finally: Try any remaining orders */
6890 dwTry = dwAllOrders;
6893 TRACE("Attempt %ld, dwTry is 0x%08lx\n", dwCount, dwTry);
6899 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
6901 if (dwTry & ORDER_MDY)
6903 if (VARIANT_IsValidMonthDay(v2,v1,v3))
6906 goto VARIANT_MakeDate_OK;
6908 dwAllOrders &= ~ORDER_MDY;
6910 if (dwTry & ORDER_YMD)
6912 if (VARIANT_IsValidMonthDay(v3,v2,v1))
6915 goto VARIANT_MakeDate_OK;
6917 dwAllOrders &= ~ORDER_YMD;
6919 if (dwTry & ORDER_YDM)
6921 if (VARIANT_IsValidMonthDay(v2,v3,v1))
6925 goto VARIANT_MakeDate_OK;
6927 dwAllOrders &= ~ORDER_YDM;
6929 if (dwTry & ORDER_DMY)
6931 if (VARIANT_IsValidMonthDay(v1,v2,v3))
6932 goto VARIANT_MakeDate_OK;
6933 dwAllOrders &= ~ORDER_DMY;
6935 if (dwTry & ORDER_MYD)
6937 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
6938 if (VARIANT_IsValidMonthDay(v3,v1,v2))
6942 goto VARIANT_MakeDate_OK;
6944 dwAllOrders &= ~ORDER_MYD;
6948 if (dp->dwCount == 2)
6950 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
6951 v3 = 1; /* 1st of the month */
6952 dwAllOrders = ORDER_YMD|ORDER_MYD;
6953 dp->dwCount = 0; /* Don't return to this code path again */
6955 goto VARIANT_MakeDate_Start;
6958 /* No valid dates were able to be constructed */
6959 return DISP_E_TYPEMISMATCH;
6961 VARIANT_MakeDate_OK:
6963 /* Check that the time part is ok */
6964 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
6965 return DISP_E_TYPEMISMATCH;
6967 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
6968 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
6970 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
6972 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
6976 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
6977 * be retrieved from:
6978 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
6979 * But Wine doesn't have/use that key as at the time of writing.
6981 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
6982 TRACE("Returning date %ld/%ld/%d\n", v1, v2, st->wYear);
6986 /******************************************************************************
6987 * VarDateFromStr [OLEAUT32.94]
6989 * Convert a VT_BSTR to at VT_DATE.
6992 * strIn [I] String to convert
6993 * lcid [I] Locale identifier for the conversion
6994 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
6995 * pdateOut [O] Destination for the converted value
6998 * Success: S_OK. pdateOut contains the converted value.
6999 * FAILURE: An HRESULT error code indicating the prolem.
7002 * Any date format that can be created using the date formats from lcid
7003 * (Either from kernel Nls functions, variant conversion or formatting) is a
7004 * valid input to this function. In addition, a few more esoteric formats are
7005 * also supported for compatibility with the native version. The date is
7006 * interpreted according to the date settings in the control panel, unless
7007 * the date is invalid in that format, in which the most compatible format
7008 * that produces a valid date will be used.
7010 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7012 static const USHORT ParseDateTokens[] =
7014 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7015 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7016 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7017 LOCALE_SMONTHNAME13,
7018 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7019 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7020 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7021 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7022 LOCALE_SABBREVMONTHNAME13,
7023 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7024 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7025 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7026 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7027 LOCALE_SABBREVDAYNAME7,
7028 LOCALE_S1159, LOCALE_S2359
7030 static const BYTE ParseDateMonths[] =
7032 1,2,3,4,5,6,7,8,9,10,11,12,13,
7033 1,2,3,4,5,6,7,8,9,10,11,12,13
7036 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
7038 DWORD dwDateSeps = 0, iDate = 0;
7039 HRESULT hRet = S_OK;
7041 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7042 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7043 return E_INVALIDARG;
7046 return DISP_E_TYPEMISMATCH;
7050 TRACE("(%s,0x%08lx,0x%08lx,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7052 memset(&dp, 0, sizeof(dp));
7054 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7055 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7056 TRACE("iDate is %ld\n", iDate);
7058 /* Get the month/day/am/pm tokens for this locale */
7059 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7062 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7064 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7065 * GetAltMonthNames(). We should really cache these strings too.
7068 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
7069 tokens[i] = SysAllocString(buff);
7070 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7073 /* Parse the string into our structure */
7079 if (isdigitW(*strIn))
7081 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
7085 else if (isalpha(*strIn))
7087 BOOL bFound = FALSE;
7089 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7091 DWORD dwLen = strlenW(tokens[i]);
7092 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
7096 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7097 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7102 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7103 hRet = DISP_E_TYPEMISMATCH;
7106 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7107 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7110 strIn += (dwLen - 1);
7118 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7119 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7121 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7122 if (*strIn == 'a' || *strIn == 'A')
7124 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7125 dp.dwParseFlags |= DP_AM;
7129 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7130 dp.dwParseFlags |= DP_PM;
7136 TRACE("No matching token for %s\n", debugstr_w(strIn));
7137 hRet = DISP_E_TYPEMISMATCH;
7142 else if (*strIn == ':' || *strIn == '.')
7144 if (!dp.dwCount || !strIn[1])
7145 hRet = DISP_E_TYPEMISMATCH;
7147 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7149 else if (*strIn == '-' || *strIn == '/')
7152 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7153 hRet = DISP_E_TYPEMISMATCH;
7155 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7157 else if (*strIn == ',' || isspaceW(*strIn))
7159 if (*strIn == ',' && !strIn[1])
7160 hRet = DISP_E_TYPEMISMATCH;
7164 hRet = DISP_E_TYPEMISMATCH;
7169 if (!dp.dwCount || dp.dwCount > 6 ||
7170 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7171 hRet = DISP_E_TYPEMISMATCH;
7173 if (SUCCEEDED(hRet))
7176 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7178 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7180 /* Figure out which numbers correspond to which fields.
7182 * This switch statement works based on the fact that native interprets any
7183 * fields that are not joined with a time separator ('.' or ':') as date
7184 * fields. Thus we construct a value from 0-32 where each set bit indicates
7185 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7186 * For valid permutations, we set dwOffset to point to the first date field
7187 * and shorten dp.dwCount by the number of time fields found. The real
7188 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7189 * each date number must represent in the context of iDate.
7191 TRACE("0x%08lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7193 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7195 case 0x1: /* TT TTDD TTDDD */
7196 if (dp.dwCount > 3 &&
7197 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7198 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7199 hRet = DISP_E_TYPEMISMATCH;
7200 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7201 hRet = DISP_E_TYPEMISMATCH;
7202 st.wHour = dp.dwValues[0];
7203 st.wMinute = dp.dwValues[1];
7208 case 0x3: /* TTT TTTDD TTTDDD */
7209 if (dp.dwCount > 4 &&
7210 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7211 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7212 hRet = DISP_E_TYPEMISMATCH;
7213 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7214 hRet = DISP_E_TYPEMISMATCH;
7215 st.wHour = dp.dwValues[0];
7216 st.wMinute = dp.dwValues[1];
7217 st.wSecond = dp.dwValues[2];
7222 case 0x4: /* DDTT */
7223 if (dp.dwCount != 4 ||
7224 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7225 hRet = DISP_E_TYPEMISMATCH;
7227 st.wHour = dp.dwValues[2];
7228 st.wMinute = dp.dwValues[3];
7232 case 0x0: /* T DD DDD TDDD TDDD */
7233 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7235 st.wHour = dp.dwValues[0]; /* T */
7239 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7241 hRet = DISP_E_TYPEMISMATCH;
7243 else if (dp.dwCount == 3)
7245 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7248 st.wHour = dp.dwValues[0];
7252 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7255 st.wHour = dp.dwValues[2];
7258 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7259 hRet = DISP_E_TYPEMISMATCH;
7261 else if (dp.dwCount == 4)
7264 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7266 st.wHour = dp.dwValues[0];
7269 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7271 st.wHour = dp.dwValues[3];
7274 hRet = DISP_E_TYPEMISMATCH;
7277 /* .. fall through .. */
7279 case 0x8: /* DDDTT */
7280 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7281 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7282 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7283 dp.dwCount == 4 || dp.dwCount == 6)
7284 hRet = DISP_E_TYPEMISMATCH;
7285 st.wHour = dp.dwValues[3];
7286 st.wMinute = dp.dwValues[4];
7287 if (dp.dwCount == 5)
7291 case 0xC: /* DDTTT */
7292 if (dp.dwCount != 5 ||
7293 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7294 hRet = DISP_E_TYPEMISMATCH;
7295 st.wHour = dp.dwValues[2];
7296 st.wMinute = dp.dwValues[3];
7297 st.wSecond = dp.dwValues[4];
7301 case 0x18: /* DDDTTT */
7302 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7303 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7304 hRet = DISP_E_TYPEMISMATCH;
7305 st.wHour = dp.dwValues[3];
7306 st.wMinute = dp.dwValues[4];
7307 st.wSecond = dp.dwValues[5];
7312 hRet = DISP_E_TYPEMISMATCH;
7316 if (SUCCEEDED(hRet))
7318 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7320 if (dwFlags & VAR_TIMEVALUEONLY)
7326 else if (dwFlags & VAR_DATEVALUEONLY)
7327 st.wHour = st.wMinute = st.wSecond = 0;
7329 /* Finally, convert the value to a VT_DATE */
7330 if (SUCCEEDED(hRet))
7331 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7335 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7336 SysFreeString(tokens[i]);
7340 /******************************************************************************
7341 * VarDateFromI1 (OLEAUT32.221)
7343 * Convert a VT_I1 to a VT_DATE.
7347 * pdateOut [O] Destination
7352 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7354 return VarR8FromI1(cIn, pdateOut);
7357 /******************************************************************************
7358 * VarDateFromUI2 (OLEAUT32.222)
7360 * Convert a VT_UI2 to a VT_DATE.
7364 * pdateOut [O] Destination
7369 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7371 return VarR8FromUI2(uiIn, pdateOut);
7374 /******************************************************************************
7375 * VarDateFromUI4 (OLEAUT32.223)
7377 * Convert a VT_UI4 to a VT_DATE.
7381 * pdateOut [O] Destination
7386 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7388 return VarDateFromR8(ulIn, pdateOut);
7391 /**********************************************************************
7392 * VarDateFromDec (OLEAUT32.224)
7394 * Convert a VT_DECIMAL to a VT_DATE.
7398 * pdateOut [O] Destination
7403 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
7405 return VarR8FromDec(pdecIn, pdateOut);
7408 /******************************************************************************
7409 * VarDateFromI8 (OLEAUT32.364)
7411 * Convert a VT_I8 to a VT_DATE.
7415 * pdateOut [O] Destination
7419 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7421 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
7423 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
7424 *pdateOut = (DATE)llIn;
7428 /******************************************************************************
7429 * VarDateFromUI8 (OLEAUT32.365)
7431 * Convert a VT_UI8 to a VT_DATE.
7435 * pdateOut [O] Destination
7439 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7441 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
7443 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
7444 *pdateOut = (DATE)ullIn;