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;
2970 *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart;
2974 /************************************************************************
2975 * VarR4FromI8 (OLEAUT32.360)
2977 * Convert a VT_I8 to a VT_R4.
2981 * pFltOut [O] Destination
2986 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2988 return _VarR4FromI8(llIn, pFltOut);
2991 /************************************************************************
2992 * VarR4FromUI8 (OLEAUT32.361)
2994 * Convert a VT_UI8 to a VT_R4.
2998 * pFltOut [O] Destination
3003 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
3005 return _VarR4FromUI8(ullIn, pFltOut);
3008 /************************************************************************
3009 * VarR4CmpR8 (OLEAUT32.316)
3011 * Compare a VT_R4 to a VT_R8.
3014 * fltLeft [I] Source
3015 * dblRight [I] Value to compare
3018 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3019 * equal to or greater than dblRight respectively.
3021 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3023 if (fltLeft < dblRight)
3025 else if (fltLeft > dblRight)
3033 /************************************************************************
3034 * VarR8FromUI1 (OLEAUT32.78)
3036 * Convert a VT_UI1 to a VT_R8.
3040 * pDblOut [O] Destination
3045 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3047 return _VarR8FromUI1(bIn, pDblOut);
3050 /************************************************************************
3051 * VarR8FromI2 (OLEAUT32.79)
3053 * Convert a VT_I2 to a VT_R8.
3057 * pDblOut [O] Destination
3062 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3064 return _VarR8FromI2(sIn, pDblOut);
3067 /************************************************************************
3068 * VarR8FromI4 (OLEAUT32.80)
3070 * Convert a VT_I4 to a VT_R8.
3074 * pDblOut [O] Destination
3079 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3081 return _VarR8FromI4(lIn, pDblOut);
3084 /************************************************************************
3085 * VarR8FromR4 (OLEAUT32.81)
3087 * Convert a VT_R4 to a VT_R8.
3091 * pDblOut [O] Destination
3096 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3098 return _VarR8FromR4(fltIn, pDblOut);
3101 /************************************************************************
3102 * VarR8FromCy (OLEAUT32.82)
3104 * Convert a VT_CY to a VT_R8.
3108 * pDblOut [O] Destination
3113 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3115 return _VarR8FromCy(cyIn, pDblOut);
3118 /************************************************************************
3119 * VarR8FromDate (OLEAUT32.83)
3121 * Convert a VT_DATE to a VT_R8.
3125 * pDblOut [O] Destination
3130 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3132 return _VarR8FromDate(dateIn, pDblOut);
3135 /************************************************************************
3136 * VarR8FromStr (OLEAUT32.84)
3138 * Convert a VT_BSTR to a VT_R8.
3142 * lcid [I] LCID for the conversion
3143 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3144 * pDblOut [O] Destination
3148 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3149 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3151 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3153 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3156 /************************************************************************
3157 * VarR8FromDisp (OLEAUT32.85)
3159 * Convert a VT_DISPATCH to a VT_R8.
3162 * pdispIn [I] Source
3163 * lcid [I] LCID for conversion
3164 * pDblOut [O] Destination
3168 * Failure: E_INVALIDARG, if the source value is invalid
3169 * DISP_E_OVERFLOW, if the value will not fit in the destination
3170 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3172 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3174 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8);
3177 /************************************************************************
3178 * VarR8FromBool (OLEAUT32.86)
3180 * Convert a VT_BOOL to a VT_R8.
3184 * pDblOut [O] Destination
3189 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3191 return VarR8FromI2(boolIn, pDblOut);
3194 /************************************************************************
3195 * VarR8FromI1 (OLEAUT32.217)
3197 * Convert a VT_I1 to a VT_R8.
3201 * pDblOut [O] Destination
3205 * Failure: E_INVALIDARG, if the source value is invalid
3206 * DISP_E_OVERFLOW, if the value will not fit in the destination
3207 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3209 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3211 return _VarR8FromI1(cIn, pDblOut);
3214 /************************************************************************
3215 * VarR8FromUI2 (OLEAUT32.218)
3217 * Convert a VT_UI2 to a VT_R8.
3221 * pDblOut [O] Destination
3225 * Failure: E_INVALIDARG, if the source value is invalid
3226 * DISP_E_OVERFLOW, if the value will not fit in the destination
3227 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3229 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3231 return _VarR8FromUI2(usIn, pDblOut);
3234 /************************************************************************
3235 * VarR8FromUI4 (OLEAUT32.219)
3237 * Convert a VT_UI4 to a VT_R8.
3241 * pDblOut [O] Destination
3245 * Failure: E_INVALIDARG, if the source value is invalid
3246 * DISP_E_OVERFLOW, if the value will not fit in the destination
3247 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3249 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3251 return _VarR8FromUI4(ulIn, pDblOut);
3254 /************************************************************************
3255 * VarR8FromDec (OLEAUT32.220)
3257 * Convert a VT_DECIMAL to a VT_R8.
3261 * pDblOut [O] Destination
3265 * Failure: E_INVALIDARG, if the source value is invalid.
3267 HRESULT WINAPI VarR8FromDec(DECIMAL* pDecIn, double *pDblOut)
3269 BYTE scale = DEC_SCALE(pDecIn);
3270 double divisor = 1.0, highPart;
3272 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3273 return E_INVALIDARG;
3278 if (DEC_SIGN(pDecIn))
3281 if (DEC_HI32(pDecIn))
3283 highPart = (double)DEC_HI32(pDecIn) / divisor;
3289 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3293 /************************************************************************
3294 * VarR8FromI8 (OLEAUT32.362)
3296 * Convert a VT_I8 to a VT_R8.
3300 * pDblOut [O] Destination
3305 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3307 return _VarR8FromI8(llIn, pDblOut);
3310 /************************************************************************
3311 * VarR8FromUI8 (OLEAUT32.363)
3313 * Convert a VT_UI8 to a VT_R8.
3317 * pDblOut [O] Destination
3322 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3324 return _VarR8FromUI8(ullIn, pDblOut);
3327 /************************************************************************
3328 * VarR8Pow (OLEAUT32.315)
3330 * Raise a VT_R8 to a power.
3333 * dblLeft [I] Source
3334 * dblPow [I] Power to raise dblLeft by
3335 * pDblOut [O] Destination
3338 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3340 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3342 *pDblOut = pow(dblLeft, dblPow);
3346 /************************************************************************
3347 * VarR8Round (OLEAUT32.317)
3349 * Round a VT_R8 to a given number of decimal points.
3353 * nDig [I] Number of decimal points to round to
3354 * pDblOut [O] Destination for rounded number
3357 * Success: S_OK. pDblOut is rounded to nDig digits.
3358 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3361 * The native version of this function rounds using the internal
3362 * binary representation of the number. Wine uses the dutch rounding
3363 * convention, so therefore small differences can occur in the value returned.
3364 * MSDN says that you should use your own rounding function if you want
3365 * rounding to be predictable in your application.
3367 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3369 double scale, whole, fract;
3372 return E_INVALIDARG;
3374 scale = pow(10.0, nDig);
3377 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3378 fract = dblIn - whole;
3381 dblIn = whole + 1.0;
3382 else if (fract == 0.5)
3383 dblIn = whole + fmod(whole, 2.0);
3384 else if (fract >= 0.0)
3386 else if (fract == -0.5)
3387 dblIn = whole - fmod(whole, 2.0);
3388 else if (fract > -0.5)
3391 dblIn = whole - 1.0;
3393 *pDblOut = dblIn / scale;
3400 /* Powers of 10 from 0..4 D.P. */
3401 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3402 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3404 /************************************************************************
3405 * VarCyFromUI1 (OLEAUT32.98)
3407 * Convert a VT_UI1 to a VT_CY.
3411 * pCyOut [O] Destination
3415 * Failure: E_INVALIDARG, if the source value is invalid
3416 * DISP_E_OVERFLOW, if the value will not fit in the destination
3417 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3419 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3421 return VarCyFromR8(bIn, pCyOut);
3424 /************************************************************************
3425 * VarCyFromI2 (OLEAUT32.99)
3427 * Convert a VT_I2 to a VT_CY.
3431 * pCyOut [O] Destination
3435 * Failure: E_INVALIDARG, if the source value is invalid
3436 * DISP_E_OVERFLOW, if the value will not fit in the destination
3437 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3439 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3441 return VarCyFromR8(sIn, pCyOut);
3444 /************************************************************************
3445 * VarCyFromI4 (OLEAUT32.100)
3447 * Convert a VT_I4 to a VT_CY.
3451 * pCyOut [O] Destination
3455 * Failure: E_INVALIDARG, if the source value is invalid
3456 * DISP_E_OVERFLOW, if the value will not fit in the destination
3457 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3459 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3461 return VarCyFromR8(lIn, pCyOut);
3464 /************************************************************************
3465 * VarCyFromR4 (OLEAUT32.101)
3467 * Convert a VT_R4 to a VT_CY.
3471 * pCyOut [O] Destination
3475 * Failure: E_INVALIDARG, if the source value is invalid
3476 * DISP_E_OVERFLOW, if the value will not fit in the destination
3477 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3479 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3481 return VarCyFromR8(fltIn, pCyOut);
3484 /************************************************************************
3485 * VarCyFromR8 (OLEAUT32.102)
3487 * Convert a VT_R8 to a VT_CY.
3491 * pCyOut [O] Destination
3495 * Failure: E_INVALIDARG, if the source value is invalid
3496 * DISP_E_OVERFLOW, if the value will not fit in the destination
3497 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3499 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3501 #if defined(__GNUC__) && defined(__i386__)
3502 /* This code gives identical results to Win32 on Intel.
3503 * Here we use fp exceptions to catch overflows when storing the value.
3505 static const unsigned short r8_fpcontrol = 0x137f;
3506 static const double r8_multiplier = CY_MULTIPLIER_F;
3507 unsigned short old_fpcontrol, result_fpstatus;
3509 /* Clear exceptions, save the old fp state and load the new state */
3510 __asm__ __volatile__( "fnclex" );
3511 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3512 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3513 /* Perform the conversion. */
3514 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3515 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3516 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3517 /* Save the resulting fp state, load the old state and clear exceptions */
3518 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3519 __asm__ __volatile__( "fnclex" );
3520 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3522 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3523 return DISP_E_OVERFLOW;
3526 /* This version produces slightly different results for boundary cases */
3527 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3528 return DISP_E_OVERFLOW;
3529 dblIn *= CY_MULTIPLIER_F;
3530 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3535 /************************************************************************
3536 * VarCyFromDate (OLEAUT32.103)
3538 * Convert a VT_DATE to a VT_CY.
3542 * pCyOut [O] Destination
3546 * Failure: E_INVALIDARG, if the source value is invalid
3547 * DISP_E_OVERFLOW, if the value will not fit in the destination
3548 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3550 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3552 return VarCyFromR8(dateIn, pCyOut);
3555 /************************************************************************
3556 * VarCyFromStr (OLEAUT32.104)
3558 * Convert a VT_BSTR to a VT_CY.
3562 * lcid [I] LCID for the conversion
3563 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3564 * pCyOut [O] Destination
3568 * Failure: E_INVALIDARG, if the source value is invalid
3569 * DISP_E_OVERFLOW, if the value will not fit in the destination
3570 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3572 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3574 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3577 /************************************************************************
3578 * VarCyFromDisp (OLEAUT32.105)
3580 * Convert a VT_DISPATCH to a VT_CY.
3583 * pdispIn [I] Source
3584 * lcid [I] LCID for conversion
3585 * pCyOut [O] Destination
3589 * Failure: E_INVALIDARG, if the source value is invalid
3590 * DISP_E_OVERFLOW, if the value will not fit in the destination
3591 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3593 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3595 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY);
3598 /************************************************************************
3599 * VarCyFromBool (OLEAUT32.106)
3601 * Convert a VT_BOOL to a VT_CY.
3605 * pCyOut [O] Destination
3609 * Failure: E_INVALIDARG, if the source value is invalid
3610 * DISP_E_OVERFLOW, if the value will not fit in the destination
3611 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3614 * While the sign of the boolean is stored in the currency, the value is
3615 * converted to either 0 or 1.
3617 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3619 return VarCyFromR8(boolIn, pCyOut);
3622 /************************************************************************
3623 * VarCyFromI1 (OLEAUT32.225)
3625 * Convert a VT_I1 to a VT_CY.
3629 * pCyOut [O] Destination
3633 * Failure: E_INVALIDARG, if the source value is invalid
3634 * DISP_E_OVERFLOW, if the value will not fit in the destination
3635 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3637 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3639 return VarCyFromR8(cIn, pCyOut);
3642 /************************************************************************
3643 * VarCyFromUI2 (OLEAUT32.226)
3645 * Convert a VT_UI2 to a VT_CY.
3649 * pCyOut [O] Destination
3653 * Failure: E_INVALIDARG, if the source value is invalid
3654 * DISP_E_OVERFLOW, if the value will not fit in the destination
3655 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3657 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3659 return VarCyFromR8(usIn, pCyOut);
3662 /************************************************************************
3663 * VarCyFromUI4 (OLEAUT32.227)
3665 * Convert a VT_UI4 to a VT_CY.
3669 * pCyOut [O] Destination
3673 * Failure: E_INVALIDARG, if the source value is invalid
3674 * DISP_E_OVERFLOW, if the value will not fit in the destination
3675 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3677 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3679 return VarCyFromR8(ulIn, pCyOut);
3682 /************************************************************************
3683 * VarCyFromDec (OLEAUT32.228)
3685 * Convert a VT_DECIMAL to a VT_CY.
3689 * pCyOut [O] Destination
3693 * Failure: E_INVALIDARG, if the source value is invalid
3694 * DISP_E_OVERFLOW, if the value will not fit in the destination
3695 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3697 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
3702 hRet = VarDecRound(pdecIn, 4, &rounded);
3704 if (SUCCEEDED(hRet))
3708 if (DEC_HI32(&rounded))
3709 return DISP_E_OVERFLOW;
3711 /* Note: Without the casts this promotes to int64 which loses precision */
3712 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3713 if (DEC_SIGN(&rounded))
3715 return VarCyFromR8(d, pCyOut);
3720 /************************************************************************
3721 * VarCyFromI8 (OLEAUT32.366)
3723 * Convert a VT_I8 to a VT_CY.
3727 * pCyOut [O] Destination
3731 * Failure: E_INVALIDARG, if the source value is invalid
3732 * DISP_E_OVERFLOW, if the value will not fit in the destination
3733 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3735 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3737 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3738 pCyOut->int64 = llIn * CY_MULTIPLIER;
3742 /************************************************************************
3743 * VarCyFromUI8 (OLEAUT32.375)
3745 * Convert a VT_UI8 to a VT_CY.
3749 * pCyOut [O] Destination
3753 * Failure: E_INVALIDARG, if the source value is invalid
3754 * DISP_E_OVERFLOW, if the value will not fit in the destination
3755 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3757 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3759 return VarCyFromR8(ullIn, pCyOut);
3762 /************************************************************************
3763 * VarCyAdd (OLEAUT32.299)
3765 * Add one CY to another.
3769 * cyRight [I] Value to add
3770 * pCyOut [O] Destination
3774 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3776 HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut)
3779 _VarR8FromCy(cyLeft, &l);
3780 _VarR8FromCy(cyRight, &r);
3782 return VarCyFromR8(l, pCyOut);
3785 /************************************************************************
3786 * VarCyMul (OLEAUT32.303)
3788 * Multiply one CY by another.
3792 * cyRight [I] Value to multiply by
3793 * pCyOut [O] Destination
3797 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3799 HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut)
3802 _VarR8FromCy(cyLeft, &l);
3803 _VarR8FromCy(cyRight, &r);
3805 return VarCyFromR8(l, pCyOut);
3808 /************************************************************************
3809 * VarCyMulI4 (OLEAUT32.304)
3811 * Multiply one CY by a VT_I4.
3815 * lRight [I] Value to multiply by
3816 * pCyOut [O] Destination
3820 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3822 HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut)
3826 _VarR8FromCy(cyLeft, &d);
3828 return VarCyFromR8(d, pCyOut);
3831 /************************************************************************
3832 * VarCySub (OLEAUT32.305)
3834 * Subtract one CY from another.
3838 * cyRight [I] Value to subtract
3839 * pCyOut [O] Destination
3843 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3845 HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut)
3848 _VarR8FromCy(cyLeft, &l);
3849 _VarR8FromCy(cyRight, &r);
3851 return VarCyFromR8(l, pCyOut);
3854 /************************************************************************
3855 * VarCyAbs (OLEAUT32.306)
3857 * Convert a VT_CY into its absolute value.
3861 * pCyOut [O] Destination
3864 * Success: S_OK. pCyOut contains the absolute value.
3865 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3867 HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut)
3869 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3870 return DISP_E_OVERFLOW;
3872 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3876 /************************************************************************
3877 * VarCyFix (OLEAUT32.307)
3879 * Return the integer part of a VT_CY.
3883 * pCyOut [O] Destination
3887 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3890 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3891 * negative numbers away from 0, while this function rounds them towards zero.
3893 HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut)
3895 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3896 pCyOut->int64 *= CY_MULTIPLIER;
3900 /************************************************************************
3901 * VarCyInt (OLEAUT32.308)
3903 * Return the integer part of a VT_CY.
3907 * pCyOut [O] Destination
3911 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3914 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3915 * negative numbers towards 0, while this function rounds them away from zero.
3917 HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut)
3919 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3920 pCyOut->int64 *= CY_MULTIPLIER;
3922 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3924 pCyOut->int64 -= CY_MULTIPLIER;
3929 /************************************************************************
3930 * VarCyNeg (OLEAUT32.309)
3932 * Change the sign of a VT_CY.
3936 * pCyOut [O] Destination
3940 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3942 HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut)
3944 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3945 return DISP_E_OVERFLOW;
3947 pCyOut->int64 = -cyIn.int64;
3951 /************************************************************************
3952 * VarCyRound (OLEAUT32.310)
3954 * Change the precision of a VT_CY.
3958 * cDecimals [I] New number of decimals to keep
3959 * pCyOut [O] Destination
3963 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3965 HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
3968 return E_INVALIDARG;
3972 /* Rounding to more precision than we have */
3978 double d, div = CY_Divisors[cDecimals];
3980 _VarR8FromCy(cyIn, &d);
3982 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3983 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3984 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3989 /************************************************************************
3990 * VarCyCmp (OLEAUT32.311)
3992 * Compare two VT_CY values.
3996 * cyRight [I] Value to compare
3999 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4000 * compare is less, equal or greater than source respectively.
4001 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4003 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
4008 /* Subtract right from left, and compare the result to 0 */
4009 hRet = VarCySub(cyLeft, cyRight, &result);
4011 if (SUCCEEDED(hRet))
4013 if (result.int64 < 0)
4014 hRet = (HRESULT)VARCMP_LT;
4015 else if (result.int64 > 0)
4016 hRet = (HRESULT)VARCMP_GT;
4018 hRet = (HRESULT)VARCMP_EQ;
4023 /************************************************************************
4024 * VarCyCmpR8 (OLEAUT32.312)
4026 * Compare a VT_CY to a double
4029 * cyLeft [I] Currency Source
4030 * dblRight [I] double to compare to cyLeft
4033 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4034 * less than, equal to or greater than cyLeft respectively.
4035 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4037 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight)
4042 hRet = VarCyFromR8(dblRight, &cyRight);
4044 if (SUCCEEDED(hRet))
4045 hRet = VarCyCmp(cyLeft, cyRight);
4050 /************************************************************************
4051 * VarCyMulI8 (OLEAUT32.329)
4053 * Multiply a VT_CY by a VT_I8.
4057 * llRight [I] Value to multiply by
4058 * pCyOut [O] Destination
4062 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4064 HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
4068 _VarR8FromCy(cyLeft, &d);
4069 d = d * (double)llRight;
4070 return VarCyFromR8(d, pCyOut);
4076 /************************************************************************
4077 * VarDecFromUI1 (OLEAUT32.190)
4079 * Convert a VT_UI1 to a DECIMAL.
4083 * pDecOut [O] Destination
4088 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4090 return VarDecFromUI4(bIn, pDecOut);
4093 /************************************************************************
4094 * VarDecFromI2 (OLEAUT32.191)
4096 * Convert a VT_I2 to a DECIMAL.
4100 * pDecOut [O] Destination
4105 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4107 return VarDecFromI4(sIn, pDecOut);
4110 /************************************************************************
4111 * VarDecFromI4 (OLEAUT32.192)
4113 * Convert a VT_I4 to a DECIMAL.
4117 * pDecOut [O] Destination
4122 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4124 DEC_HI32(pDecOut) = 0;
4125 DEC_MID32(pDecOut) = 0;
4129 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4130 DEC_LO32(pDecOut) = -lIn;
4134 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4135 DEC_LO32(pDecOut) = lIn;
4140 #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT))
4142 /************************************************************************
4143 * VarDecFromR4 (OLEAUT32.193)
4145 * Convert a VT_R4 to a DECIMAL.
4149 * pDecOut [O] Destination
4154 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4158 sprintfW( buff, szFloatFormatW, fltIn );
4159 return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut);
4162 /************************************************************************
4163 * VarDecFromR8 (OLEAUT32.194)
4165 * Convert a VT_R8 to a DECIMAL.
4169 * pDecOut [O] Destination
4174 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4178 sprintfW( buff, szDoubleFormatW, dblIn );
4179 return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut);
4182 /************************************************************************
4183 * VarDecFromDate (OLEAUT32.195)
4185 * Convert a VT_DATE to a DECIMAL.
4189 * pDecOut [O] Destination
4194 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4196 return VarDecFromR8(dateIn, pDecOut);
4199 /************************************************************************
4200 * VarDecFromCy (OLEAUT32.196)
4202 * Convert a VT_CY to a DECIMAL.
4206 * pDecOut [O] Destination
4211 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4213 DEC_HI32(pDecOut) = 0;
4215 /* Note: This assumes 2s complement integer representation */
4216 if (cyIn.s.Hi & 0x80000000)
4218 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4219 DEC_LO64(pDecOut) = -cyIn.int64;
4223 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4224 DEC_MID32(pDecOut) = cyIn.s.Hi;
4225 DEC_LO32(pDecOut) = cyIn.s.Lo;
4230 /************************************************************************
4231 * VarDecFromStr (OLEAUT32.197)
4233 * Convert a VT_BSTR to a DECIMAL.
4237 * lcid [I] LCID for the conversion
4238 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4239 * pDecOut [O] Destination
4243 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4245 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4247 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4250 /************************************************************************
4251 * VarDecFromDisp (OLEAUT32.198)
4253 * Convert a VT_DISPATCH to a DECIMAL.
4256 * pdispIn [I] Source
4257 * lcid [I] LCID for conversion
4258 * pDecOut [O] Destination
4262 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4264 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4266 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL);
4269 /************************************************************************
4270 * VarDecFromBool (OLEAUT32.199)
4272 * Convert a VT_BOOL to a DECIMAL.
4276 * pDecOut [O] Destination
4282 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4284 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4286 DEC_HI32(pDecOut) = 0;
4287 DEC_MID32(pDecOut) = 0;
4290 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4291 DEC_LO32(pDecOut) = 1;
4295 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4296 DEC_LO32(pDecOut) = 0;
4301 /************************************************************************
4302 * VarDecFromI1 (OLEAUT32.241)
4304 * Convert a VT_I1 to a DECIMAL.
4308 * pDecOut [O] Destination
4313 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4315 return VarDecFromI4(cIn, pDecOut);
4318 /************************************************************************
4319 * VarDecFromUI2 (OLEAUT32.242)
4321 * Convert a VT_UI2 to a DECIMAL.
4325 * pDecOut [O] Destination
4330 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4332 return VarDecFromUI4(usIn, pDecOut);
4335 /************************************************************************
4336 * VarDecFromUI4 (OLEAUT32.243)
4338 * Convert a VT_UI4 to a DECIMAL.
4342 * pDecOut [O] Destination
4347 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4349 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4350 DEC_HI32(pDecOut) = 0;
4351 DEC_MID32(pDecOut) = 0;
4352 DEC_LO32(pDecOut) = ulIn;
4356 /************************************************************************
4357 * VarDecFromI8 (OLEAUT32.374)
4359 * Convert a VT_I8 to a DECIMAL.
4363 * pDecOut [O] Destination
4368 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4370 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4372 DEC_HI32(pDecOut) = 0;
4374 /* Note: This assumes 2s complement integer representation */
4375 if (pLi->u.HighPart & 0x80000000)
4377 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4378 DEC_LO64(pDecOut) = -pLi->QuadPart;
4382 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4383 DEC_MID32(pDecOut) = pLi->u.HighPart;
4384 DEC_LO32(pDecOut) = pLi->u.LowPart;
4389 /************************************************************************
4390 * VarDecFromUI8 (OLEAUT32.375)
4392 * Convert a VT_UI8 to a DECIMAL.
4396 * pDecOut [O] Destination
4401 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4403 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4404 DEC_HI32(pDecOut) = 0;
4405 DEC_LO64(pDecOut) = ullIn;
4409 /* Make two DECIMALS the same scale; used by math functions below */
4410 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4411 const DECIMAL** ppDecRight,
4414 static DECIMAL scaleFactor;
4417 HRESULT hRet = S_OK;
4419 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4420 return E_INVALIDARG;
4422 DEC_LO32(&scaleFactor) = 10;
4424 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4427 return S_OK; /* Same scale */
4429 if (scaleAmount > 0)
4431 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4432 *ppDecRight = pDecOut;
4436 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4437 *ppDecLeft = pDecOut;
4438 i = scaleAmount = -scaleAmount;
4441 if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE)
4442 return DISP_E_OVERFLOW; /* Can't scale up */
4444 /* Multiply up the value to be scaled by the correct amount */
4445 while (SUCCEEDED(hRet) && i--)
4447 /* Note we are multiplying by a value with a scale of 0, so we don't recurse */
4448 hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut);
4451 DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */
4455 /* Add two unsigned 32 bit values with overflow */
4456 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4458 ULARGE_INTEGER ul64;
4460 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4461 *pulHigh = ul64.u.HighPart;
4462 return ul64.u.LowPart;
4465 /* Subtract two unsigned 32 bit values with underflow */
4466 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4469 ULARGE_INTEGER ul64;
4471 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4472 if (ulLeft < ulRight)
4475 if (ul64.QuadPart > (ULONG64)*pulHigh)
4476 ul64.QuadPart -= (ULONG64)*pulHigh;
4479 ul64.QuadPart -= (ULONG64)*pulHigh;
4483 ul64.u.HighPart = -ul64.u.HighPart ;
4485 *pulHigh = ul64.u.HighPart;
4486 return ul64.u.LowPart;
4489 /* Multiply two unsigned 32 bit values with overflow */
4490 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4492 ULARGE_INTEGER ul64;
4494 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4495 *pulHigh = ul64.u.HighPart;
4496 return ul64.u.LowPart;
4499 /* Compare two decimals that have the same scale */
4500 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4502 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4503 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4505 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4510 /************************************************************************
4511 * VarDecAdd (OLEAUT32.177)
4513 * Add one DECIMAL to another.
4516 * pDecLeft [I] Source
4517 * pDecRight [I] Value to add
4518 * pDecOut [O] Destination
4522 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4524 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4529 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled);
4531 if (SUCCEEDED(hRet))
4533 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4535 BYTE sign = DECIMAL_POS;
4537 /* Correct for the sign of the result */
4538 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4540 /* -x + -y : Negative */
4542 goto VarDecAdd_AsPositive;
4544 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4546 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4548 /* -x + y : Negative if x > y */
4552 VarDecAdd_AsNegative:
4553 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4554 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4555 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4559 VarDecAdd_AsInvertedNegative:
4560 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4561 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4562 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4565 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4567 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4569 /* x + -y : Negative if x <= y */
4573 goto VarDecAdd_AsInvertedNegative;
4575 goto VarDecAdd_AsNegative;
4579 /* x + y : Positive */
4580 VarDecAdd_AsPositive:
4581 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4582 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4583 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4587 return DISP_E_OVERFLOW; /* overflowed */
4589 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4590 DEC_SIGN(pDecOut) = sign;
4595 /************************************************************************
4596 * VarDecDiv (OLEAUT32.178)
4598 * Divide one DECIMAL by another.
4601 * pDecLeft [I] Source
4602 * pDecRight [I] Value to divide by
4603 * pDecOut [O] Destination
4607 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4609 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4611 FIXME("(%p,%p,%p)-stub!\n",pDecLeft,pDecRight,pDecOut);
4612 return DISP_E_OVERFLOW;
4615 /************************************************************************
4616 * VarDecMul (OLEAUT32.179)
4618 * Multiply one DECIMAL by another.
4621 * pDecLeft [I] Source
4622 * pDecRight [I] Value to multiply by
4623 * pDecOut [O] Destination
4627 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4629 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4631 /* FIXME: This only allows multiplying by a fixed integer <= 0xffffffff */
4633 if (!DEC_SCALE(pDecLeft) || !DEC_SCALE(pDecRight))
4635 /* At least one term is an integer */
4636 const DECIMAL* pDecInteger = DEC_SCALE(pDecLeft) ? pDecRight : pDecLeft;
4637 const DECIMAL* pDecOperand = DEC_SCALE(pDecLeft) ? pDecLeft : pDecRight;
4638 HRESULT hRet = S_OK;
4639 unsigned int multiplier = DEC_LO32(pDecInteger);
4642 if (DEC_HI32(pDecInteger) || DEC_MID32(pDecInteger))
4644 FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut);
4645 return DISP_E_OVERFLOW;
4648 DEC_LO32(pDecOut) = VARIANT_Mul(DEC_LO32(pDecOperand), multiplier, &overflow);
4649 DEC_MID32(pDecOut) = VARIANT_Mul(DEC_MID32(pDecOperand), multiplier, &overflow);
4650 DEC_HI32(pDecOut) = VARIANT_Mul(DEC_HI32(pDecOperand), multiplier, &overflow);
4653 hRet = DISP_E_OVERFLOW;
4656 BYTE sign = DECIMAL_POS;
4658 if (DEC_SIGN(pDecLeft) != DEC_SIGN(pDecRight))
4659 sign = DECIMAL_NEG; /* pos * neg => negative */
4660 DEC_SIGN(pDecOut) = sign;
4661 DEC_SCALE(pDecOut) = DEC_SCALE(pDecOperand);
4665 FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut);
4666 return DISP_E_OVERFLOW;
4669 /************************************************************************
4670 * VarDecSub (OLEAUT32.181)
4672 * Subtract one DECIMAL from another.
4675 * pDecLeft [I] Source
4676 * pDecRight [I] DECIMAL to subtract from pDecLeft
4677 * pDecOut [O] Destination
4680 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4682 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4686 /* Implement as addition of the negative */
4687 VarDecNeg(pDecRight, &decRight);
4688 return VarDecAdd(pDecLeft, &decRight, pDecOut);
4691 /************************************************************************
4692 * VarDecAbs (OLEAUT32.182)
4694 * Convert a DECIMAL into its absolute value.
4698 * pDecOut [O] Destination
4701 * S_OK. This function does not fail.
4703 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
4706 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
4710 /************************************************************************
4711 * VarDecFix (OLEAUT32.187)
4713 * Return the integer portion of a DECIMAL.
4717 * pDecOut [O] Destination
4721 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4724 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
4725 * negative numbers away from 0, while this function rounds them towards zero.
4727 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
4729 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
4730 return E_INVALIDARG;
4732 if (!DEC_SCALE(pDecIn))
4734 *pDecOut = *pDecIn; /* Already an integer */
4738 FIXME("semi-stub!\n");
4739 return DISP_E_OVERFLOW;
4742 /************************************************************************
4743 * VarDecInt (OLEAUT32.188)
4745 * Return the integer portion of a DECIMAL.
4749 * pDecOut [O] Destination
4753 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4756 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
4757 * negative numbers towards 0, while this function rounds them away from zero.
4759 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
4761 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
4762 return E_INVALIDARG;
4764 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
4765 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
4767 FIXME("semi-stub!\n");
4768 return DISP_E_OVERFLOW;
4771 /************************************************************************
4772 * VarDecNeg (OLEAUT32.189)
4774 * Change the sign of a DECIMAL.
4778 * pDecOut [O] Destination
4781 * S_OK. This function does not fail.
4783 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
4786 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
4790 /************************************************************************
4791 * VarDecRound (OLEAUT32.203)
4793 * Change the precision of a DECIMAL.
4797 * cDecimals [I] New number of decimals to keep
4798 * pDecOut [O] Destination
4801 * Success: S_OK. pDecOut contains the rounded value.
4802 * Failure: E_INVALIDARG if any argument is invalid.
4804 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
4806 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
4807 return E_INVALIDARG;
4809 if (cDecimals >= DEC_SCALE(pDecIn))
4811 *pDecOut = *pDecIn; /* More precision than we have */
4815 FIXME("semi-stub!\n");
4817 return DISP_E_OVERFLOW;
4820 /************************************************************************
4821 * VarDecCmp (OLEAUT32.204)
4823 * Compare two DECIMAL values.
4826 * pDecLeft [I] Source
4827 * pDecRight [I] Value to compare
4830 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
4831 * is less than, equal to or greater than pDecRight respectively.
4832 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4834 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
4839 /* Subtract right from left, and compare the result to 0 */
4840 hRet = VarDecSub(pDecLeft, pDecRight, &result);
4842 if (SUCCEEDED(hRet))
4844 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
4846 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
4847 hRet = (HRESULT)VARCMP_LT;
4849 hRet = (HRESULT)VARCMP_GT;
4851 hRet = (HRESULT)VARCMP_EQ;
4856 /************************************************************************
4857 * VarDecCmpR8 (OLEAUT32.298)
4859 * Compare a DECIMAL to a double
4862 * pDecLeft [I] DECIMAL Source
4863 * dblRight [I] double to compare to pDecLeft
4866 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
4867 * is less than, equal to or greater than pDecLeft respectively.
4868 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4870 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
4875 hRet = VarDecFromR8(dblRight, &decRight);
4877 if (SUCCEEDED(hRet))
4878 hRet = VarDecCmp(pDecLeft, &decRight);
4886 /************************************************************************
4887 * VarBoolFromUI1 (OLEAUT32.118)
4889 * Convert a VT_UI1 to a VT_BOOL.
4893 * pBoolOut [O] Destination
4898 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
4900 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
4904 /************************************************************************
4905 * VarBoolFromI2 (OLEAUT32.119)
4907 * Convert a VT_I2 to a VT_BOOL.
4911 * pBoolOut [O] Destination
4916 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
4918 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
4922 /************************************************************************
4923 * VarBoolFromI4 (OLEAUT32.120)
4925 * Convert a VT_I4 to a VT_BOOL.
4929 * pBoolOut [O] Destination
4934 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
4936 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
4940 /************************************************************************
4941 * VarBoolFromR4 (OLEAUT32.121)
4943 * Convert a VT_R4 to a VT_BOOL.
4947 * pBoolOut [O] Destination
4952 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
4954 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
4958 /************************************************************************
4959 * VarBoolFromR8 (OLEAUT32.122)
4961 * Convert a VT_R8 to a VT_BOOL.
4965 * pBoolOut [O] Destination
4970 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
4972 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
4976 /************************************************************************
4977 * VarBoolFromDate (OLEAUT32.123)
4979 * Convert a VT_DATE to a VT_BOOL.
4983 * pBoolOut [O] Destination
4988 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
4990 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
4994 /************************************************************************
4995 * VarBoolFromCy (OLEAUT32.124)
4997 * Convert a VT_CY to a VT_BOOL.
5001 * pBoolOut [O] Destination
5006 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
5008 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
5012 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
5016 hrsrc = FindResourceExW( OLEAUT32_hModule, (LPWSTR)RT_STRING,
5017 (LPCWSTR)((dwId >> 4) + 1), langId );
5020 HGLOBAL hmem = LoadResource( OLEAUT32_hModule, hrsrc );
5027 p = LockResource( hmem );
5028 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
5030 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
5031 lpszDest[*p] = '\0';
5032 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
5039 /************************************************************************
5040 * VarBoolFromStr (OLEAUT32.125)
5042 * Convert a VT_BSTR to a VT_BOOL.
5046 * lcid [I] LCID for the conversion
5047 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5048 * pBoolOut [O] Destination
5052 * Failure: E_INVALIDARG, if pBoolOut is invalid.
5053 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5056 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
5057 * it may contain (in any case mapping) the text "true" or "false".
5058 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
5059 * localised text of "True" or "False" in the language specified by lcid.
5060 * - If none of these matches occur, the string is treated as a numeric string
5061 * and the boolean pBoolOut will be set according to whether the number is zero
5062 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
5063 * - If the text is not numeric and does not match any of the above, then
5064 * DISP_E_TYPEMISMATCH is returned.
5066 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
5068 /* Any VB/VBA programmers out there should recognise these strings... */
5069 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
5070 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
5072 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5073 HRESULT hRes = S_OK;
5075 if (!strIn || !pBoolOut)
5076 return DISP_E_TYPEMISMATCH;
5078 /* Check if we should be comparing against localised text */
5079 if (dwFlags & VAR_LOCALBOOL)
5081 /* Convert our LCID into a usable value */
5082 lcid = ConvertDefaultLocale(lcid);
5084 langId = LANGIDFROMLCID(lcid);
5086 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
5087 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5089 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
5090 * I don't think this is needed unless any of the localised text strings
5091 * contain characters that can be so mapped. In the event that this is
5092 * true for a given language (possibly some Asian languages), then strIn
5093 * should be mapped here _only_ if langId is an Id for which this can occur.
5097 /* Note that if we are not comparing against localised strings, langId
5098 * will have its default value of LANG_ENGLISH. This allows us to mimic
5099 * the native behaviour of always checking against English strings even
5100 * after we've checked for localised ones.
5102 VarBoolFromStr_CheckLocalised:
5103 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
5105 /* Compare against localised strings, ignoring case */
5106 if (!strcmpiW(strIn, szBuff))
5108 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
5111 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
5112 if (!strcmpiW(strIn, szBuff))
5114 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
5119 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
5121 /* We have checked the localised text, now check English */
5122 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5123 goto VarBoolFromStr_CheckLocalised;
5126 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
5127 if (!strcmpW(strIn, szFalse))
5128 *pBoolOut = VARIANT_FALSE;
5129 else if (!strcmpW(strIn, szTrue))
5130 *pBoolOut = VARIANT_TRUE;
5135 /* If this string is a number, convert it as one */
5136 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
5137 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
5142 /************************************************************************
5143 * VarBoolFromDisp (OLEAUT32.126)
5145 * Convert a VT_DISPATCH to a VT_BOOL.
5148 * pdispIn [I] Source
5149 * lcid [I] LCID for conversion
5150 * pBoolOut [O] Destination
5154 * Failure: E_INVALIDARG, if the source value is invalid
5155 * DISP_E_OVERFLOW, if the value will not fit in the destination
5156 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5158 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
5160 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL);
5163 /************************************************************************
5164 * VarBoolFromI1 (OLEAUT32.233)
5166 * Convert a VT_I1 to a VT_BOOL.
5170 * pBoolOut [O] Destination
5175 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
5177 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
5181 /************************************************************************
5182 * VarBoolFromUI2 (OLEAUT32.234)
5184 * Convert a VT_UI2 to a VT_BOOL.
5188 * pBoolOut [O] Destination
5193 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
5195 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
5199 /************************************************************************
5200 * VarBoolFromUI4 (OLEAUT32.235)
5202 * Convert a VT_UI4 to a VT_BOOL.
5206 * pBoolOut [O] Destination
5211 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
5213 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
5217 /************************************************************************
5218 * VarBoolFromDec (OLEAUT32.236)
5220 * Convert a VT_DECIMAL to a VT_BOOL.
5224 * pBoolOut [O] Destination
5228 * Failure: E_INVALIDARG, if pDecIn is invalid.
5230 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
5232 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
5233 return E_INVALIDARG;
5235 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
5236 *pBoolOut = VARIANT_TRUE;
5238 *pBoolOut = VARIANT_FALSE;
5242 /************************************************************************
5243 * VarBoolFromI8 (OLEAUT32.370)
5245 * Convert a VT_I8 to a VT_BOOL.
5249 * pBoolOut [O] Destination
5254 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
5256 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
5260 /************************************************************************
5261 * VarBoolFromUI8 (OLEAUT32.371)
5263 * Convert a VT_UI8 to a VT_BOOL.
5267 * pBoolOut [O] Destination
5272 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
5274 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
5281 /* Write a number from a UI8 and sign */
5282 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
5286 WCHAR ulNextDigit = ulVal % 10;
5288 *szOut-- = '0' + ulNextDigit;
5289 ulVal = (ulVal - ulNextDigit) / 10;
5296 /* Create a (possibly localised) BSTR from a UI8 and sign */
5297 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
5299 WCHAR szConverted[256];
5301 if (dwFlags & VAR_NEGATIVE)
5304 if (dwFlags & LOCALE_USE_NLS)
5306 /* Format the number for the locale */
5307 szConverted[0] = '\0';
5308 GetNumberFormatW(lcid,
5309 dwFlags & LOCALE_NOUSEROVERRIDE,
5310 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
5311 szOut = szConverted;
5313 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
5316 /* Create a (possibly localised) BSTR from a UI8 and sign */
5317 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
5319 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
5322 return E_INVALIDARG;
5324 /* Create the basic number string */
5326 szOut = VARIANT_WriteNumber(ulVal, szOut);
5328 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
5329 TRACE("returning %s\n", debugstr_w(*pbstrOut));
5330 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
5333 /******************************************************************************
5334 * VarBstrFromUI1 (OLEAUT32.108)
5336 * Convert a VT_UI1 to a VT_BSTR.
5340 * lcid [I] LCID for the conversion
5341 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5342 * pbstrOut [O] Destination
5346 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5347 * E_OUTOFMEMORY, if memory allocation fails.
5349 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5351 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
5354 /******************************************************************************
5355 * VarBstrFromI2 (OLEAUT32.109)
5357 * Convert a VT_I2 to a VT_BSTR.
5361 * lcid [I] LCID for the conversion
5362 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5363 * pbstrOut [O] Destination
5367 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5368 * E_OUTOFMEMORY, if memory allocation fails.
5370 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5377 dwFlags |= VAR_NEGATIVE;
5379 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
5382 /******************************************************************************
5383 * VarBstrFromI4 (OLEAUT32.110)
5385 * Convert a VT_I4 to a VT_BSTR.
5389 * lcid [I] LCID for the conversion
5390 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5391 * pbstrOut [O] Destination
5395 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5396 * E_OUTOFMEMORY, if memory allocation fails.
5398 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5405 dwFlags |= VAR_NEGATIVE;
5407 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
5410 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
5411 BSTR* pbstrOut, LPCWSTR lpszFormat)
5416 return E_INVALIDARG;
5418 sprintfW( buff, lpszFormat, dblIn );
5420 /* Negative zeroes are disallowed (some applications depend on this).
5421 If buff starts with a minus, and then nothing follows but zeroes
5422 and/or a period, it is a negative zero and is replaced with a
5423 canonical zero. This duplicates native oleaut32 behavior.
5427 const WCHAR szAccept[] = {'0', '.', '\0'};
5428 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
5429 { buff[0] = '0'; buff[1] = '\0'; }
5432 TRACE("created string %s\n", debugstr_w(buff));
5433 if (dwFlags & LOCALE_USE_NLS)
5437 /* Format the number for the locale */
5439 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
5440 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
5441 TRACE("created NLS string %s\n", debugstr_w(numbuff));
5442 *pbstrOut = SysAllocString(numbuff);
5445 *pbstrOut = SysAllocString(buff);
5446 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
5449 /******************************************************************************
5450 * VarBstrFromR4 (OLEAUT32.111)
5452 * Convert a VT_R4 to a VT_BSTR.
5456 * lcid [I] LCID for the conversion
5457 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5458 * pbstrOut [O] Destination
5462 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5463 * E_OUTOFMEMORY, if memory allocation fails.
5465 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5467 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
5470 /******************************************************************************
5471 * VarBstrFromR8 (OLEAUT32.112)
5473 * Convert a VT_R8 to a VT_BSTR.
5477 * lcid [I] LCID for the conversion
5478 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5479 * pbstrOut [O] Destination
5483 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5484 * E_OUTOFMEMORY, if memory allocation fails.
5486 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5488 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
5491 /******************************************************************************
5492 * VarBstrFromCy [OLEAUT32.113]
5494 * Convert a VT_CY to a VT_BSTR.
5498 * lcid [I] LCID for the conversion
5499 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5500 * pbstrOut [O] Destination
5504 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5505 * E_OUTOFMEMORY, if memory allocation fails.
5507 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
5513 return E_INVALIDARG;
5515 VarR8FromCy(cyIn, &dblVal);
5516 sprintfW(buff, szDoubleFormatW, dblVal);
5518 if (dwFlags & LOCALE_USE_NLS)
5522 /* Format the currency for the locale */
5524 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
5525 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR));
5526 *pbstrOut = SysAllocString(cybuff);
5529 *pbstrOut = SysAllocString(buff);
5531 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
5534 /******************************************************************************
5535 * VarBstrFromDate [OLEAUT32.114]
5537 * Convert a VT_DATE to a VT_BSTR.
5541 * lcid [I] LCID for the conversion
5542 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5543 * pbstrOut [O] Destination
5547 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
5548 * E_OUTOFMEMORY, if memory allocation fails.
5550 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5553 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
5554 WCHAR date[128], *time;
5556 TRACE("(%g,0x%08lx,0x%08lx,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
5558 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
5559 return E_INVALIDARG;
5563 if (dwFlags & VAR_CALENDAR_THAI)
5564 st.wYear += 553; /* Use the Thai buddhist calendar year */
5565 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
5566 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
5568 if (dwFlags & LOCALE_USE_NLS)
5569 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
5572 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
5573 double partial = dateIn - whole;
5576 dwFlags |= VAR_TIMEVALUEONLY;
5577 else if (partial < 1e-12)
5578 dwFlags |= VAR_DATEVALUEONLY;
5581 if (dwFlags & VAR_TIMEVALUEONLY)
5584 if (!GetDateFormatW(lcid, dwFormatFlags|DATE_SHORTDATE, &st, NULL, date,
5585 sizeof(date)/sizeof(WCHAR)))
5586 return E_INVALIDARG;
5588 if (!(dwFlags & VAR_DATEVALUEONLY))
5590 time = date + strlenW(date);
5593 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
5594 sizeof(date)/sizeof(WCHAR)-(time-date)))
5595 return E_INVALIDARG;
5598 *pbstrOut = SysAllocString(date);
5600 TRACE("returning %s\n", debugstr_w(*pbstrOut));
5601 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
5604 /******************************************************************************
5605 * VarBstrFromBool (OLEAUT32.116)
5607 * Convert a VT_BOOL to a VT_BSTR.
5611 * lcid [I] LCID for the conversion
5612 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5613 * pbstrOut [O] Destination
5617 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5618 * E_OUTOFMEMORY, if memory allocation fails.
5621 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
5622 * localised text of "True" or "False". To convert a bool into a
5623 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
5625 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5628 DWORD dwResId = IDS_TRUE;
5631 TRACE("%d,0x%08lx,0x%08lx,%p\n", boolIn, lcid, dwFlags, pbstrOut);
5634 return E_INVALIDARG;
5636 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
5637 * for variant formatting */
5638 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
5649 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
5652 lcid = ConvertDefaultLocale(lcid);
5653 langId = LANGIDFROMLCID(lcid);
5654 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
5655 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5657 if (boolIn == VARIANT_FALSE)
5658 dwResId++; /* Use negative form */
5660 VarBstrFromBool_GetLocalised:
5661 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
5663 *pbstrOut = SysAllocString(szBuff);
5664 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
5667 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
5669 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5670 goto VarBstrFromBool_GetLocalised;
5673 /* Should never get here */
5674 WARN("Failed to load bool text!\n");
5675 return E_OUTOFMEMORY;
5678 /******************************************************************************
5679 * VarBstrFromI1 (OLEAUT32.229)
5681 * Convert a VT_I1 to a VT_BSTR.
5685 * lcid [I] LCID for the conversion
5686 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5687 * pbstrOut [O] Destination
5691 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5692 * E_OUTOFMEMORY, if memory allocation fails.
5694 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5701 dwFlags |= VAR_NEGATIVE;
5703 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
5706 /******************************************************************************
5707 * VarBstrFromUI2 (OLEAUT32.230)
5709 * Convert a VT_UI2 to a VT_BSTR.
5713 * lcid [I] LCID for the conversion
5714 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5715 * pbstrOut [O] Destination
5719 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5720 * E_OUTOFMEMORY, if memory allocation fails.
5722 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5724 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
5727 /******************************************************************************
5728 * VarBstrFromUI4 (OLEAUT32.231)
5730 * Convert a VT_UI4 to a VT_BSTR.
5734 * lcid [I] LCID for the conversion
5735 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5736 * pbstrOut [O] Destination
5740 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5741 * E_OUTOFMEMORY, if memory allocation fails.
5743 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5745 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
5748 /******************************************************************************
5749 * VarBstrFromDec (OLEAUT32.232)
5751 * Convert a VT_DECIMAL to a VT_BSTR.
5755 * lcid [I] LCID for the conversion
5756 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5757 * pbstrOut [O] Destination
5761 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5762 * E_OUTOFMEMORY, if memory allocation fails.
5764 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5767 return E_INVALIDARG;
5769 if (!DEC_SCALE(pDecIn) && !DEC_HI32(pDecIn))
5771 WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
5773 /* Create the basic number string */
5775 szOut = VARIANT_WriteNumber(DEC_LO64(pDecIn), szOut);
5776 if (DEC_SIGN(pDecIn))
5777 dwFlags |= VAR_NEGATIVE;
5779 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
5780 TRACE("returning %s\n", debugstr_w(*pbstrOut));
5781 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
5783 FIXME("semi-stub\n");
5784 return E_INVALIDARG;
5787 /************************************************************************
5788 * VarBstrFromI8 (OLEAUT32.370)
5790 * Convert a VT_I8 to a VT_BSTR.
5794 * lcid [I] LCID for the conversion
5795 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5796 * pbstrOut [O] Destination
5800 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5801 * E_OUTOFMEMORY, if memory allocation fails.
5803 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5805 ULONG64 ul64 = llIn;
5810 dwFlags |= VAR_NEGATIVE;
5812 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
5815 /************************************************************************
5816 * VarBstrFromUI8 (OLEAUT32.371)
5818 * Convert a VT_UI8 to a VT_BSTR.
5822 * lcid [I] LCID for the conversion
5823 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5824 * pbstrOut [O] Destination
5828 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5829 * E_OUTOFMEMORY, if memory allocation fails.
5831 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5833 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
5836 /**********************************************************************
5837 * VarBstrCat (OLEAUT32.313)
5839 * Concatenate two BSTR values.
5842 * pbstrLeft [I] Source
5843 * pbstrRight [I] Value to concatenate
5844 * pbstrOut [O] Destination
5848 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5849 * E_OUTOFMEMORY, if memory allocation fails.
5851 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
5856 return E_INVALIDARG;
5858 len = pbstrLeft ? strlenW(pbstrLeft) : 0;
5860 len += strlenW(pbstrRight);
5862 *pbstrOut = SysAllocStringLen(NULL, len);
5864 return E_OUTOFMEMORY;
5866 (*pbstrOut)[0] = '\0';
5869 strcpyW(*pbstrOut, pbstrLeft);
5872 strcatW(*pbstrOut, pbstrRight);
5877 /**********************************************************************
5878 * VarBstrCmp (OLEAUT32.314)
5880 * Compare two BSTR values.
5883 * pbstrLeft [I] Source
5884 * pbstrRight [I] Value to compare
5885 * lcid [I] LCID for the comparison
5886 * dwFlags [I] Flags to pass directly to CompareStringW().
5889 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
5890 * than, equal to or greater than pbstrRight respectively.
5891 * VARCMP_NULL is returned if either string is NULL, unless both are NULL
5892 * in which case VARCMP_EQ is returned.
5894 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
5898 if (!pbstrRight || !*pbstrRight)
5902 else if (!pbstrRight)
5909 return CompareStringW(lcid, dwFlags, pbstrLeft, -1, pbstrRight, -1) - 1;
5916 /******************************************************************************
5917 * VarDateFromUI1 (OLEAUT32.88)
5919 * Convert a VT_UI1 to a VT_DATE.
5923 * pdateOut [O] Destination
5928 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
5930 return VarR8FromUI1(bIn, pdateOut);
5933 /******************************************************************************
5934 * VarDateFromI2 (OLEAUT32.89)
5936 * Convert a VT_I2 to a VT_DATE.
5940 * pdateOut [O] Destination
5945 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
5947 return VarR8FromI2(sIn, pdateOut);
5950 /******************************************************************************
5951 * VarDateFromI4 (OLEAUT32.90)
5953 * Convert a VT_I4 to a VT_DATE.
5957 * pdateOut [O] Destination
5962 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
5964 return VarDateFromR8(lIn, pdateOut);
5967 /******************************************************************************
5968 * VarDateFromR4 (OLEAUT32.91)
5970 * Convert a VT_R4 to a VT_DATE.
5974 * pdateOut [O] Destination
5979 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
5981 return VarR8FromR4(fltIn, pdateOut);
5984 /******************************************************************************
5985 * VarDateFromR8 (OLEAUT32.92)
5987 * Convert a VT_R8 to a VT_DATE.
5991 * pdateOut [O] Destination
5996 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
5998 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
5999 *pdateOut = (DATE)dblIn;
6003 /**********************************************************************
6004 * VarDateFromDisp (OLEAUT32.95)
6006 * Convert a VT_DISPATCH to a VT_DATE.
6009 * pdispIn [I] Source
6010 * lcid [I] LCID for conversion
6011 * pdateOut [O] Destination
6015 * Failure: E_INVALIDARG, if the source value is invalid
6016 * DISP_E_OVERFLOW, if the value will not fit in the destination
6017 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6019 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
6021 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE);
6024 /******************************************************************************
6025 * VarDateFromBool (OLEAUT32.96)
6027 * Convert a VT_BOOL to a VT_DATE.
6031 * pdateOut [O] Destination
6036 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
6038 return VarR8FromBool(boolIn, pdateOut);
6041 /**********************************************************************
6042 * VarDateFromCy (OLEAUT32.93)
6044 * Convert a VT_CY to a VT_DATE.
6048 * pdateOut [O] Destination
6053 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
6055 return VarR8FromCy(cyIn, pdateOut);
6058 /* Date string parsing */
6059 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
6060 #define DP_DATESEP 0x02 /* Date separator */
6061 #define DP_MONTH 0x04 /* Month name */
6062 #define DP_AM 0x08 /* AM */
6063 #define DP_PM 0x10 /* PM */
6065 typedef struct tagDATEPARSE
6067 DWORD dwCount; /* Number of fields found so far (maximum 6) */
6068 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
6069 DWORD dwFlags[6]; /* Flags for each field */
6070 DWORD dwValues[6]; /* Value of each field */
6073 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
6075 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
6077 /* Determine if a day is valid in a given month of a given year */
6078 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
6080 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
6082 if (day && month && month < 13)
6084 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
6090 /* Possible orders for 3 numbers making up a date */
6091 #define ORDER_MDY 0x01
6092 #define ORDER_YMD 0x02
6093 #define ORDER_YDM 0x04
6094 #define ORDER_DMY 0x08
6095 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
6097 /* Determine a date for a particular locale, from 3 numbers */
6098 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
6099 DWORD offset, SYSTEMTIME *st)
6101 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
6105 v1 = 30; /* Default to (Variant) 0 date part */
6108 goto VARIANT_MakeDate_OK;
6111 v1 = dp->dwValues[offset + 0];
6112 v2 = dp->dwValues[offset + 1];
6113 if (dp->dwCount == 2)
6116 GetSystemTime(¤t);
6120 v3 = dp->dwValues[offset + 2];
6122 TRACE("(%ld,%ld,%ld,%ld,%ld)\n", v1, v2, v3, iDate, offset);
6124 /* If one number must be a month (Because a month name was given), then only
6125 * consider orders with the month in that position.
6126 * If we took the current year as 'v3', then only allow a year in that position.
6128 if (dp->dwFlags[offset + 0] & DP_MONTH)
6130 dwAllOrders = ORDER_MDY;
6132 else if (dp->dwFlags[offset + 1] & DP_MONTH)
6134 dwAllOrders = ORDER_DMY;
6135 if (dp->dwCount > 2)
6136 dwAllOrders |= ORDER_YMD;
6138 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
6140 dwAllOrders = ORDER_YDM;
6144 dwAllOrders = ORDER_MDY|ORDER_DMY;
6145 if (dp->dwCount > 2)
6146 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
6149 VARIANT_MakeDate_Start:
6150 TRACE("dwAllOrders is 0x%08lx\n", dwAllOrders);
6158 /* First: Try the order given by iDate */
6161 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
6162 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
6163 default: dwTry = dwAllOrders & ORDER_YMD; break;
6166 else if (dwCount == 1)
6168 /* Second: Try all the orders compatible with iDate */
6171 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
6172 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break;
6173 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
6178 /* Finally: Try any remaining orders */
6179 dwTry = dwAllOrders;
6182 TRACE("Attempt %ld, dwTry is 0x%08lx\n", dwCount, dwTry);
6188 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
6190 if (dwTry & ORDER_MDY)
6192 if (VARIANT_IsValidMonthDay(v2,v1,v3))
6195 goto VARIANT_MakeDate_OK;
6197 dwAllOrders &= ~ORDER_MDY;
6199 if (dwTry & ORDER_YMD)
6201 if (VARIANT_IsValidMonthDay(v3,v2,v1))
6204 goto VARIANT_MakeDate_OK;
6206 dwAllOrders &= ~ORDER_YMD;
6208 if (dwTry & ORDER_YDM)
6210 if (VARIANT_IsValidMonthDay(v2,v3,v1))
6214 goto VARIANT_MakeDate_OK;
6216 dwAllOrders &= ~ORDER_YDM;
6218 if (dwTry & ORDER_DMY)
6220 if (VARIANT_IsValidMonthDay(v1,v2,v3))
6221 goto VARIANT_MakeDate_OK;
6222 dwAllOrders &= ~ORDER_DMY;
6224 if (dwTry & ORDER_MYD)
6226 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
6227 if (VARIANT_IsValidMonthDay(v3,v1,v2))
6231 goto VARIANT_MakeDate_OK;
6233 dwAllOrders &= ~ORDER_MYD;
6237 if (dp->dwCount == 2)
6239 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
6240 v3 = 1; /* 1st of the month */
6241 dwAllOrders = ORDER_YMD|ORDER_MYD;
6242 dp->dwCount = 0; /* Don't return to this code path again */
6244 goto VARIANT_MakeDate_Start;
6247 /* No valid dates were able to be constructed */
6248 return DISP_E_TYPEMISMATCH;
6250 VARIANT_MakeDate_OK:
6252 /* Check that the time part is ok */
6253 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
6254 return DISP_E_TYPEMISMATCH;
6256 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
6257 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
6259 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
6261 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
6265 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
6266 * be retrieved from:
6267 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
6268 * But Wine doesn't have/use that key as at the time of writing.
6270 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
6271 TRACE("Returning date %ld/%ld/%d\n", v1, v2, st->wYear);
6275 /******************************************************************************
6276 * VarDateFromStr [OLEAUT32.94]
6278 * Convert a VT_BSTR to at VT_DATE.
6281 * strIn [I] String to convert
6282 * lcid [I] Locale identifier for the conversion
6283 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
6284 * pdateOut [O] Destination for the converted value
6287 * Success: S_OK. pdateOut contains the converted value.
6288 * FAILURE: An HRESULT error code indicating the prolem.
6291 * Any date format that can be created using the date formats from lcid
6292 * (Either from kernel Nls functions, variant conversion or formatting) is a
6293 * valid input to this function. In addition, a few more esoteric formats are
6294 * also supported for compatibility with the native version. The date is
6295 * interpreted according to the date settings in the control panel, unless
6296 * the date is invalid in that format, in which the most compatible format
6297 * that produces a valid date will be used.
6299 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
6301 static const USHORT ParseDateTokens[] =
6303 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
6304 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
6305 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
6306 LOCALE_SMONTHNAME13,
6307 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
6308 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
6309 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
6310 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
6311 LOCALE_SABBREVMONTHNAME13,
6312 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
6313 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
6314 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
6315 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
6316 LOCALE_SABBREVDAYNAME7,
6317 LOCALE_S1159, LOCALE_S2359
6319 static const BYTE ParseDateMonths[] =
6321 1,2,3,4,5,6,7,8,9,10,11,12,13,
6322 1,2,3,4,5,6,7,8,9,10,11,12,13
6325 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
6327 DWORD dwDateSeps = 0, iDate = 0;
6328 HRESULT hRet = S_OK;
6330 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
6331 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
6332 return E_INVALIDARG;
6335 return DISP_E_TYPEMISMATCH;
6339 TRACE("(%s,0x%08lx,0x%08lx,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
6341 memset(&dp, 0, sizeof(dp));
6343 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
6344 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
6345 TRACE("iDate is %ld\n", iDate);
6347 /* Get the month/day/am/pm tokens for this locale */
6348 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
6351 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
6353 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
6354 * GetAltMonthNames(). We should really cache these strings too.
6357 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
6358 tokens[i] = SysAllocString(buff);
6359 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
6362 /* Parse the string into our structure */
6368 if (isdigitW(*strIn))
6370 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
6374 else if (isalpha(*strIn))
6376 BOOL bFound = FALSE;
6378 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
6380 DWORD dwLen = strlenW(tokens[i]);
6381 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
6385 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
6386 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
6391 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
6392 hRet = DISP_E_TYPEMISMATCH;
6395 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
6396 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
6399 strIn += (dwLen - 1);
6407 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
6408 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
6410 /* Special case - 'a' and 'p' are recognised as short for am/pm */
6411 if (*strIn == 'a' || *strIn == 'A')
6413 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
6414 dp.dwParseFlags |= DP_AM;
6418 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
6419 dp.dwParseFlags |= DP_PM;
6425 TRACE("No matching token for %s\n", debugstr_w(strIn));
6426 hRet = DISP_E_TYPEMISMATCH;
6431 else if (*strIn == ':' || *strIn == '.')
6433 if (!dp.dwCount || !strIn[1])
6434 hRet = DISP_E_TYPEMISMATCH;
6436 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
6438 else if (*strIn == '-' || *strIn == '/')
6441 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
6442 hRet = DISP_E_TYPEMISMATCH;
6444 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
6446 else if (*strIn == ',' || isspaceW(*strIn))
6448 if (*strIn == ',' && !strIn[1])
6449 hRet = DISP_E_TYPEMISMATCH;
6453 hRet = DISP_E_TYPEMISMATCH;
6458 if (!dp.dwCount || dp.dwCount > 6 ||
6459 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
6460 hRet = DISP_E_TYPEMISMATCH;
6462 if (SUCCEEDED(hRet))
6465 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
6467 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
6469 /* Figure out which numbers correspond to which fields.
6471 * This switch statement works based on the fact that native interprets any
6472 * fields that are not joined with a time separator ('.' or ':') as date
6473 * fields. Thus we construct a value from 0-32 where each set bit indicates
6474 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
6475 * For valid permutations, we set dwOffset to point to the first date field
6476 * and shorten dp.dwCount by the number of time fields found. The real
6477 * magic here occurs in VARIANT_MakeDate() above, where we determine what
6478 * each date number must represent in the context of iDate.
6480 TRACE("0x%08lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
6482 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
6484 case 0x1: /* TT TTDD TTDDD */
6485 if (dp.dwCount > 3 &&
6486 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
6487 (dp.dwFlags[4] & (DP_AM|DP_PM))))
6488 hRet = DISP_E_TYPEMISMATCH;
6489 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
6490 hRet = DISP_E_TYPEMISMATCH;
6491 st.wHour = dp.dwValues[0];
6492 st.wMinute = dp.dwValues[1];
6497 case 0x3: /* TTT TTTDD TTTDDD */
6498 if (dp.dwCount > 4 &&
6499 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
6500 (dp.dwFlags[5] & (DP_AM|DP_PM))))
6501 hRet = DISP_E_TYPEMISMATCH;
6502 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
6503 hRet = DISP_E_TYPEMISMATCH;
6504 st.wHour = dp.dwValues[0];
6505 st.wMinute = dp.dwValues[1];
6506 st.wSecond = dp.dwValues[2];
6511 case 0x4: /* DDTT */
6512 if (dp.dwCount != 4 ||
6513 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
6514 hRet = DISP_E_TYPEMISMATCH;
6516 st.wHour = dp.dwValues[2];
6517 st.wMinute = dp.dwValues[3];
6521 case 0x0: /* T DD DDD TDDD TDDD */
6522 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
6524 st.wHour = dp.dwValues[0]; /* T */
6528 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
6530 hRet = DISP_E_TYPEMISMATCH;
6532 else if (dp.dwCount == 3)
6534 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
6537 st.wHour = dp.dwValues[0];
6541 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
6544 st.wHour = dp.dwValues[2];
6547 else if (dp.dwParseFlags & (DP_AM|DP_PM))
6548 hRet = DISP_E_TYPEMISMATCH;
6550 else if (dp.dwCount == 4)
6553 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
6555 st.wHour = dp.dwValues[0];
6558 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
6560 st.wHour = dp.dwValues[3];
6563 hRet = DISP_E_TYPEMISMATCH;
6566 /* .. fall through .. */
6568 case 0x8: /* DDDTT */
6569 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
6570 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
6571 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
6572 dp.dwCount == 4 || dp.dwCount == 6)
6573 hRet = DISP_E_TYPEMISMATCH;
6574 st.wHour = dp.dwValues[3];
6575 st.wMinute = dp.dwValues[4];
6576 if (dp.dwCount == 5)
6580 case 0xC: /* DDTTT */
6581 if (dp.dwCount != 5 ||
6582 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
6583 hRet = DISP_E_TYPEMISMATCH;
6584 st.wHour = dp.dwValues[2];
6585 st.wMinute = dp.dwValues[3];
6586 st.wSecond = dp.dwValues[4];
6590 case 0x18: /* DDDTTT */
6591 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
6592 (dp.dwFlags[2] & (DP_AM|DP_PM)))
6593 hRet = DISP_E_TYPEMISMATCH;
6594 st.wHour = dp.dwValues[3];
6595 st.wMinute = dp.dwValues[4];
6596 st.wSecond = dp.dwValues[5];
6601 hRet = DISP_E_TYPEMISMATCH;
6605 if (SUCCEEDED(hRet))
6607 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
6609 if (dwFlags & VAR_TIMEVALUEONLY)
6615 else if (dwFlags & VAR_DATEVALUEONLY)
6616 st.wHour = st.wMinute = st.wSecond = 0;
6618 /* Finally, convert the value to a VT_DATE */
6619 if (SUCCEEDED(hRet))
6620 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
6624 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
6625 SysFreeString(tokens[i]);
6629 /******************************************************************************
6630 * VarDateFromI1 (OLEAUT32.221)
6632 * Convert a VT_I1 to a VT_DATE.
6636 * pdateOut [O] Destination
6641 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
6643 return VarR8FromI1(cIn, pdateOut);
6646 /******************************************************************************
6647 * VarDateFromUI2 (OLEAUT32.222)
6649 * Convert a VT_UI2 to a VT_DATE.
6653 * pdateOut [O] Destination
6658 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
6660 return VarR8FromUI2(uiIn, pdateOut);
6663 /******************************************************************************
6664 * VarDateFromUI4 (OLEAUT32.223)
6666 * Convert a VT_UI4 to a VT_DATE.
6670 * pdateOut [O] Destination
6675 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
6677 return VarDateFromR8(ulIn, pdateOut);
6680 /**********************************************************************
6681 * VarDateFromDec (OLEAUT32.224)
6683 * Convert a VT_DECIMAL to a VT_DATE.
6687 * pdateOut [O] Destination
6692 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
6694 return VarR8FromDec(pdecIn, pdateOut);
6697 /******************************************************************************
6698 * VarDateFromI8 (OLEAUT32.364)
6700 * Convert a VT_I8 to a VT_DATE.
6704 * pdateOut [O] Destination
6708 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
6710 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
6712 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
6713 *pdateOut = (DATE)llIn;
6717 /******************************************************************************
6718 * VarDateFromUI8 (OLEAUT32.365)
6720 * Convert a VT_UI8 to a VT_DATE.
6724 * pdateOut [O] Destination
6728 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
6730 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
6732 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
6733 *pdateOut = (DATE)ullIn;