2 * Low level variant functions
4 * Copyright 2003 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
25 #include "wine/debug.h"
26 #include "wine/unicode.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(variant);
35 extern HMODULE OLEAUT32_hModule;
37 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
38 #define CY_MULTIPLIER_F 10000.0
39 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
40 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
42 static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' };
43 static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' };
45 /* Copy data from one variant to another. */
46 static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
51 case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
54 case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
59 case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
64 case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break;
65 case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break;
66 case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
67 case VT_BSTR: memcpy(pOut, &V_BSTR(srcVar), sizeof(BSTR)); break;
69 FIXME("VT_ type %d unhandled, please report!\n", vt);
73 /* Macro to inline conversion from a float or double to any integer type,
74 * rounding according to the 'dutch' convention.
76 #define VARIANT_DutchRound(typ, value, res) do { \
77 double whole = value < 0 ? ceil(value) : floor(value); \
78 double fract = value - whole; \
79 if (fract > 0.5) res = (typ)whole + (typ)1; \
80 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
81 else if (fract >= 0.0) res = (typ)whole; \
82 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
83 else if (fract > -0.5) res = (typ)whole; \
84 else res = (typ)whole - (typ)1; \
88 /* Coerce VT_BSTR to a numeric type */
89 static HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
90 void* pOut, VARTYPE vt)
97 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
98 np.cDig = sizeof(rgb) / sizeof(BYTE);
99 np.dwInFlags = NUMPRS_STD;
101 hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
105 /* 1 << vt gives us the VTBIT constant for the destination number type */
106 hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
108 VARIANT_CopyData(&dstVar, vt, pOut);
113 /* Coerce VT_DISPATCH to another type */
114 static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut,
115 VARTYPE vt, DWORD dwFlags)
117 static DISPPARAMS emptyParams = { NULL, NULL, 0, 0 };
118 VARIANTARG srcVar, dstVar;
122 return DISP_E_BADVARTYPE;
124 /* Get the default 'value' property from the IDispatch */
125 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
126 &emptyParams, &srcVar, NULL, NULL);
130 /* Convert the property to the requested type */
131 V_VT(&dstVar) = VT_EMPTY;
132 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt);
133 VariantClear(&srcVar);
137 VARIANT_CopyData(&dstVar, vt, pOut);
138 VariantClear(&srcVar);
142 hRet = DISP_E_TYPEMISMATCH;
146 /* Inline return type */
147 #define RETTYP static inline HRESULT
150 /* Simple compiler cast from one type to another */
151 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
152 *out = in; return S_OK; }
154 /* Compiler cast where input cannot be negative */
155 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
156 if (in < (src)0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
158 /* Compiler cast where input cannot be > some number */
159 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
160 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
162 /* Compiler cast where input cannot be < some number or >= some other number */
163 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
164 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
167 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX)
168 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX)
169 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX)
170 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool)
171 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX)
172 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX)
173 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX)
174 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX)
177 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX)
178 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool)
179 NEGTST(BYTE, signed char, VarUI1FromI1)
180 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX)
181 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX)
182 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX)
183 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX)
184 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX)
187 SIMPLE(SHORT, BYTE, VarI2FromUI1)
188 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX)
189 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool)
190 SIMPLE(SHORT, signed char, VarI2FromI1)
191 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX)
192 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX)
193 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX)
194 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX)
197 SIMPLE(USHORT, BYTE, VarUI2FromUI1)
198 NEGTST(USHORT, SHORT, VarUI2FromI2)
199 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX)
200 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool)
201 NEGTST(USHORT, signed char, VarUI2FromI1)
202 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX)
203 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX)
204 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX)
207 SIMPLE(LONG, BYTE, VarI4FromUI1)
208 SIMPLE(LONG, SHORT, VarI4FromI2)
209 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool)
210 SIMPLE(LONG, signed char, VarI4FromI1)
211 SIMPLE(LONG, USHORT, VarI4FromUI2)
212 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX)
213 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX)
214 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX)
217 SIMPLE(ULONG, BYTE, VarUI4FromUI1)
218 NEGTST(ULONG, SHORT, VarUI4FromI2)
219 NEGTST(ULONG, LONG, VarUI4FromI4)
220 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool)
221 NEGTST(ULONG, signed char, VarUI4FromI1)
222 SIMPLE(ULONG, USHORT, VarUI4FromUI2)
223 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX)
224 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX)
227 SIMPLE(LONG64, BYTE, VarI8FromUI1)
228 SIMPLE(LONG64, SHORT, VarI8FromI2)
229 SIMPLE(LONG64, signed char, VarI8FromI1)
230 SIMPLE(LONG64, USHORT, VarI8FromUI2)
231 SIMPLE(LONG64, ULONG, VarI8FromUI4)
232 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX)
235 SIMPLE(ULONG64, BYTE, VarUI8FromUI1)
236 NEGTST(ULONG64, SHORT, VarUI8FromI2)
237 NEGTST(ULONG64, signed char, VarUI8FromI1)
238 SIMPLE(ULONG64, USHORT, VarUI8FromUI2)
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, 0);
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, 0);
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, 0);
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, 0);
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, 0);
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, 0);
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, 0);
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, 0);
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, 0);
2857 /************************************************************************
2858 * VarR4FromBool (OLEAUT32.76)
2860 * Convert a VT_BOOL to a VT_R4.
2864 * pFltOut [O] Destination
2869 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2871 return VarR4FromI2(boolIn, pFltOut);
2874 /************************************************************************
2875 * VarR4FromI1 (OLEAUT32.213)
2877 * Convert a VT_I1 to a VT_R4.
2881 * pFltOut [O] Destination
2885 * Failure: E_INVALIDARG, if the source value is invalid
2886 * DISP_E_OVERFLOW, if the value will not fit in the destination
2887 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2889 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2891 return _VarR4FromI1(cIn, pFltOut);
2894 /************************************************************************
2895 * VarR4FromUI2 (OLEAUT32.214)
2897 * Convert a VT_UI2 to a VT_R4.
2901 * pFltOut [O] Destination
2905 * Failure: E_INVALIDARG, if the source value is invalid
2906 * DISP_E_OVERFLOW, if the value will not fit in the destination
2907 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2909 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2911 return _VarR4FromUI2(usIn, pFltOut);
2914 /************************************************************************
2915 * VarR4FromUI4 (OLEAUT32.215)
2917 * Convert a VT_UI4 to a VT_R4.
2921 * pFltOut [O] Destination
2925 * Failure: E_INVALIDARG, if the source value is invalid
2926 * DISP_E_OVERFLOW, if the value will not fit in the destination
2927 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2929 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2931 return _VarR4FromUI4(ulIn, pFltOut);
2934 /************************************************************************
2935 * VarR4FromDec (OLEAUT32.216)
2937 * Convert a VT_DECIMAL to a VT_R4.
2941 * pFltOut [O] Destination
2945 * Failure: E_INVALIDARG, if the source value is invalid.
2947 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
2949 BYTE scale = DEC_SCALE(pDecIn);
2953 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2954 return E_INVALIDARG;
2959 if (DEC_SIGN(pDecIn))
2962 if (DEC_HI32(pDecIn))
2964 highPart = (double)DEC_HI32(pDecIn) / (double)divisor;
2965 highPart *= 4294967296.0F;
2966 highPart *= 4294967296.0F;
2971 *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart;
2975 /************************************************************************
2976 * VarR4FromI8 (OLEAUT32.360)
2978 * Convert a VT_I8 to a VT_R4.
2982 * pFltOut [O] Destination
2987 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2989 return _VarR4FromI8(llIn, pFltOut);
2992 /************************************************************************
2993 * VarR4FromUI8 (OLEAUT32.361)
2995 * Convert a VT_UI8 to a VT_R4.
2999 * pFltOut [O] Destination
3004 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
3006 return _VarR4FromUI8(ullIn, pFltOut);
3009 /************************************************************************
3010 * VarR4CmpR8 (OLEAUT32.316)
3012 * Compare a VT_R4 to a VT_R8.
3015 * fltLeft [I] Source
3016 * dblRight [I] Value to compare
3019 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3020 * equal to or greater than dblRight respectively.
3022 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3024 if (fltLeft < dblRight)
3026 else if (fltLeft > dblRight)
3034 /************************************************************************
3035 * VarR8FromUI1 (OLEAUT32.78)
3037 * Convert a VT_UI1 to a VT_R8.
3041 * pDblOut [O] Destination
3046 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3048 return _VarR8FromUI1(bIn, pDblOut);
3051 /************************************************************************
3052 * VarR8FromI2 (OLEAUT32.79)
3054 * Convert a VT_I2 to a VT_R8.
3058 * pDblOut [O] Destination
3063 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3065 return _VarR8FromI2(sIn, pDblOut);
3068 /************************************************************************
3069 * VarR8FromI4 (OLEAUT32.80)
3071 * Convert a VT_I4 to a VT_R8.
3075 * pDblOut [O] Destination
3080 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3082 return _VarR8FromI4(lIn, pDblOut);
3085 /************************************************************************
3086 * VarR8FromR4 (OLEAUT32.81)
3088 * Convert a VT_R4 to a VT_R8.
3092 * pDblOut [O] Destination
3097 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3099 return _VarR8FromR4(fltIn, pDblOut);
3102 /************************************************************************
3103 * VarR8FromCy (OLEAUT32.82)
3105 * Convert a VT_CY to a VT_R8.
3109 * pDblOut [O] Destination
3114 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3116 return _VarR8FromCy(cyIn, pDblOut);
3119 /************************************************************************
3120 * VarR8FromDate (OLEAUT32.83)
3122 * Convert a VT_DATE to a VT_R8.
3126 * pDblOut [O] Destination
3131 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3133 return _VarR8FromDate(dateIn, pDblOut);
3136 /************************************************************************
3137 * VarR8FromStr (OLEAUT32.84)
3139 * Convert a VT_BSTR to a VT_R8.
3143 * lcid [I] LCID for the conversion
3144 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3145 * pDblOut [O] Destination
3149 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3150 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3152 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3154 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3157 /************************************************************************
3158 * VarR8FromDisp (OLEAUT32.85)
3160 * Convert a VT_DISPATCH to a VT_R8.
3163 * pdispIn [I] Source
3164 * lcid [I] LCID for conversion
3165 * pDblOut [O] Destination
3169 * Failure: E_INVALIDARG, if the source value is invalid
3170 * DISP_E_OVERFLOW, if the value will not fit in the destination
3171 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3173 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3175 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0);
3178 /************************************************************************
3179 * VarR8FromBool (OLEAUT32.86)
3181 * Convert a VT_BOOL to a VT_R8.
3185 * pDblOut [O] Destination
3190 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3192 return VarR8FromI2(boolIn, pDblOut);
3195 /************************************************************************
3196 * VarR8FromI1 (OLEAUT32.217)
3198 * Convert a VT_I1 to a VT_R8.
3202 * pDblOut [O] Destination
3206 * Failure: E_INVALIDARG, if the source value is invalid
3207 * DISP_E_OVERFLOW, if the value will not fit in the destination
3208 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3210 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3212 return _VarR8FromI1(cIn, pDblOut);
3215 /************************************************************************
3216 * VarR8FromUI2 (OLEAUT32.218)
3218 * Convert a VT_UI2 to a VT_R8.
3222 * pDblOut [O] Destination
3226 * Failure: E_INVALIDARG, if the source value is invalid
3227 * DISP_E_OVERFLOW, if the value will not fit in the destination
3228 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3230 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3232 return _VarR8FromUI2(usIn, pDblOut);
3235 /************************************************************************
3236 * VarR8FromUI4 (OLEAUT32.219)
3238 * Convert a VT_UI4 to a VT_R8.
3242 * pDblOut [O] Destination
3246 * Failure: E_INVALIDARG, if the source value is invalid
3247 * DISP_E_OVERFLOW, if the value will not fit in the destination
3248 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3250 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3252 return _VarR8FromUI4(ulIn, pDblOut);
3255 /************************************************************************
3256 * VarR8FromDec (OLEAUT32.220)
3258 * Convert a VT_DECIMAL to a VT_R8.
3262 * pDblOut [O] Destination
3266 * Failure: E_INVALIDARG, if the source value is invalid.
3268 HRESULT WINAPI VarR8FromDec(DECIMAL* pDecIn, double *pDblOut)
3270 BYTE scale = DEC_SCALE(pDecIn);
3271 double divisor = 1.0, highPart;
3273 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3274 return E_INVALIDARG;
3279 if (DEC_SIGN(pDecIn))
3282 if (DEC_HI32(pDecIn))
3284 highPart = (double)DEC_HI32(pDecIn) / divisor;
3285 highPart *= 4294967296.0F;
3286 highPart *= 4294967296.0F;
3291 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3295 /************************************************************************
3296 * VarR8FromI8 (OLEAUT32.362)
3298 * Convert a VT_I8 to a VT_R8.
3302 * pDblOut [O] Destination
3307 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3309 return _VarR8FromI8(llIn, pDblOut);
3312 /************************************************************************
3313 * VarR8FromUI8 (OLEAUT32.363)
3315 * Convert a VT_UI8 to a VT_R8.
3319 * pDblOut [O] Destination
3324 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3326 return _VarR8FromUI8(ullIn, pDblOut);
3329 /************************************************************************
3330 * VarR8Pow (OLEAUT32.315)
3332 * Raise a VT_R8 to a power.
3335 * dblLeft [I] Source
3336 * dblPow [I] Power to raise dblLeft by
3337 * pDblOut [O] Destination
3340 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3342 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3344 *pDblOut = pow(dblLeft, dblPow);
3348 /************************************************************************
3349 * VarR8Round (OLEAUT32.317)
3351 * Round a VT_R8 to a given number of decimal points.
3355 * nDig [I] Number of decimal points to round to
3356 * pDblOut [O] Destination for rounded number
3359 * Success: S_OK. pDblOut is rounded to nDig digits.
3360 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3363 * The native version of this function rounds using the internal
3364 * binary representation of the number. Wine uses the dutch rounding
3365 * convention, so therefore small differences can occur in the value returned.
3366 * MSDN says that you should use your own rounding function if you want
3367 * rounding to be predictable in your application.
3369 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3371 double scale, whole, fract;
3374 return E_INVALIDARG;
3376 scale = pow(10.0, nDig);
3379 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3380 fract = dblIn - whole;
3383 dblIn = whole + 1.0;
3384 else if (fract == 0.5)
3385 dblIn = whole + fmod(whole, 2.0);
3386 else if (fract >= 0.0)
3388 else if (fract == -0.5)
3389 dblIn = whole - fmod(whole, 2.0);
3390 else if (fract > -0.5)
3393 dblIn = whole - 1.0;
3395 *pDblOut = dblIn / scale;
3402 /* Powers of 10 from 0..4 D.P. */
3403 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3404 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3406 /************************************************************************
3407 * VarCyFromUI1 (OLEAUT32.98)
3409 * Convert a VT_UI1 to a VT_CY.
3413 * pCyOut [O] Destination
3417 * Failure: E_INVALIDARG, if the source value is invalid
3418 * DISP_E_OVERFLOW, if the value will not fit in the destination
3419 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3421 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3423 return VarCyFromR8(bIn, pCyOut);
3426 /************************************************************************
3427 * VarCyFromI2 (OLEAUT32.99)
3429 * Convert a VT_I2 to a VT_CY.
3433 * pCyOut [O] Destination
3437 * Failure: E_INVALIDARG, if the source value is invalid
3438 * DISP_E_OVERFLOW, if the value will not fit in the destination
3439 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3441 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3443 return VarCyFromR8(sIn, pCyOut);
3446 /************************************************************************
3447 * VarCyFromI4 (OLEAUT32.100)
3449 * Convert a VT_I4 to a VT_CY.
3453 * pCyOut [O] Destination
3457 * Failure: E_INVALIDARG, if the source value is invalid
3458 * DISP_E_OVERFLOW, if the value will not fit in the destination
3459 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3461 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3463 return VarCyFromR8(lIn, pCyOut);
3466 /************************************************************************
3467 * VarCyFromR4 (OLEAUT32.101)
3469 * Convert a VT_R4 to a VT_CY.
3473 * pCyOut [O] Destination
3477 * Failure: E_INVALIDARG, if the source value is invalid
3478 * DISP_E_OVERFLOW, if the value will not fit in the destination
3479 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3481 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3483 return VarCyFromR8(fltIn, pCyOut);
3486 /************************************************************************
3487 * VarCyFromR8 (OLEAUT32.102)
3489 * Convert a VT_R8 to a VT_CY.
3493 * pCyOut [O] Destination
3497 * Failure: E_INVALIDARG, if the source value is invalid
3498 * DISP_E_OVERFLOW, if the value will not fit in the destination
3499 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3501 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3503 #if defined(__GNUC__) && defined(__i386__)
3504 /* This code gives identical results to Win32 on Intel.
3505 * Here we use fp exceptions to catch overflows when storing the value.
3507 static const unsigned short r8_fpcontrol = 0x137f;
3508 static const double r8_multiplier = CY_MULTIPLIER_F;
3509 unsigned short old_fpcontrol, result_fpstatus;
3511 /* Clear exceptions, save the old fp state and load the new state */
3512 __asm__ __volatile__( "fnclex" );
3513 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3514 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3515 /* Perform the conversion. */
3516 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3517 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3518 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3519 /* Save the resulting fp state, load the old state and clear exceptions */
3520 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3521 __asm__ __volatile__( "fnclex" );
3522 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3524 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3525 return DISP_E_OVERFLOW;
3527 /* This version produces slightly different results for boundary cases */
3528 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3529 return DISP_E_OVERFLOW;
3530 dblIn *= CY_MULTIPLIER_F;
3531 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3536 /************************************************************************
3537 * VarCyFromDate (OLEAUT32.103)
3539 * Convert a VT_DATE to a VT_CY.
3543 * pCyOut [O] Destination
3547 * Failure: E_INVALIDARG, if the source value is invalid
3548 * DISP_E_OVERFLOW, if the value will not fit in the destination
3549 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3551 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3553 return VarCyFromR8(dateIn, pCyOut);
3556 /************************************************************************
3557 * VarCyFromStr (OLEAUT32.104)
3559 * Convert a VT_BSTR to a VT_CY.
3563 * lcid [I] LCID for the conversion
3564 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3565 * pCyOut [O] Destination
3569 * Failure: E_INVALIDARG, if the source value is invalid
3570 * DISP_E_OVERFLOW, if the value will not fit in the destination
3571 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3573 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3575 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3578 /************************************************************************
3579 * VarCyFromDisp (OLEAUT32.105)
3581 * Convert a VT_DISPATCH to a VT_CY.
3584 * pdispIn [I] Source
3585 * lcid [I] LCID for conversion
3586 * pCyOut [O] Destination
3590 * Failure: E_INVALIDARG, if the source value is invalid
3591 * DISP_E_OVERFLOW, if the value will not fit in the destination
3592 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3594 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3596 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0);
3599 /************************************************************************
3600 * VarCyFromBool (OLEAUT32.106)
3602 * Convert a VT_BOOL to a VT_CY.
3606 * pCyOut [O] Destination
3610 * Failure: E_INVALIDARG, if the source value is invalid
3611 * DISP_E_OVERFLOW, if the value will not fit in the destination
3612 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3615 * While the sign of the boolean is stored in the currency, the value is
3616 * converted to either 0 or 1.
3618 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3620 return VarCyFromR8(boolIn, pCyOut);
3623 /************************************************************************
3624 * VarCyFromI1 (OLEAUT32.225)
3626 * Convert a VT_I1 to a VT_CY.
3630 * pCyOut [O] Destination
3634 * Failure: E_INVALIDARG, if the source value is invalid
3635 * DISP_E_OVERFLOW, if the value will not fit in the destination
3636 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3638 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3640 return VarCyFromR8(cIn, pCyOut);
3643 /************************************************************************
3644 * VarCyFromUI2 (OLEAUT32.226)
3646 * Convert a VT_UI2 to a VT_CY.
3650 * pCyOut [O] Destination
3654 * Failure: E_INVALIDARG, if the source value is invalid
3655 * DISP_E_OVERFLOW, if the value will not fit in the destination
3656 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3658 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3660 return VarCyFromR8(usIn, pCyOut);
3663 /************************************************************************
3664 * VarCyFromUI4 (OLEAUT32.227)
3666 * Convert a VT_UI4 to a VT_CY.
3670 * pCyOut [O] Destination
3674 * Failure: E_INVALIDARG, if the source value is invalid
3675 * DISP_E_OVERFLOW, if the value will not fit in the destination
3676 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3678 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3680 return VarCyFromR8(ulIn, pCyOut);
3683 /************************************************************************
3684 * VarCyFromDec (OLEAUT32.228)
3686 * Convert a VT_DECIMAL to a VT_CY.
3690 * pCyOut [O] Destination
3694 * Failure: E_INVALIDARG, if the source value is invalid
3695 * DISP_E_OVERFLOW, if the value will not fit in the destination
3696 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3698 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
3703 hRet = VarDecRound(pdecIn, 4, &rounded);
3705 if (SUCCEEDED(hRet))
3709 if (DEC_HI32(&rounded))
3710 return DISP_E_OVERFLOW;
3712 /* Note: Without the casts this promotes to int64 which loses precision */
3713 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3714 if (DEC_SIGN(&rounded))
3716 return VarCyFromR8(d, pCyOut);
3721 /************************************************************************
3722 * VarCyFromI8 (OLEAUT32.366)
3724 * Convert a VT_I8 to a VT_CY.
3728 * pCyOut [O] Destination
3732 * Failure: E_INVALIDARG, if the source value is invalid
3733 * DISP_E_OVERFLOW, if the value will not fit in the destination
3734 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3736 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3738 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3739 pCyOut->int64 = llIn * CY_MULTIPLIER;
3743 /************************************************************************
3744 * VarCyFromUI8 (OLEAUT32.375)
3746 * Convert a VT_UI8 to a VT_CY.
3750 * pCyOut [O] Destination
3754 * Failure: E_INVALIDARG, if the source value is invalid
3755 * DISP_E_OVERFLOW, if the value will not fit in the destination
3756 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3758 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3760 return VarCyFromR8(ullIn, pCyOut);
3763 /************************************************************************
3764 * VarCyAdd (OLEAUT32.299)
3766 * Add one CY to another.
3770 * cyRight [I] Value to add
3771 * pCyOut [O] Destination
3775 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3777 HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut)
3780 _VarR8FromCy(cyLeft, &l);
3781 _VarR8FromCy(cyRight, &r);
3783 return VarCyFromR8(l, pCyOut);
3786 /************************************************************************
3787 * VarCyMul (OLEAUT32.303)
3789 * Multiply one CY by another.
3793 * cyRight [I] Value to multiply by
3794 * pCyOut [O] Destination
3798 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3800 HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut)
3803 _VarR8FromCy(cyLeft, &l);
3804 _VarR8FromCy(cyRight, &r);
3806 return VarCyFromR8(l, pCyOut);
3809 /************************************************************************
3810 * VarCyMulI4 (OLEAUT32.304)
3812 * Multiply one CY by a VT_I4.
3816 * lRight [I] Value to multiply by
3817 * pCyOut [O] Destination
3821 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3823 HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut)
3827 _VarR8FromCy(cyLeft, &d);
3829 return VarCyFromR8(d, pCyOut);
3832 /************************************************************************
3833 * VarCySub (OLEAUT32.305)
3835 * Subtract one CY from another.
3839 * cyRight [I] Value to subtract
3840 * pCyOut [O] Destination
3844 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3846 HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut)
3849 _VarR8FromCy(cyLeft, &l);
3850 _VarR8FromCy(cyRight, &r);
3852 return VarCyFromR8(l, pCyOut);
3855 /************************************************************************
3856 * VarCyAbs (OLEAUT32.306)
3858 * Convert a VT_CY into its absolute value.
3862 * pCyOut [O] Destination
3865 * Success: S_OK. pCyOut contains the absolute value.
3866 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3868 HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut)
3870 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3871 return DISP_E_OVERFLOW;
3873 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3877 /************************************************************************
3878 * VarCyFix (OLEAUT32.307)
3880 * Return the integer part of a VT_CY.
3884 * pCyOut [O] Destination
3888 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3891 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3892 * negative numbers away from 0, while this function rounds them towards zero.
3894 HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut)
3896 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3897 pCyOut->int64 *= CY_MULTIPLIER;
3901 /************************************************************************
3902 * VarCyInt (OLEAUT32.308)
3904 * Return the integer part of a VT_CY.
3908 * pCyOut [O] Destination
3912 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3915 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3916 * negative numbers towards 0, while this function rounds them away from zero.
3918 HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut)
3920 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3921 pCyOut->int64 *= CY_MULTIPLIER;
3923 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3925 pCyOut->int64 -= CY_MULTIPLIER;
3930 /************************************************************************
3931 * VarCyNeg (OLEAUT32.309)
3933 * Change the sign of a VT_CY.
3937 * pCyOut [O] Destination
3941 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3943 HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut)
3945 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3946 return DISP_E_OVERFLOW;
3948 pCyOut->int64 = -cyIn.int64;
3952 /************************************************************************
3953 * VarCyRound (OLEAUT32.310)
3955 * Change the precision of a VT_CY.
3959 * cDecimals [I] New number of decimals to keep
3960 * pCyOut [O] Destination
3964 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3966 HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
3969 return E_INVALIDARG;
3973 /* Rounding to more precision than we have */
3979 double d, div = CY_Divisors[cDecimals];
3981 _VarR8FromCy(cyIn, &d);
3983 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3984 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3985 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3990 /************************************************************************
3991 * VarCyCmp (OLEAUT32.311)
3993 * Compare two VT_CY values.
3997 * cyRight [I] Value to compare
4000 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4001 * compare is less, equal or greater than source respectively.
4002 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4004 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
4009 /* Subtract right from left, and compare the result to 0 */
4010 hRet = VarCySub(cyLeft, cyRight, &result);
4012 if (SUCCEEDED(hRet))
4014 if (result.int64 < 0)
4015 hRet = (HRESULT)VARCMP_LT;
4016 else if (result.int64 > 0)
4017 hRet = (HRESULT)VARCMP_GT;
4019 hRet = (HRESULT)VARCMP_EQ;
4024 /************************************************************************
4025 * VarCyCmpR8 (OLEAUT32.312)
4027 * Compare a VT_CY to a double
4030 * cyLeft [I] Currency Source
4031 * dblRight [I] double to compare to cyLeft
4034 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4035 * less than, equal to or greater than cyLeft respectively.
4036 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4038 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight)
4043 hRet = VarCyFromR8(dblRight, &cyRight);
4045 if (SUCCEEDED(hRet))
4046 hRet = VarCyCmp(cyLeft, cyRight);
4051 /************************************************************************
4052 * VarCyMulI8 (OLEAUT32.329)
4054 * Multiply a VT_CY by a VT_I8.
4058 * llRight [I] Value to multiply by
4059 * pCyOut [O] Destination
4063 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4065 HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
4069 _VarR8FromCy(cyLeft, &d);
4070 d = d * (double)llRight;
4071 return VarCyFromR8(d, pCyOut);
4077 /************************************************************************
4078 * VarDecFromUI1 (OLEAUT32.190)
4080 * Convert a VT_UI1 to a DECIMAL.
4084 * pDecOut [O] Destination
4089 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4091 return VarDecFromUI4(bIn, pDecOut);
4094 /************************************************************************
4095 * VarDecFromI2 (OLEAUT32.191)
4097 * Convert a VT_I2 to a DECIMAL.
4101 * pDecOut [O] Destination
4106 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4108 return VarDecFromI4(sIn, pDecOut);
4111 /************************************************************************
4112 * VarDecFromI4 (OLEAUT32.192)
4114 * Convert a VT_I4 to a DECIMAL.
4118 * pDecOut [O] Destination
4123 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4125 DEC_HI32(pDecOut) = 0;
4126 DEC_MID32(pDecOut) = 0;
4130 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4131 DEC_LO32(pDecOut) = -lIn;
4135 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4136 DEC_LO32(pDecOut) = lIn;
4141 #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT))
4143 /* internal representation of the value stored in a DECIMAL. The bytes are
4144 stored from LSB at index 0 to MSB at index 11
4146 typedef struct DECIMAL_internal
4148 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4149 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4150 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4153 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest);
4154 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest);
4155 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to);
4156 static void VARIANT_DecFromDI(VARIANT_DI * from, DECIMAL * to);
4158 /************************************************************************
4159 * VarDecFromR4 (OLEAUT32.193)
4161 * Convert a VT_R4 to a DECIMAL.
4165 * pDecOut [O] Destination
4170 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4175 hres = VARIANT_DI_FromR4(fltIn, &di);
4176 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4180 /************************************************************************
4181 * VarDecFromR8 (OLEAUT32.194)
4183 * Convert a VT_R8 to a DECIMAL.
4187 * pDecOut [O] Destination
4192 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4197 hres = VARIANT_DI_FromR8(dblIn, &di);
4198 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4202 /************************************************************************
4203 * VarDecFromDate (OLEAUT32.195)
4205 * Convert a VT_DATE to a DECIMAL.
4209 * pDecOut [O] Destination
4214 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4216 return VarDecFromR8(dateIn, pDecOut);
4219 /************************************************************************
4220 * VarDecFromCy (OLEAUT32.196)
4222 * Convert a VT_CY to a DECIMAL.
4226 * pDecOut [O] Destination
4231 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4233 DEC_HI32(pDecOut) = 0;
4235 /* Note: This assumes 2s complement integer representation */
4236 if (cyIn.s.Hi & 0x80000000)
4238 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4239 DEC_LO64(pDecOut) = -cyIn.int64;
4243 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4244 DEC_MID32(pDecOut) = cyIn.s.Hi;
4245 DEC_LO32(pDecOut) = cyIn.s.Lo;
4250 /************************************************************************
4251 * VarDecFromStr (OLEAUT32.197)
4253 * Convert a VT_BSTR to a DECIMAL.
4257 * lcid [I] LCID for the conversion
4258 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4259 * pDecOut [O] Destination
4263 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4265 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4267 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4270 /************************************************************************
4271 * VarDecFromDisp (OLEAUT32.198)
4273 * Convert a VT_DISPATCH to a DECIMAL.
4276 * pdispIn [I] Source
4277 * lcid [I] LCID for conversion
4278 * pDecOut [O] Destination
4282 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4284 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4286 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0);
4289 /************************************************************************
4290 * VarDecFromBool (OLEAUT32.199)
4292 * Convert a VT_BOOL to a DECIMAL.
4296 * pDecOut [O] Destination
4302 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4304 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4306 DEC_HI32(pDecOut) = 0;
4307 DEC_MID32(pDecOut) = 0;
4310 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4311 DEC_LO32(pDecOut) = 1;
4315 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4316 DEC_LO32(pDecOut) = 0;
4321 /************************************************************************
4322 * VarDecFromI1 (OLEAUT32.241)
4324 * Convert a VT_I1 to a DECIMAL.
4328 * pDecOut [O] Destination
4333 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4335 return VarDecFromI4(cIn, pDecOut);
4338 /************************************************************************
4339 * VarDecFromUI2 (OLEAUT32.242)
4341 * Convert a VT_UI2 to a DECIMAL.
4345 * pDecOut [O] Destination
4350 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4352 return VarDecFromUI4(usIn, pDecOut);
4355 /************************************************************************
4356 * VarDecFromUI4 (OLEAUT32.243)
4358 * Convert a VT_UI4 to a DECIMAL.
4362 * pDecOut [O] Destination
4367 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4369 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4370 DEC_HI32(pDecOut) = 0;
4371 DEC_MID32(pDecOut) = 0;
4372 DEC_LO32(pDecOut) = ulIn;
4376 /************************************************************************
4377 * VarDecFromI8 (OLEAUT32.374)
4379 * Convert a VT_I8 to a DECIMAL.
4383 * pDecOut [O] Destination
4388 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4390 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4392 DEC_HI32(pDecOut) = 0;
4394 /* Note: This assumes 2s complement integer representation */
4395 if (pLi->u.HighPart & 0x80000000)
4397 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4398 DEC_LO64(pDecOut) = -pLi->QuadPart;
4402 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4403 DEC_MID32(pDecOut) = pLi->u.HighPart;
4404 DEC_LO32(pDecOut) = pLi->u.LowPart;
4409 /************************************************************************
4410 * VarDecFromUI8 (OLEAUT32.375)
4412 * Convert a VT_UI8 to a DECIMAL.
4416 * pDecOut [O] Destination
4421 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4423 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4424 DEC_HI32(pDecOut) = 0;
4425 DEC_LO64(pDecOut) = ullIn;
4429 /* Make two DECIMALS the same scale; used by math functions below */
4430 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4431 const DECIMAL** ppDecRight,
4434 static DECIMAL scaleFactor;
4437 HRESULT hRet = S_OK;
4439 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4440 return E_INVALIDARG;
4442 DEC_LO32(&scaleFactor) = 10;
4444 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4447 return S_OK; /* Same scale */
4449 if (scaleAmount > 0)
4451 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4452 *ppDecRight = pDecOut;
4456 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4457 *ppDecLeft = pDecOut;
4458 i = scaleAmount = -scaleAmount;
4461 if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE)
4462 return DISP_E_OVERFLOW; /* Can't scale up */
4464 /* Multiply up the value to be scaled by the correct amount */
4465 while (SUCCEEDED(hRet) && i--)
4467 /* Note we are multiplying by a value with a scale of 0, so we don't recurse */
4468 hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut);
4471 DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */
4475 /* Add two unsigned 32 bit values with overflow */
4476 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4478 ULARGE_INTEGER ul64;
4480 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4481 *pulHigh = ul64.u.HighPart;
4482 return ul64.u.LowPart;
4485 /* Subtract two unsigned 32 bit values with underflow */
4486 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4489 ULARGE_INTEGER ul64;
4491 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4492 if (ulLeft < ulRight)
4495 if (ul64.QuadPart > (ULONG64)*pulHigh)
4496 ul64.QuadPart -= (ULONG64)*pulHigh;
4499 ul64.QuadPart -= (ULONG64)*pulHigh;
4503 ul64.u.HighPart = -ul64.u.HighPart ;
4505 *pulHigh = ul64.u.HighPart;
4506 return ul64.u.LowPart;
4509 /* Multiply two unsigned 32 bit values with overflow */
4510 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4512 ULARGE_INTEGER ul64;
4514 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4515 *pulHigh = ul64.u.HighPart;
4516 return ul64.u.LowPart;
4519 /* Compare two decimals that have the same scale */
4520 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4522 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4523 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4525 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4530 /************************************************************************
4531 * VarDecAdd (OLEAUT32.177)
4533 * Add one DECIMAL to another.
4536 * pDecLeft [I] Source
4537 * pDecRight [I] Value to add
4538 * pDecOut [O] Destination
4542 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4544 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4549 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled);
4551 if (SUCCEEDED(hRet))
4553 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4555 BYTE sign = DECIMAL_POS;
4557 /* Correct for the sign of the result */
4558 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4560 /* -x + -y : Negative */
4562 goto VarDecAdd_AsPositive;
4564 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4566 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4568 /* -x + y : Negative if x > y */
4572 VarDecAdd_AsNegative:
4573 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4574 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4575 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4579 VarDecAdd_AsInvertedNegative:
4580 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4581 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4582 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4585 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4587 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4589 /* x + -y : Negative if x <= y */
4593 goto VarDecAdd_AsInvertedNegative;
4595 goto VarDecAdd_AsNegative;
4599 /* x + y : Positive */
4600 VarDecAdd_AsPositive:
4601 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4602 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4603 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4607 return DISP_E_OVERFLOW; /* overflowed */
4609 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4610 DEC_SIGN(pDecOut) = sign;
4615 /* translate from external DECIMAL format into an internal representation */
4616 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4618 to->scale = DEC_SCALE(from);
4619 to->sign = DEC_SIGN(from) ? 1 : 0;
4621 to->bitsnum[0] = DEC_LO32(from);
4622 to->bitsnum[1] = DEC_MID32(from);
4623 to->bitsnum[2] = DEC_HI32(from);
4626 static void VARIANT_DecFromDI(VARIANT_DI * from, DECIMAL * to)
4629 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4631 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4634 DEC_LO32(to) = from->bitsnum[0];
4635 DEC_MID32(to) = from->bitsnum[1];
4636 DEC_HI32(to) = from->bitsnum[2];
4639 /* clear an internal representation of a DECIMAL */
4640 static void VARIANT_DI_clear(VARIANT_DI * i)
4642 memset(i, 0, sizeof(VARIANT_DI));
4645 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4646 size is supported. The value in p is replaced by the quotient of the division, and
4647 the remainder is returned as a result. This routine is most often used with a divisor
4648 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4650 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4655 } else if (divisor == 1) {
4656 /* dividend remains unchanged */
4659 unsigned char remainder = 0;
4660 ULONGLONG iTempDividend;
4663 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4664 for (; i >= 0; i--) {
4665 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4666 remainder = iTempDividend % divisor;
4667 p[i] = iTempDividend / divisor;
4674 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4675 static int VARIANT_int_iszero(DWORD * p, unsigned int n)
4677 for (; n > 0; n--) if (*p++ != 0) return 0;
4681 /* multiply two DECIMALS, without changing either one, and place result in third
4682 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4683 digits when scale > 0 in order to fit an overflowing result. Final overflow
4686 static int VARIANT_DI_mul(VARIANT_DI * a, VARIANT_DI * b, VARIANT_DI * result)
4690 signed int mulstart;
4692 VARIANT_DI_clear(result);
4693 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4695 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4696 of the result is formed by adding the scales of the operands.
4698 result->scale = a->scale + b->scale;
4699 memset(running, 0, sizeof(running));
4701 /* count number of leading zero-bytes in operand A */
4702 for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4704 /* result is 0, because operand A is 0 */
4708 unsigned char remainder = 0;
4711 /* perform actual multiplication */
4712 for (iA = 0; iA <= mulstart; iA++) {
4716 for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
4720 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4723 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4729 /* Too bad - native oleaut does not do this, so we should not either */
4731 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4732 This operation should not lose significant digits, and gives an
4733 opportunity to reduce the possibility of overflows in future
4734 operations issued by the application.
4736 while (result->scale > 0) {
4737 memcpy(quotient, running, sizeof(quotient));
4738 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4739 if (remainder > 0) break;
4740 memcpy(running, quotient, sizeof(quotient));
4744 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4745 This operation *will* lose significant digits of the result because
4746 all the factors of 10 were consumed by the previous operation.
4748 while (result->scale > 0 && !VARIANT_int_iszero(
4749 running + sizeof(result->bitsnum) / sizeof(DWORD),
4750 (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
4752 remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
4753 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4757 /* round up the result - native oleaut32 does this */
4758 if (remainder >= 5) {
4760 for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
4761 ULONGLONG digit = running[i] + 1;
4762 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4763 running[i] = digit & 0xFFFFFFFF;
4767 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4768 and copy result bits into result structure
4770 r_overflow = !VARIANT_int_iszero(
4771 running + sizeof(result->bitsnum)/sizeof(DWORD),
4772 (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
4773 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4778 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4779 hardcoded (period for decimal separator, dash as negative sign). Returns 0 for
4780 success, nonzero if insufficient space in output buffer.
4782 static int VARIANT_DI_tostringW(VARIANT_DI * a, WCHAR * s, unsigned int n)
4786 unsigned char remainder;
4789 /* place negative sign */
4790 if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
4798 /* prepare initial 0 */
4803 } else overflow = 1;
4807 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4808 while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
4809 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4813 s[i++] = '0' + remainder;
4818 if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
4820 /* reverse order of digits */
4821 WCHAR * x = s; WCHAR * y = s + i - 1;
4828 /* check for decimal point. "i" now has string length */
4829 if (i <= a->scale) {
4830 unsigned int numzeroes = a->scale + 1 - i;
4831 if (i + 1 + numzeroes >= n) {
4834 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4836 while (numzeroes > 0) {
4837 s[--numzeroes] = '0';
4842 /* place decimal point */
4844 unsigned int periodpos = i - a->scale;
4848 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4849 s[periodpos] = '.'; i++;
4851 /* remove extra zeros at the end, if any */
4852 while (s[i - 1] == '0') s[--i] = '\0';
4853 if (s[i - 1] == '.') s[--i] = '\0';
4861 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4862 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4867 /* shift whole DWORDs to the left */
4870 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4871 *p = 0; shift -= 32;
4874 /* shift remainder (1..31 bits) */
4876 if (shift > 0) for (i = 0; i < n; i++)
4879 b = p[i] >> (32 - shift);
4880 p[i] = (p[i] << shift) | shifted;
4885 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4886 Value at v is incremented by the value at p. Any size is supported, provided
4887 that v is not shorter than p. Any unapplied carry is returned as a result.
4889 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, DWORD * p,
4892 unsigned char carry = 0;
4898 for (i = 0; i < np; i++) {
4899 sum = (ULONGLONG)v[i]
4902 v[i] = sum & 0xffffffff;
4905 for (; i < nv && carry; i++) {
4906 sum = (ULONGLONG)v[i]
4908 v[i] = sum & 0xffffffff;
4915 /* perform integral division with operand p as dividend. Parameter n indicates
4916 number of available DWORDs in divisor p, but available space in p must be
4917 actually at least 2 * n DWORDs, because the remainder of the integral
4918 division is built in the next n DWORDs past the start of the quotient. This
4919 routine replaces the dividend in p with the quotient, and appends n
4920 additional DWORDs for the remainder.
4922 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4923 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4924 source code to the VLI (Very Large Integer) division operator. This algorithm
4925 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4926 variably-scaled integers such as the MS DECIMAL representation.
4928 static void VARIANT_int_div(DWORD * p, unsigned int n, DWORD * divisor,
4933 DWORD * negdivisor = tempsub + n;
4935 /* build 2s-complement of divisor */
4936 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
4938 VARIANT_int_add(negdivisor, n, p + n, 1);
4939 memset(p + n, 0, n * sizeof(DWORD));
4941 /* skip all leading zero DWORDs in quotient */
4942 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
4943 /* i is now number of DWORDs left to process */
4944 for (i <<= 5; i < (n << 5); i++) {
4945 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
4947 /* trial subtraction */
4948 memcpy(tempsub, p + n, n * sizeof(DWORD));
4949 VARIANT_int_add(tempsub, n, negdivisor, n);
4951 /* check whether result of subtraction was negative */
4952 if ((tempsub[n - 1] & 0x80000000) == 0) {
4953 memcpy(p + n, tempsub, n * sizeof(DWORD));
4959 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4960 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
4965 for (iOverflowMul = 0, i = 0; i < n; i++)
4966 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
4967 return (unsigned char)iOverflowMul;
4970 /* increment value in A by the value indicated in B, with scale adjusting.
4971 Modifies parameters by adjusting scales. Returns 0 if addition was
4972 successful, nonzero if a parameter underflowed before it could be
4973 successfully used in the addition.
4975 static int VARIANT_int_addlossy(
4976 DWORD * a, int * ascale, unsigned int an,
4977 DWORD * b, int * bscale, unsigned int bn)
4981 if (VARIANT_int_iszero(a, an)) {
4982 /* if A is zero, copy B into A, after removing digits */
4983 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
4984 VARIANT_int_divbychar(b, bn, 10);
4987 memcpy(a, b, an * sizeof(DWORD));
4989 } else if (!VARIANT_int_iszero(b, bn)) {
4990 unsigned int tn = an + 1;
4993 if (bn + 1 > tn) tn = bn + 1;
4994 if (*ascale != *bscale) {
4995 /* first (optimistic) try - try to scale down the one with the bigger
4996 scale, while this number is divisible by 10 */
4997 DWORD * digitchosen;
4998 unsigned int nchosen;
5002 if (*ascale < *bscale) {
5003 targetscale = *ascale;
5004 scalechosen = bscale;
5008 targetscale = *bscale;
5009 scalechosen = ascale;
5013 memset(t, 0, tn * sizeof(DWORD));
5014 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5016 /* divide by 10 until target scale is reached */
5017 while (*scalechosen > targetscale) {
5018 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5021 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5026 if (*ascale != *bscale) {
5027 DWORD * digitchosen;
5028 unsigned int nchosen;
5032 /* try to scale up the one with the smaller scale */
5033 if (*ascale > *bscale) {
5034 targetscale = *ascale;
5035 scalechosen = bscale;
5039 targetscale = *bscale;
5040 scalechosen = ascale;
5044 memset(t, 0, tn * sizeof(DWORD));
5045 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5047 /* multiply by 10 until target scale is reached, or
5048 significant bytes overflow the number
5050 while (*scalechosen < targetscale && t[nchosen] == 0) {
5051 VARIANT_int_mulbychar(t, tn, 10);
5052 if (t[nchosen] == 0) {
5053 /* still does not overflow */
5055 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5060 if (*ascale != *bscale) {
5061 /* still different? try to scale down the one with the bigger scale
5062 (this *will* lose significant digits) */
5063 DWORD * digitchosen;
5064 unsigned int nchosen;
5068 if (*ascale < *bscale) {
5069 targetscale = *ascale;
5070 scalechosen = bscale;
5074 targetscale = *bscale;
5075 scalechosen = ascale;
5079 memset(t, 0, tn * sizeof(DWORD));
5080 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5082 /* divide by 10 until target scale is reached */
5083 while (*scalechosen > targetscale) {
5084 VARIANT_int_divbychar(t, tn, 10);
5086 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5090 /* check whether any of the operands still has significant digits
5093 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5096 /* at this step, both numbers have the same scale and can be added
5097 as integers. However, the result might not fit in A, so further
5098 scaling down might be necessary.
5100 while (!underflow) {
5101 memset(t, 0, tn * sizeof(DWORD));
5102 memcpy(t, a, an * sizeof(DWORD));
5104 VARIANT_int_add(t, tn, b, bn);
5105 if (VARIANT_int_iszero(t + an, tn - an)) {
5106 /* addition was successful */
5107 memcpy(a, t, an * sizeof(DWORD));
5110 /* addition overflowed - remove significant digits
5111 from both operands and try again */
5112 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5113 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5114 /* check whether any operand keeps significant digits after
5115 scaledown (underflow case 2)
5117 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5125 /* perform complete DECIMAL division in the internal representation. Returns
5126 0 if the division was completed (even if quotient is set to 0), or nonzero
5127 in case of quotient overflow.
5129 static HRESULT VARIANT_DI_div(VARIANT_DI * dividend, VARIANT_DI * divisor, VARIANT_DI * quotient)
5131 HRESULT r_overflow = S_OK;
5133 if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
5135 r_overflow = DISP_E_DIVBYZERO;
5136 } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
5137 VARIANT_DI_clear(quotient);
5139 int quotientscale, remainderscale, tempquotientscale;
5140 DWORD remainderplusquotient[8];
5143 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5144 tempquotientscale = quotientscale;
5145 VARIANT_DI_clear(quotient);
5146 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5148 /* The following strategy is used for division
5149 1) if there was a nonzero remainder from previous iteration, use it as
5150 dividend for this iteration, else (for first iteration) use intended
5152 2) perform integer division in temporary buffer, develop quotient in
5153 low-order part, remainder in high-order part
5154 3) add quotient from step 2 to final result, with possible loss of
5156 4) multiply integer part of remainder by 10, while incrementing the
5157 scale of the remainder. This operation preserves the intended value
5159 5) loop to step 1 until one of the following is true:
5160 a) remainder is zero (exact division achieved)
5161 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5163 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5164 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5167 remainderplusquotient, 4,
5168 divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
5169 underflow = VARIANT_int_addlossy(
5170 quotient->bitsnum, "ientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
5171 remainderplusquotient, &tempquotientscale, 4);
5172 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5173 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5174 tempquotientscale = ++remainderscale;
5175 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5177 /* quotient scale might now be negative (extremely big number). If, so, try
5178 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5179 until scale is 0. If this cannot be done, it is a real overflow.
5181 while (!r_overflow && quotientscale < 0) {
5182 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5183 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5184 VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
5185 if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
5186 (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
5188 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5189 } else r_overflow = DISP_E_OVERFLOW;
5192 if (quotientscale <= 255) quotient->scale = quotientscale;
5193 else VARIANT_DI_clear(quotient);
5199 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5200 with an undefined scale, which will be assigned to (if possible). It also
5201 receives an exponent of 2. This procedure will then manipulate the mantissa
5202 and calculate a corresponding scale, so that the exponent2 value is assimilated
5203 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5204 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5206 static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, int isDouble)
5208 HRESULT hres = S_OK;
5209 int exponent5, exponent10;
5211 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5212 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5213 exponent10 might be used to set the VARIANT_DI scale directly. However,
5214 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5215 exponent5 = -exponent2;
5216 exponent10 = exponent2;
5218 /* Handle exponent5 > 0 */
5219 while (exponent5 > 0) {
5223 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5224 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5225 somehow the mantissa should be divided by 2. */
5226 if ((val->bitsnum[0] & 1) == 0) {
5227 /* The mantissa is divisible by 2. Therefore the division can be done
5228 without losing significant digits. */
5229 exponent10++; exponent5--;
5232 bPrevCarryBit = val->bitsnum[2] & 1;
5233 val->bitsnum[2] >>= 1;
5234 bCurrCarryBit = val->bitsnum[1] & 1;
5235 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5236 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5238 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5239 be multiplied by 5, unless the multiplication overflows. */
5240 DWORD temp_bitsnum[3];
5244 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5245 if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) {
5246 /* Multiplication succeeded without overflow, so copy result back
5248 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5250 /* Mask out 3 extraneous bits introduced by the multiply */
5252 /* Multiplication by 5 overflows. The mantissa should be divided
5253 by 2, and therefore will lose significant digits. */
5257 bPrevCarryBit = val->bitsnum[2] & 1;
5258 val->bitsnum[2] >>= 1;
5259 bCurrCarryBit = val->bitsnum[1] & 1;
5260 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5261 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5266 /* Handle exponent5 < 0 */
5267 while (exponent5 < 0) {
5268 /* In order to divide the value represented by the VARIANT_DI by 5, it
5269 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5270 and the mantissa should be multiplied by 2 */
5271 if ((val->bitsnum[2] & 0x80000000) == 0) {
5272 /* The mantissa can withstand a shift-left without overflowing */
5273 exponent10--; exponent5++;
5274 VARIANT_int_shiftleft(val->bitsnum, 3, 1);
5276 /* The mantissa would overflow if shifted. Therefore it should be
5277 directly divided by 5. This will lose significant digits, unless
5278 by chance the mantissa happens to be divisible by 5 */
5280 VARIANT_int_divbychar(val->bitsnum, 3, 5);
5284 /* At this point, the mantissa has assimilated the exponent5, but the
5285 exponent10 might not be suitable for assignment. The exponent10 must be
5286 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5287 down appropriately. */
5288 while (hres == S_OK && exponent10 > 0) {
5289 /* In order to bring exponent10 down to 0, the mantissa should be
5290 multiplied by 10 to compensate. If the exponent10 is too big, this
5291 will cause the mantissa to overflow. */
5292 if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) {
5295 hres = DISP_E_OVERFLOW;
5298 while (exponent10 < -DEC_MAX_SCALE) {
5300 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5301 be divided by 10 to compensate. If the exponent10 is too small, this
5302 will cause the mantissa to underflow and become 0 */
5303 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5305 if (VARIANT_int_iszero(val->bitsnum, 3)) {
5306 /* Underflow, unable to keep dividing */
5308 } else if (rem10 >= 5) {
5310 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5313 /* This step is requierd in order to remove excess bits of precision from the
5314 end of the bit representation, down to the precision guaranteed by the
5315 floating point number. */
5317 while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[2] == 0 && (val->bitsnum[1] & 0xFFE00000) != 0))) {
5320 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5324 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5328 while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 ||
5329 (val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) {
5332 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5336 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5340 /* Remove multiples of 10 from the representation */
5341 while (exponent10 < 0) {
5342 DWORD temp_bitsnum[3];
5344 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5345 if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) {
5347 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5351 /* Scale assignment */
5352 if (hres == S_OK) val->scale = -exponent10;
5361 unsigned long m : 23;
5362 unsigned int exp_bias : 8;
5363 unsigned int sign : 1;
5368 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5369 intermediate string step. */
5370 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest)
5372 HRESULT hres = S_OK;
5377 /* Detect special cases */
5378 if (fx.i.m == 0 && fx.i.exp_bias == 0) {
5379 /* Floating-point zero */
5380 VARIANT_DI_clear(dest);
5381 } else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) {
5382 /* Floating-point infinity */
5383 hres = DISP_E_OVERFLOW;
5384 } else if (fx.i.exp_bias == 0xFF) {
5385 /* Floating-point NaN */
5386 hres = DISP_E_BADVARTYPE;
5389 VARIANT_DI_clear(dest);
5391 exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */
5392 dest->sign = fx.i.sign; /* Sign is simply copied */
5394 /* Copy significant bits to VARIANT_DI mantissa */
5395 dest->bitsnum[0] = fx.i.m;
5396 dest->bitsnum[0] &= 0x007FFFFF;
5397 if (fx.i.exp_bias == 0) {
5398 /* Denormalized number - correct exponent */
5401 /* Add hidden bit to mantissa */
5402 dest->bitsnum[0] |= 0x00800000;
5405 /* The act of copying a FP mantissa as integer bits is equivalent to
5406 shifting left the mantissa 23 bits. The exponent2 is reduced to
5410 hres = VARIANT_DI_normalize(dest, exponent2, 0);
5420 unsigned long m_lo : 32; /* 52 bits of precision */
5421 unsigned int m_hi : 20;
5422 unsigned int exp_bias : 11; /* bias == 1023 */
5423 unsigned int sign : 1;
5428 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5429 intermediate string step. */
5430 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest)
5432 HRESULT hres = S_OK;
5437 /* Detect special cases */
5438 if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) {
5439 /* Floating-point zero */
5440 VARIANT_DI_clear(dest);
5441 } else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) {
5442 /* Floating-point infinity */
5443 hres = DISP_E_OVERFLOW;
5444 } else if (fx.i.exp_bias == 0x7FF) {
5445 /* Floating-point NaN */
5446 hres = DISP_E_BADVARTYPE;
5449 VARIANT_DI_clear(dest);
5451 exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */
5452 dest->sign = fx.i.sign; /* Sign is simply copied */
5454 /* Copy significant bits to VARIANT_DI mantissa */
5455 dest->bitsnum[0] = fx.i.m_lo;
5456 dest->bitsnum[1] = fx.i.m_hi;
5457 dest->bitsnum[1] &= 0x000FFFFF;
5458 if (fx.i.exp_bias == 0) {
5459 /* Denormalized number - correct exponent */
5462 /* Add hidden bit to mantissa */
5463 dest->bitsnum[1] |= 0x00100000;
5466 /* The act of copying a FP mantissa as integer bits is equivalent to
5467 shifting left the mantissa 52 bits. The exponent2 is reduced to
5471 hres = VARIANT_DI_normalize(dest, exponent2, 1);
5477 /************************************************************************
5478 * VarDecDiv (OLEAUT32.178)
5480 * Divide one DECIMAL by another.
5483 * pDecLeft [I] Source
5484 * pDecRight [I] Value to divide by
5485 * pDecOut [O] Destination
5489 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5491 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5493 HRESULT hRet = S_OK;
5494 VARIANT_DI di_left, di_right, di_result;
5497 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5499 VARIANT_DIFromDec(pDecLeft, &di_left);
5500 VARIANT_DIFromDec(pDecRight, &di_right);
5501 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result);
5504 /* division actually overflowed */
5511 if (di_result.scale > DEC_MAX_SCALE)
5513 unsigned char remainder = 0;
5515 /* division underflowed. In order to comply with the MSDN
5516 specifications for DECIMAL ranges, some significant digits
5519 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5521 while (di_result.scale > DEC_MAX_SCALE &&
5522 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
5524 remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
5527 if (di_result.scale > DEC_MAX_SCALE)
5529 WARN("result underflowed, setting to 0\n");
5530 di_result.scale = 0;
5533 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5536 for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
5537 ULONGLONG digit = di_result.bitsnum[i] + 1;
5538 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5539 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5543 VARIANT_DecFromDI(&di_result, pDecOut);
5548 /************************************************************************
5549 * VarDecMul (OLEAUT32.179)
5551 * Multiply one DECIMAL by another.
5554 * pDecLeft [I] Source
5555 * pDecRight [I] Value to multiply by
5556 * pDecOut [O] Destination
5560 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5562 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5564 HRESULT hRet = S_OK;
5565 VARIANT_DI di_left, di_right, di_result;
5568 VARIANT_DIFromDec(pDecLeft, &di_left);
5569 VARIANT_DIFromDec(pDecRight, &di_right);
5570 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5573 /* multiplication actually overflowed */
5574 hRet = DISP_E_OVERFLOW;
5578 if (di_result.scale > DEC_MAX_SCALE)
5580 /* multiplication underflowed. In order to comply with the MSDN
5581 specifications for DECIMAL ranges, some significant digits
5584 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5586 while (di_result.scale > DEC_MAX_SCALE &&
5587 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
5589 VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
5592 if (di_result.scale > DEC_MAX_SCALE)
5594 WARN("result underflowed, setting to 0\n");
5595 di_result.scale = 0;
5599 VARIANT_DecFromDI(&di_result, pDecOut);
5604 /************************************************************************
5605 * VarDecSub (OLEAUT32.181)
5607 * Subtract one DECIMAL from another.
5610 * pDecLeft [I] Source
5611 * pDecRight [I] DECIMAL to subtract from pDecLeft
5612 * pDecOut [O] Destination
5615 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5617 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5621 /* Implement as addition of the negative */
5622 VarDecNeg(pDecRight, &decRight);
5623 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5626 /************************************************************************
5627 * VarDecAbs (OLEAUT32.182)
5629 * Convert a DECIMAL into its absolute value.
5633 * pDecOut [O] Destination
5636 * S_OK. This function does not fail.
5638 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5641 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5645 /************************************************************************
5646 * VarDecFix (OLEAUT32.187)
5648 * Return the integer portion of a DECIMAL.
5652 * pDecOut [O] Destination
5656 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5659 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5660 * negative numbers away from 0, while this function rounds them towards zero.
5662 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5664 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5665 return E_INVALIDARG;
5667 if (!DEC_SCALE(pDecIn))
5669 *pDecOut = *pDecIn; /* Already an integer */
5673 FIXME("semi-stub!\n");
5674 return DISP_E_OVERFLOW;
5677 /************************************************************************
5678 * VarDecInt (OLEAUT32.188)
5680 * Return the integer portion of a DECIMAL.
5684 * pDecOut [O] Destination
5688 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5691 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5692 * negative numbers towards 0, while this function rounds them away from zero.
5694 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5696 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5697 return E_INVALIDARG;
5699 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5700 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5702 FIXME("semi-stub!\n");
5703 return DISP_E_OVERFLOW;
5706 /************************************************************************
5707 * VarDecNeg (OLEAUT32.189)
5709 * Change the sign of a DECIMAL.
5713 * pDecOut [O] Destination
5716 * S_OK. This function does not fail.
5718 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5721 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5725 /************************************************************************
5726 * VarDecRound (OLEAUT32.203)
5728 * Change the precision of a DECIMAL.
5732 * cDecimals [I] New number of decimals to keep
5733 * pDecOut [O] Destination
5736 * Success: S_OK. pDecOut contains the rounded value.
5737 * Failure: E_INVALIDARG if any argument is invalid.
5739 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5741 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5742 return E_INVALIDARG;
5744 if (cDecimals >= DEC_SCALE(pDecIn))
5746 *pDecOut = *pDecIn; /* More precision than we have */
5750 FIXME("semi-stub!\n");
5752 return DISP_E_OVERFLOW;
5755 /************************************************************************
5756 * VarDecCmp (OLEAUT32.204)
5758 * Compare two DECIMAL values.
5761 * pDecLeft [I] Source
5762 * pDecRight [I] Value to compare
5765 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5766 * is less than, equal to or greater than pDecRight respectively.
5767 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5769 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5774 /* Subtract right from left, and compare the result to 0 */
5775 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5777 if (SUCCEEDED(hRet))
5779 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5781 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5782 hRet = (HRESULT)VARCMP_LT;
5784 hRet = (HRESULT)VARCMP_GT;
5786 hRet = (HRESULT)VARCMP_EQ;
5791 /************************************************************************
5792 * VarDecCmpR8 (OLEAUT32.298)
5794 * Compare a DECIMAL to a double
5797 * pDecLeft [I] DECIMAL Source
5798 * dblRight [I] double to compare to pDecLeft
5801 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5802 * is less than, equal to or greater than pDecLeft respectively.
5803 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5805 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5810 hRet = VarDecFromR8(dblRight, &decRight);
5812 if (SUCCEEDED(hRet))
5813 hRet = VarDecCmp(pDecLeft, &decRight);
5821 /************************************************************************
5822 * VarBoolFromUI1 (OLEAUT32.118)
5824 * Convert a VT_UI1 to a VT_BOOL.
5828 * pBoolOut [O] Destination
5833 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5835 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5839 /************************************************************************
5840 * VarBoolFromI2 (OLEAUT32.119)
5842 * Convert a VT_I2 to a VT_BOOL.
5846 * pBoolOut [O] Destination
5851 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5853 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5857 /************************************************************************
5858 * VarBoolFromI4 (OLEAUT32.120)
5860 * Convert a VT_I4 to a VT_BOOL.
5864 * pBoolOut [O] Destination
5869 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
5871 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
5875 /************************************************************************
5876 * VarBoolFromR4 (OLEAUT32.121)
5878 * Convert a VT_R4 to a VT_BOOL.
5882 * pBoolOut [O] Destination
5887 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
5889 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
5893 /************************************************************************
5894 * VarBoolFromR8 (OLEAUT32.122)
5896 * Convert a VT_R8 to a VT_BOOL.
5900 * pBoolOut [O] Destination
5905 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
5907 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
5911 /************************************************************************
5912 * VarBoolFromDate (OLEAUT32.123)
5914 * Convert a VT_DATE to a VT_BOOL.
5918 * pBoolOut [O] Destination
5923 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
5925 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
5929 /************************************************************************
5930 * VarBoolFromCy (OLEAUT32.124)
5932 * Convert a VT_CY to a VT_BOOL.
5936 * pBoolOut [O] Destination
5941 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
5943 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
5947 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
5951 hrsrc = FindResourceExW( OLEAUT32_hModule, (LPWSTR)RT_STRING,
5952 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
5955 HGLOBAL hmem = LoadResource( OLEAUT32_hModule, hrsrc );
5962 p = LockResource( hmem );
5963 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
5965 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
5966 lpszDest[*p] = '\0';
5967 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
5974 /************************************************************************
5975 * VarBoolFromStr (OLEAUT32.125)
5977 * Convert a VT_BSTR to a VT_BOOL.
5981 * lcid [I] LCID for the conversion
5982 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5983 * pBoolOut [O] Destination
5987 * Failure: E_INVALIDARG, if pBoolOut is invalid.
5988 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5991 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
5992 * it may contain (in any case mapping) the text "true" or "false".
5993 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
5994 * localised text of "True" or "False" in the language specified by lcid.
5995 * - If none of these matches occur, the string is treated as a numeric string
5996 * and the boolean pBoolOut will be set according to whether the number is zero
5997 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
5998 * - If the text is not numeric and does not match any of the above, then
5999 * DISP_E_TYPEMISMATCH is returned.
6001 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
6003 /* Any VB/VBA programmers out there should recognise these strings... */
6004 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
6005 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
6007 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6008 HRESULT hRes = S_OK;
6010 if (!strIn || !pBoolOut)
6011 return DISP_E_TYPEMISMATCH;
6013 /* Check if we should be comparing against localised text */
6014 if (dwFlags & VAR_LOCALBOOL)
6016 /* Convert our LCID into a usable value */
6017 lcid = ConvertDefaultLocale(lcid);
6019 langId = LANGIDFROMLCID(lcid);
6021 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6022 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6024 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6025 * I don't think this is needed unless any of the localised text strings
6026 * contain characters that can be so mapped. In the event that this is
6027 * true for a given language (possibly some Asian languages), then strIn
6028 * should be mapped here _only_ if langId is an Id for which this can occur.
6032 /* Note that if we are not comparing against localised strings, langId
6033 * will have its default value of LANG_ENGLISH. This allows us to mimic
6034 * the native behaviour of always checking against English strings even
6035 * after we've checked for localised ones.
6037 VarBoolFromStr_CheckLocalised:
6038 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
6040 /* Compare against localised strings, ignoring case */
6041 if (!strcmpiW(strIn, szBuff))
6043 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
6046 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
6047 if (!strcmpiW(strIn, szBuff))
6049 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
6054 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6056 /* We have checked the localised text, now check English */
6057 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6058 goto VarBoolFromStr_CheckLocalised;
6061 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6062 if (!strcmpW(strIn, szFalse))
6063 *pBoolOut = VARIANT_FALSE;
6064 else if (!strcmpW(strIn, szTrue))
6065 *pBoolOut = VARIANT_TRUE;
6070 /* If this string is a number, convert it as one */
6071 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
6072 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
6077 /************************************************************************
6078 * VarBoolFromDisp (OLEAUT32.126)
6080 * Convert a VT_DISPATCH to a VT_BOOL.
6083 * pdispIn [I] Source
6084 * lcid [I] LCID for conversion
6085 * pBoolOut [O] Destination
6089 * Failure: E_INVALIDARG, if the source value is invalid
6090 * DISP_E_OVERFLOW, if the value will not fit in the destination
6091 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6093 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
6095 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
6098 /************************************************************************
6099 * VarBoolFromI1 (OLEAUT32.233)
6101 * Convert a VT_I1 to a VT_BOOL.
6105 * pBoolOut [O] Destination
6110 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
6112 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
6116 /************************************************************************
6117 * VarBoolFromUI2 (OLEAUT32.234)
6119 * Convert a VT_UI2 to a VT_BOOL.
6123 * pBoolOut [O] Destination
6128 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
6130 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
6134 /************************************************************************
6135 * VarBoolFromUI4 (OLEAUT32.235)
6137 * Convert a VT_UI4 to a VT_BOOL.
6141 * pBoolOut [O] Destination
6146 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
6148 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
6152 /************************************************************************
6153 * VarBoolFromDec (OLEAUT32.236)
6155 * Convert a VT_DECIMAL to a VT_BOOL.
6159 * pBoolOut [O] Destination
6163 * Failure: E_INVALIDARG, if pDecIn is invalid.
6165 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
6167 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
6168 return E_INVALIDARG;
6170 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
6171 *pBoolOut = VARIANT_TRUE;
6173 *pBoolOut = VARIANT_FALSE;
6177 /************************************************************************
6178 * VarBoolFromI8 (OLEAUT32.370)
6180 * Convert a VT_I8 to a VT_BOOL.
6184 * pBoolOut [O] Destination
6189 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
6191 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
6195 /************************************************************************
6196 * VarBoolFromUI8 (OLEAUT32.371)
6198 * Convert a VT_UI8 to a VT_BOOL.
6202 * pBoolOut [O] Destination
6207 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
6209 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
6216 /* Write a number from a UI8 and sign */
6217 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
6221 WCHAR ulNextDigit = ulVal % 10;
6223 *szOut-- = '0' + ulNextDigit;
6224 ulVal = (ulVal - ulNextDigit) / 10;
6231 /* Create a (possibly localised) BSTR from a UI8 and sign */
6232 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
6234 WCHAR szConverted[256];
6236 if (dwFlags & VAR_NEGATIVE)
6239 if (dwFlags & LOCALE_USE_NLS)
6241 /* Format the number for the locale */
6242 szConverted[0] = '\0';
6243 GetNumberFormatW(lcid,
6244 dwFlags & LOCALE_NOUSEROVERRIDE,
6245 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
6246 szOut = szConverted;
6248 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
6251 /* Create a (possibly localised) BSTR from a UI8 and sign */
6252 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
6254 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
6257 return E_INVALIDARG;
6259 /* Create the basic number string */
6261 szOut = VARIANT_WriteNumber(ulVal, szOut);
6263 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
6264 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6265 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6268 /******************************************************************************
6269 * VarBstrFromUI1 (OLEAUT32.108)
6271 * Convert a VT_UI1 to a VT_BSTR.
6275 * lcid [I] LCID for the conversion
6276 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6277 * pbstrOut [O] Destination
6281 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6282 * E_OUTOFMEMORY, if memory allocation fails.
6284 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6286 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6289 /******************************************************************************
6290 * VarBstrFromI2 (OLEAUT32.109)
6292 * Convert a VT_I2 to a VT_BSTR.
6296 * lcid [I] LCID for the conversion
6297 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6298 * pbstrOut [O] Destination
6302 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6303 * E_OUTOFMEMORY, if memory allocation fails.
6305 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6312 dwFlags |= VAR_NEGATIVE;
6314 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6317 /******************************************************************************
6318 * VarBstrFromI4 (OLEAUT32.110)
6320 * Convert a VT_I4 to a VT_BSTR.
6324 * lcid [I] LCID for the conversion
6325 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6326 * pbstrOut [O] Destination
6330 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6331 * E_OUTOFMEMORY, if memory allocation fails.
6333 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6340 dwFlags |= VAR_NEGATIVE;
6342 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6345 static BSTR VARIANT_BstrReplaceDecimal(WCHAR * buff, LCID lcid, ULONG dwFlags)
6348 WCHAR lpDecimalSep[16];
6350 /* Native oleaut32 uses the locale-specific decimal separator even in the
6351 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6352 American locales will see "one thousand and one tenth" as "1000,1"
6353 instead of "1000.1" (notice the comma). The following code checks for
6354 the need to replace the decimal separator, and if so, will prepare an
6355 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6357 GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE),
6358 lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
6359 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6361 /* locale is compatible with English - return original string */
6362 bstrOut = SysAllocString(buff);
6368 WCHAR empty[1] = {'\0'};
6369 NUMBERFMTW minFormat;
6371 minFormat.NumDigits = 0;
6372 minFormat.LeadingZero = 0;
6373 minFormat.Grouping = 0;
6374 minFormat.lpDecimalSep = lpDecimalSep;
6375 minFormat.lpThousandSep = empty;
6376 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6378 /* count number of decimal digits in string */
6379 p = strchrW( buff, '.' );
6380 if (p) minFormat.NumDigits = strlenW(p + 1);
6383 if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
6385 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6386 bstrOut = SysAllocString(buff);
6390 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6391 bstrOut = SysAllocString(numbuff);
6397 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6398 BSTR* pbstrOut, LPCWSTR lpszFormat)
6403 return E_INVALIDARG;
6405 sprintfW( buff, lpszFormat, dblIn );
6407 /* Negative zeroes are disallowed (some applications depend on this).
6408 If buff starts with a minus, and then nothing follows but zeroes
6409 and/or a period, it is a negative zero and is replaced with a
6410 canonical zero. This duplicates native oleaut32 behavior.
6414 const WCHAR szAccept[] = {'0', '.', '\0'};
6415 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
6416 { buff[0] = '0'; buff[1] = '\0'; }
6419 TRACE("created string %s\n", debugstr_w(buff));
6420 if (dwFlags & LOCALE_USE_NLS)
6424 /* Format the number for the locale */
6426 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6427 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6428 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6429 *pbstrOut = SysAllocString(numbuff);
6433 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6435 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6438 /******************************************************************************
6439 * VarBstrFromR4 (OLEAUT32.111)
6441 * Convert a VT_R4 to a VT_BSTR.
6445 * lcid [I] LCID for the conversion
6446 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6447 * pbstrOut [O] Destination
6451 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6452 * E_OUTOFMEMORY, if memory allocation fails.
6454 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6456 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
6459 /******************************************************************************
6460 * VarBstrFromR8 (OLEAUT32.112)
6462 * Convert a VT_R8 to a VT_BSTR.
6466 * lcid [I] LCID for the conversion
6467 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6468 * pbstrOut [O] Destination
6472 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6473 * E_OUTOFMEMORY, if memory allocation fails.
6475 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6477 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
6480 /******************************************************************************
6481 * VarBstrFromCy [OLEAUT32.113]
6483 * Convert a VT_CY to a VT_BSTR.
6487 * lcid [I] LCID for the conversion
6488 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6489 * pbstrOut [O] Destination
6493 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6494 * E_OUTOFMEMORY, if memory allocation fails.
6496 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6502 return E_INVALIDARG;
6506 decVal.bitsnum[0] = cyIn.s.Lo;
6507 decVal.bitsnum[1] = cyIn.s.Hi;
6508 if (cyIn.s.Hi & 0x80000000UL) {
6511 /* Negative number! */
6513 decVal.bitsnum[0] = ~decVal.bitsnum[0];
6514 decVal.bitsnum[1] = ~decVal.bitsnum[1];
6515 VARIANT_int_add(decVal.bitsnum, 3, &one, 1);
6517 decVal.bitsnum[2] = 0;
6518 VARIANT_DI_tostringW(&decVal, buff, sizeof(buff));
6520 if (dwFlags & LOCALE_USE_NLS)
6524 /* Format the currency for the locale */
6526 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6527 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR));
6528 *pbstrOut = SysAllocString(cybuff);
6531 *pbstrOut = SysAllocString(buff);
6533 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6536 /******************************************************************************
6537 * VarBstrFromDate [OLEAUT32.114]
6539 * Convert a VT_DATE to a VT_BSTR.
6543 * lcid [I] LCID for the conversion
6544 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6545 * pbstrOut [O] Destination
6549 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6550 * E_OUTOFMEMORY, if memory allocation fails.
6552 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6555 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6556 WCHAR date[128], *time;
6558 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
6560 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6561 return E_INVALIDARG;
6565 if (dwFlags & VAR_CALENDAR_THAI)
6566 st.wYear += 553; /* Use the Thai buddhist calendar year */
6567 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6568 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6570 if (dwFlags & LOCALE_USE_NLS)
6571 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6574 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6575 double partial = dateIn - whole;
6578 dwFlags |= VAR_TIMEVALUEONLY;
6579 else if (partial < 1e-12)
6580 dwFlags |= VAR_DATEVALUEONLY;
6583 if (dwFlags & VAR_TIMEVALUEONLY)
6586 if (!GetDateFormatW(lcid, dwFormatFlags|DATE_SHORTDATE, &st, NULL, date,
6587 sizeof(date)/sizeof(WCHAR)))
6588 return E_INVALIDARG;
6590 if (!(dwFlags & VAR_DATEVALUEONLY))
6592 time = date + strlenW(date);
6595 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
6596 sizeof(date)/sizeof(WCHAR)-(time-date)))
6597 return E_INVALIDARG;
6600 *pbstrOut = SysAllocString(date);
6602 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6603 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6606 /******************************************************************************
6607 * VarBstrFromBool (OLEAUT32.116)
6609 * Convert a VT_BOOL to a VT_BSTR.
6613 * lcid [I] LCID for the conversion
6614 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6615 * pbstrOut [O] Destination
6619 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6620 * E_OUTOFMEMORY, if memory allocation fails.
6623 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6624 * localised text of "True" or "False". To convert a bool into a
6625 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6627 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6630 DWORD dwResId = IDS_TRUE;
6633 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn, lcid, dwFlags, pbstrOut);
6636 return E_INVALIDARG;
6638 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6639 * for variant formatting */
6640 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6651 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6654 lcid = ConvertDefaultLocale(lcid);
6655 langId = LANGIDFROMLCID(lcid);
6656 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6657 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6659 if (boolIn == VARIANT_FALSE)
6660 dwResId++; /* Use negative form */
6662 VarBstrFromBool_GetLocalised:
6663 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6665 *pbstrOut = SysAllocString(szBuff);
6666 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6669 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6671 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6672 goto VarBstrFromBool_GetLocalised;
6675 /* Should never get here */
6676 WARN("Failed to load bool text!\n");
6677 return E_OUTOFMEMORY;
6680 /******************************************************************************
6681 * VarBstrFromI1 (OLEAUT32.229)
6683 * Convert a VT_I1 to a VT_BSTR.
6687 * lcid [I] LCID for the conversion
6688 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6689 * pbstrOut [O] Destination
6693 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6694 * E_OUTOFMEMORY, if memory allocation fails.
6696 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6703 dwFlags |= VAR_NEGATIVE;
6705 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6708 /******************************************************************************
6709 * VarBstrFromUI2 (OLEAUT32.230)
6711 * Convert a VT_UI2 to a VT_BSTR.
6715 * lcid [I] LCID for the conversion
6716 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6717 * pbstrOut [O] Destination
6721 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6722 * E_OUTOFMEMORY, if memory allocation fails.
6724 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6726 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6729 /******************************************************************************
6730 * VarBstrFromUI4 (OLEAUT32.231)
6732 * Convert a VT_UI4 to a VT_BSTR.
6736 * lcid [I] LCID for the conversion
6737 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6738 * pbstrOut [O] Destination
6742 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6743 * E_OUTOFMEMORY, if memory allocation fails.
6745 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6747 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
6750 /******************************************************************************
6751 * VarBstrFromDec (OLEAUT32.232)
6753 * Convert a VT_DECIMAL to a VT_BSTR.
6757 * lcid [I] LCID for the conversion
6758 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6759 * pbstrOut [O] Destination
6763 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6764 * E_OUTOFMEMORY, if memory allocation fails.
6766 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6772 return E_INVALIDARG;
6774 VARIANT_DIFromDec(pDecIn, &temp);
6775 VARIANT_DI_tostringW(&temp, buff, 256);
6777 if (dwFlags & LOCALE_USE_NLS)
6781 /* Format the number for the locale */
6783 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6784 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6785 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6786 *pbstrOut = SysAllocString(numbuff);
6790 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6793 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6794 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6797 /************************************************************************
6798 * VarBstrFromI8 (OLEAUT32.370)
6800 * Convert a VT_I8 to a VT_BSTR.
6804 * lcid [I] LCID for the conversion
6805 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6806 * pbstrOut [O] Destination
6810 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6811 * E_OUTOFMEMORY, if memory allocation fails.
6813 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6815 ULONG64 ul64 = llIn;
6820 dwFlags |= VAR_NEGATIVE;
6822 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6825 /************************************************************************
6826 * VarBstrFromUI8 (OLEAUT32.371)
6828 * Convert a VT_UI8 to a VT_BSTR.
6832 * lcid [I] LCID for the conversion
6833 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6834 * pbstrOut [O] Destination
6838 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6839 * E_OUTOFMEMORY, if memory allocation fails.
6841 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6843 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
6846 /************************************************************************
6847 * VarBstrFromDisp (OLEAUT32.115)
6849 * Convert a VT_DISPATCH to a BSTR.
6852 * pdispIn [I] Source
6853 * lcid [I] LCID for conversion
6854 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6855 * pbstrOut [O] Destination
6859 * Failure: E_INVALIDARG, if the source value is invalid
6860 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6862 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6864 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
6867 /**********************************************************************
6868 * VarBstrCat (OLEAUT32.313)
6870 * Concatenate two BSTR values.
6873 * pbstrLeft [I] Source
6874 * pbstrRight [I] Value to concatenate
6875 * pbstrOut [O] Destination
6879 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6880 * E_OUTOFMEMORY, if memory allocation fails.
6882 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
6884 unsigned int lenLeft, lenRight;
6887 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
6888 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
6891 return E_INVALIDARG;
6893 lenLeft = pbstrLeft ? SysStringLen(pbstrLeft) : 0;
6894 lenRight = pbstrRight ? SysStringLen(pbstrRight) : 0;
6896 *pbstrOut = SysAllocStringLen(NULL, lenLeft + lenRight);
6898 return E_OUTOFMEMORY;
6900 (*pbstrOut)[0] = '\0';
6903 memcpy(*pbstrOut, pbstrLeft, lenLeft * sizeof(WCHAR));
6906 memcpy(*pbstrOut + lenLeft, pbstrRight, lenRight * sizeof(WCHAR));
6908 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
6912 /**********************************************************************
6913 * VarBstrCmp (OLEAUT32.314)
6915 * Compare two BSTR values.
6918 * pbstrLeft [I] Source
6919 * pbstrRight [I] Value to compare
6920 * lcid [I] LCID for the comparison
6921 * dwFlags [I] Flags to pass directly to CompareStringW().
6924 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
6925 * than, equal to or greater than pbstrRight respectively.
6928 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
6929 * states. A NULL BSTR pointer is equivalent to an empty string.
6930 * If LCID is equal to 0, a byte by byte comparison is performed.
6932 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
6937 TRACE("%s,%s,%d,%08x\n",
6938 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
6939 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
6941 if (!pbstrLeft || !*pbstrLeft)
6943 if (!pbstrRight || !*pbstrRight)
6947 else if (!pbstrRight || !*pbstrRight)
6952 unsigned int lenLeft = SysStringByteLen(pbstrLeft);
6953 unsigned int lenRight = SysStringByteLen(pbstrRight);
6954 ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight));
6959 if (lenLeft < lenRight)
6961 if (lenLeft > lenRight)
6967 hres = CompareStringW(lcid, dwFlags, pbstrLeft, SysStringLen(pbstrLeft),
6968 pbstrRight, SysStringLen(pbstrRight)) - 1;
6969 TRACE("%d\n", hres);
6978 /******************************************************************************
6979 * VarDateFromUI1 (OLEAUT32.88)
6981 * Convert a VT_UI1 to a VT_DATE.
6985 * pdateOut [O] Destination
6990 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
6992 return VarR8FromUI1(bIn, pdateOut);
6995 /******************************************************************************
6996 * VarDateFromI2 (OLEAUT32.89)
6998 * Convert a VT_I2 to a VT_DATE.
7002 * pdateOut [O] Destination
7007 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
7009 return VarR8FromI2(sIn, pdateOut);
7012 /******************************************************************************
7013 * VarDateFromI4 (OLEAUT32.90)
7015 * Convert a VT_I4 to a VT_DATE.
7019 * pdateOut [O] Destination
7024 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
7026 return VarDateFromR8(lIn, pdateOut);
7029 /******************************************************************************
7030 * VarDateFromR4 (OLEAUT32.91)
7032 * Convert a VT_R4 to a VT_DATE.
7036 * pdateOut [O] Destination
7041 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
7043 return VarR8FromR4(fltIn, pdateOut);
7046 /******************************************************************************
7047 * VarDateFromR8 (OLEAUT32.92)
7049 * Convert a VT_R8 to a VT_DATE.
7053 * pdateOut [O] Destination
7058 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
7060 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
7061 *pdateOut = (DATE)dblIn;
7065 /**********************************************************************
7066 * VarDateFromDisp (OLEAUT32.95)
7068 * Convert a VT_DISPATCH to a VT_DATE.
7071 * pdispIn [I] Source
7072 * lcid [I] LCID for conversion
7073 * pdateOut [O] Destination
7077 * Failure: E_INVALIDARG, if the source value is invalid
7078 * DISP_E_OVERFLOW, if the value will not fit in the destination
7079 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7081 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
7083 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
7086 /******************************************************************************
7087 * VarDateFromBool (OLEAUT32.96)
7089 * Convert a VT_BOOL to a VT_DATE.
7093 * pdateOut [O] Destination
7098 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
7100 return VarR8FromBool(boolIn, pdateOut);
7103 /**********************************************************************
7104 * VarDateFromCy (OLEAUT32.93)
7106 * Convert a VT_CY to a VT_DATE.
7110 * pdateOut [O] Destination
7115 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
7117 return VarR8FromCy(cyIn, pdateOut);
7120 /* Date string parsing */
7121 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7122 #define DP_DATESEP 0x02 /* Date separator */
7123 #define DP_MONTH 0x04 /* Month name */
7124 #define DP_AM 0x08 /* AM */
7125 #define DP_PM 0x10 /* PM */
7127 typedef struct tagDATEPARSE
7129 DWORD dwCount; /* Number of fields found so far (maximum 6) */
7130 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
7131 DWORD dwFlags[6]; /* Flags for each field */
7132 DWORD dwValues[6]; /* Value of each field */
7135 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7137 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7139 /* Determine if a day is valid in a given month of a given year */
7140 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
7142 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7144 if (day && month && month < 13)
7146 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
7152 /* Possible orders for 3 numbers making up a date */
7153 #define ORDER_MDY 0x01
7154 #define ORDER_YMD 0x02
7155 #define ORDER_YDM 0x04
7156 #define ORDER_DMY 0x08
7157 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7159 /* Determine a date for a particular locale, from 3 numbers */
7160 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
7161 DWORD offset, SYSTEMTIME *st)
7163 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
7167 v1 = 30; /* Default to (Variant) 0 date part */
7170 goto VARIANT_MakeDate_OK;
7173 v1 = dp->dwValues[offset + 0];
7174 v2 = dp->dwValues[offset + 1];
7175 if (dp->dwCount == 2)
7178 GetSystemTime(¤t);
7182 v3 = dp->dwValues[offset + 2];
7184 TRACE("(%d,%d,%d,%d,%d)\n", v1, v2, v3, iDate, offset);
7186 /* If one number must be a month (Because a month name was given), then only
7187 * consider orders with the month in that position.
7188 * If we took the current year as 'v3', then only allow a year in that position.
7190 if (dp->dwFlags[offset + 0] & DP_MONTH)
7192 dwAllOrders = ORDER_MDY;
7194 else if (dp->dwFlags[offset + 1] & DP_MONTH)
7196 dwAllOrders = ORDER_DMY;
7197 if (dp->dwCount > 2)
7198 dwAllOrders |= ORDER_YMD;
7200 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
7202 dwAllOrders = ORDER_YDM;
7206 dwAllOrders = ORDER_MDY|ORDER_DMY;
7207 if (dp->dwCount > 2)
7208 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
7211 VARIANT_MakeDate_Start:
7212 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders);
7220 /* First: Try the order given by iDate */
7223 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
7224 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
7225 default: dwTry = dwAllOrders & ORDER_YMD; break;
7228 else if (dwCount == 1)
7230 /* Second: Try all the orders compatible with iDate */
7233 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7234 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break;
7235 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7240 /* Finally: Try any remaining orders */
7241 dwTry = dwAllOrders;
7244 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount, dwTry);
7250 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7252 if (dwTry & ORDER_MDY)
7254 if (VARIANT_IsValidMonthDay(v2,v1,v3))
7257 goto VARIANT_MakeDate_OK;
7259 dwAllOrders &= ~ORDER_MDY;
7261 if (dwTry & ORDER_YMD)
7263 if (VARIANT_IsValidMonthDay(v3,v2,v1))
7266 goto VARIANT_MakeDate_OK;
7268 dwAllOrders &= ~ORDER_YMD;
7270 if (dwTry & ORDER_YDM)
7272 if (VARIANT_IsValidMonthDay(v2,v3,v1))
7276 goto VARIANT_MakeDate_OK;
7278 dwAllOrders &= ~ORDER_YDM;
7280 if (dwTry & ORDER_DMY)
7282 if (VARIANT_IsValidMonthDay(v1,v2,v3))
7283 goto VARIANT_MakeDate_OK;
7284 dwAllOrders &= ~ORDER_DMY;
7286 if (dwTry & ORDER_MYD)
7288 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7289 if (VARIANT_IsValidMonthDay(v3,v1,v2))
7293 goto VARIANT_MakeDate_OK;
7295 dwAllOrders &= ~ORDER_MYD;
7299 if (dp->dwCount == 2)
7301 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7302 v3 = 1; /* 1st of the month */
7303 dwAllOrders = ORDER_YMD|ORDER_MYD;
7304 dp->dwCount = 0; /* Don't return to this code path again */
7306 goto VARIANT_MakeDate_Start;
7309 /* No valid dates were able to be constructed */
7310 return DISP_E_TYPEMISMATCH;
7312 VARIANT_MakeDate_OK:
7314 /* Check that the time part is ok */
7315 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
7316 return DISP_E_TYPEMISMATCH;
7318 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7319 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
7321 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
7323 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7327 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7328 * be retrieved from:
7329 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7330 * But Wine doesn't have/use that key as at the time of writing.
7332 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
7333 TRACE("Returning date %d/%d/%d\n", v1, v2, st->wYear);
7337 /******************************************************************************
7338 * VarDateFromStr [OLEAUT32.94]
7340 * Convert a VT_BSTR to at VT_DATE.
7343 * strIn [I] String to convert
7344 * lcid [I] Locale identifier for the conversion
7345 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7346 * pdateOut [O] Destination for the converted value
7349 * Success: S_OK. pdateOut contains the converted value.
7350 * FAILURE: An HRESULT error code indicating the prolem.
7353 * Any date format that can be created using the date formats from lcid
7354 * (Either from kernel Nls functions, variant conversion or formatting) is a
7355 * valid input to this function. In addition, a few more esoteric formats are
7356 * also supported for compatibility with the native version. The date is
7357 * interpreted according to the date settings in the control panel, unless
7358 * the date is invalid in that format, in which the most compatible format
7359 * that produces a valid date will be used.
7361 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7363 static const USHORT ParseDateTokens[] =
7365 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7366 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7367 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7368 LOCALE_SMONTHNAME13,
7369 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7370 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7371 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7372 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7373 LOCALE_SABBREVMONTHNAME13,
7374 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7375 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7376 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7377 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7378 LOCALE_SABBREVDAYNAME7,
7379 LOCALE_S1159, LOCALE_S2359
7381 static const BYTE ParseDateMonths[] =
7383 1,2,3,4,5,6,7,8,9,10,11,12,13,
7384 1,2,3,4,5,6,7,8,9,10,11,12,13
7387 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
7389 DWORD dwDateSeps = 0, iDate = 0;
7390 HRESULT hRet = S_OK;
7392 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7393 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7394 return E_INVALIDARG;
7397 return DISP_E_TYPEMISMATCH;
7401 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7403 memset(&dp, 0, sizeof(dp));
7405 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7406 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7407 TRACE("iDate is %d\n", iDate);
7409 /* Get the month/day/am/pm tokens for this locale */
7410 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7413 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7415 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7416 * GetAltMonthNames(). We should really cache these strings too.
7419 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
7420 tokens[i] = SysAllocString(buff);
7421 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7424 /* Parse the string into our structure */
7427 if (dp.dwCount >= 6)
7430 if (isdigitW(*strIn))
7432 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
7436 else if (isalpha(*strIn))
7438 BOOL bFound = FALSE;
7440 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7442 DWORD dwLen = strlenW(tokens[i]);
7443 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
7447 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7448 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7453 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7454 hRet = DISP_E_TYPEMISMATCH;
7457 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7458 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7461 strIn += (dwLen - 1);
7469 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7470 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7472 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7473 if (*strIn == 'a' || *strIn == 'A')
7475 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7476 dp.dwParseFlags |= DP_AM;
7480 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7481 dp.dwParseFlags |= DP_PM;
7487 TRACE("No matching token for %s\n", debugstr_w(strIn));
7488 hRet = DISP_E_TYPEMISMATCH;
7493 else if (*strIn == ':' || *strIn == '.')
7495 if (!dp.dwCount || !strIn[1])
7496 hRet = DISP_E_TYPEMISMATCH;
7498 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7500 else if (*strIn == '-' || *strIn == '/')
7503 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7504 hRet = DISP_E_TYPEMISMATCH;
7506 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7508 else if (*strIn == ',' || isspaceW(*strIn))
7510 if (*strIn == ',' && !strIn[1])
7511 hRet = DISP_E_TYPEMISMATCH;
7515 hRet = DISP_E_TYPEMISMATCH;
7520 if (!dp.dwCount || dp.dwCount > 6 ||
7521 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7522 hRet = DISP_E_TYPEMISMATCH;
7524 if (SUCCEEDED(hRet))
7527 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7529 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7531 /* Figure out which numbers correspond to which fields.
7533 * This switch statement works based on the fact that native interprets any
7534 * fields that are not joined with a time separator ('.' or ':') as date
7535 * fields. Thus we construct a value from 0-32 where each set bit indicates
7536 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7537 * For valid permutations, we set dwOffset to point to the first date field
7538 * and shorten dp.dwCount by the number of time fields found. The real
7539 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7540 * each date number must represent in the context of iDate.
7542 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7544 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7546 case 0x1: /* TT TTDD TTDDD */
7547 if (dp.dwCount > 3 &&
7548 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7549 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7550 hRet = DISP_E_TYPEMISMATCH;
7551 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7552 hRet = DISP_E_TYPEMISMATCH;
7553 st.wHour = dp.dwValues[0];
7554 st.wMinute = dp.dwValues[1];
7559 case 0x3: /* TTT TTTDD TTTDDD */
7560 if (dp.dwCount > 4 &&
7561 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7562 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7563 hRet = DISP_E_TYPEMISMATCH;
7564 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7565 hRet = DISP_E_TYPEMISMATCH;
7566 st.wHour = dp.dwValues[0];
7567 st.wMinute = dp.dwValues[1];
7568 st.wSecond = dp.dwValues[2];
7573 case 0x4: /* DDTT */
7574 if (dp.dwCount != 4 ||
7575 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7576 hRet = DISP_E_TYPEMISMATCH;
7578 st.wHour = dp.dwValues[2];
7579 st.wMinute = dp.dwValues[3];
7583 case 0x0: /* T DD DDD TDDD TDDD */
7584 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7586 st.wHour = dp.dwValues[0]; /* T */
7590 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7592 hRet = DISP_E_TYPEMISMATCH;
7594 else if (dp.dwCount == 3)
7596 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7599 st.wHour = dp.dwValues[0];
7603 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7606 st.wHour = dp.dwValues[2];
7609 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7610 hRet = DISP_E_TYPEMISMATCH;
7612 else if (dp.dwCount == 4)
7615 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7617 st.wHour = dp.dwValues[0];
7620 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7622 st.wHour = dp.dwValues[3];
7625 hRet = DISP_E_TYPEMISMATCH;
7628 /* .. fall through .. */
7630 case 0x8: /* DDDTT */
7631 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7632 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7633 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7634 dp.dwCount == 4 || dp.dwCount == 6)
7635 hRet = DISP_E_TYPEMISMATCH;
7636 st.wHour = dp.dwValues[3];
7637 st.wMinute = dp.dwValues[4];
7638 if (dp.dwCount == 5)
7642 case 0xC: /* DDTTT */
7643 if (dp.dwCount != 5 ||
7644 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7645 hRet = DISP_E_TYPEMISMATCH;
7646 st.wHour = dp.dwValues[2];
7647 st.wMinute = dp.dwValues[3];
7648 st.wSecond = dp.dwValues[4];
7652 case 0x18: /* DDDTTT */
7653 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7654 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7655 hRet = DISP_E_TYPEMISMATCH;
7656 st.wHour = dp.dwValues[3];
7657 st.wMinute = dp.dwValues[4];
7658 st.wSecond = dp.dwValues[5];
7663 hRet = DISP_E_TYPEMISMATCH;
7667 if (SUCCEEDED(hRet))
7669 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7671 if (dwFlags & VAR_TIMEVALUEONLY)
7677 else if (dwFlags & VAR_DATEVALUEONLY)
7678 st.wHour = st.wMinute = st.wSecond = 0;
7680 /* Finally, convert the value to a VT_DATE */
7681 if (SUCCEEDED(hRet))
7682 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7686 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7687 SysFreeString(tokens[i]);
7691 /******************************************************************************
7692 * VarDateFromI1 (OLEAUT32.221)
7694 * Convert a VT_I1 to a VT_DATE.
7698 * pdateOut [O] Destination
7703 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7705 return VarR8FromI1(cIn, pdateOut);
7708 /******************************************************************************
7709 * VarDateFromUI2 (OLEAUT32.222)
7711 * Convert a VT_UI2 to a VT_DATE.
7715 * pdateOut [O] Destination
7720 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7722 return VarR8FromUI2(uiIn, pdateOut);
7725 /******************************************************************************
7726 * VarDateFromUI4 (OLEAUT32.223)
7728 * Convert a VT_UI4 to a VT_DATE.
7732 * pdateOut [O] Destination
7737 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7739 return VarDateFromR8(ulIn, pdateOut);
7742 /**********************************************************************
7743 * VarDateFromDec (OLEAUT32.224)
7745 * Convert a VT_DECIMAL to a VT_DATE.
7749 * pdateOut [O] Destination
7754 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
7756 return VarR8FromDec(pdecIn, pdateOut);
7759 /******************************************************************************
7760 * VarDateFromI8 (OLEAUT32.364)
7762 * Convert a VT_I8 to a VT_DATE.
7766 * pdateOut [O] Destination
7770 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7772 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
7774 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
7775 *pdateOut = (DATE)llIn;
7779 /******************************************************************************
7780 * VarDateFromUI8 (OLEAUT32.365)
7782 * Convert a VT_UI8 to a VT_DATE.
7786 * pdateOut [O] Destination
7790 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7792 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
7794 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
7795 *pdateOut = (DATE)ullIn;