2 * Low level variant functions
4 * Copyright 2003 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
25 #include "wine/debug.h"
26 #include "wine/unicode.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(variant);
35 extern HMODULE OLEAUT32_hModule;
37 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
38 #define CY_MULTIPLIER_F 10000.0
39 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
40 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
42 static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' };
43 static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' };
45 /* Copy data from one variant to another. */
46 static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
51 case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
54 case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
59 case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
64 case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break;
65 case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break;
66 case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
68 FIXME("VT_ type %d unhandled, please report!\n", vt);
72 /* Macro to inline conversion from a float or double to any integer type,
73 * rounding according to the 'dutch' convention.
75 #define VARIANT_DutchRound(typ, value, res) do { \
76 double whole = value < 0 ? ceil(value) : floor(value); \
77 double fract = value - whole; \
78 if (fract > 0.5) res = (typ)whole + (typ)1; \
79 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
80 else if (fract >= 0.0) res = (typ)whole; \
81 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
82 else if (fract > -0.5) res = (typ)whole; \
83 else res = (typ)whole - (typ)1; \
87 /* Coerce VT_BSTR to a numeric type */
88 static HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
89 void* pOut, VARTYPE vt)
96 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
97 np.cDig = sizeof(rgb) / sizeof(BYTE);
98 np.dwInFlags = NUMPRS_STD;
100 hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
104 /* 1 << vt gives us the VTBIT constant for the destination number type */
105 hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
107 VARIANT_CopyData(&dstVar, vt, pOut);
112 /* Coerce VT_DISPATCH to another type */
113 static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut,
114 VARTYPE vt, DWORD dwFlags)
116 static const DISPPARAMS emptyParams = { NULL, NULL, 0, 0 };
117 VARIANTARG srcVar, dstVar;
121 return DISP_E_BADVARTYPE;
123 /* Get the default 'value' property from the IDispatch */
124 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
125 (DISPPARAMS*)&emptyParams, &srcVar, NULL, NULL);
129 /* Convert the property to the requested type */
130 V_VT(&dstVar) = VT_EMPTY;
131 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt);
132 VariantClear(&srcVar);
136 VARIANT_CopyData(&dstVar, vt, pOut);
137 VariantClear(&srcVar);
141 hRet = DISP_E_TYPEMISMATCH;
145 /* Inline return type */
146 #define RETTYP inline static HRESULT
149 /* Simple compiler cast from one type to another */
150 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
151 *out = in; return S_OK; }
153 /* Compiler cast where input cannot be negative */
154 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
155 if (in < (src)0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
157 /* Compiler cast where input cannot be > some number */
158 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
159 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
161 /* Compiler cast where input cannot be < some number or >= some other number */
162 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
163 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
166 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX);
167 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX);
168 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX);
169 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool);
170 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX);
171 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX);
172 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX);
173 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX);
176 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX);
177 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool);
178 NEGTST(BYTE, signed char, VarUI1FromI1);
179 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX);
180 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX);
181 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX);
182 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX);
183 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX);
186 SIMPLE(SHORT, BYTE, VarI2FromUI1);
187 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX);
188 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool);
189 SIMPLE(SHORT, signed char, VarI2FromI1);
190 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX);
191 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX);
192 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX);
193 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX);
196 SIMPLE(USHORT, BYTE, VarUI2FromUI1);
197 NEGTST(USHORT, SHORT, VarUI2FromI2);
198 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX);
199 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool);
200 NEGTST(USHORT, signed char, VarUI2FromI1);
201 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX);
202 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX);
203 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX);
206 SIMPLE(LONG, BYTE, VarI4FromUI1);
207 SIMPLE(LONG, SHORT, VarI4FromI2);
208 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool);
209 SIMPLE(LONG, signed char, VarI4FromI1);
210 SIMPLE(LONG, USHORT, VarI4FromUI2);
211 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX);
212 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX);
213 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX);
216 SIMPLE(ULONG, BYTE, VarUI4FromUI1);
217 NEGTST(ULONG, SHORT, VarUI4FromI2);
218 NEGTST(ULONG, LONG, VarUI4FromI4);
219 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool);
220 NEGTST(ULONG, signed char, VarUI4FromI1);
221 SIMPLE(ULONG, USHORT, VarUI4FromUI2);
222 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX);
223 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX);
226 SIMPLE(LONG64, BYTE, VarI8FromUI1);
227 SIMPLE(LONG64, SHORT, VarI8FromI2);
228 SIMPLE(LONG64, signed char, VarI8FromI1);
229 SIMPLE(LONG64, USHORT, VarI8FromUI2);
230 SIMPLE(LONG64, LONG, VarI8FromI4);
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 NEGTST(ULONG64, LONG, VarUI8FromI4);
240 SIMPLE(ULONG64, ULONG, VarUI8FromUI4);
241 NEGTST(ULONG64, LONG64, VarUI8FromI8);
244 SIMPLE(float, BYTE, VarR4FromUI1);
245 SIMPLE(float, SHORT, VarR4FromI2);
246 SIMPLE(float, signed char, VarR4FromI1);
247 SIMPLE(float, USHORT, VarR4FromUI2);
248 SIMPLE(float, LONG, VarR4FromI4);
249 SIMPLE(float, ULONG, VarR4FromUI4);
250 SIMPLE(float, LONG64, VarR4FromI8);
251 SIMPLE(float, ULONG64, VarR4FromUI8);
254 SIMPLE(double, BYTE, VarR8FromUI1);
255 SIMPLE(double, SHORT, VarR8FromI2);
256 SIMPLE(double, float, VarR8FromR4);
257 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
258 SIMPLE(double, DATE, VarR8FromDate);
259 SIMPLE(double, signed char, VarR8FromI1);
260 SIMPLE(double, USHORT, VarR8FromUI2);
261 SIMPLE(double, LONG, VarR8FromI4);
262 SIMPLE(double, ULONG, VarR8FromUI4);
263 SIMPLE(double, LONG64, VarR8FromI8);
264 SIMPLE(double, ULONG64, VarR8FromUI8);
270 /************************************************************************
271 * VarI1FromUI1 (OLEAUT32.244)
273 * Convert a VT_UI1 to a VT_I1.
277 * pcOut [O] Destination
281 * Failure: E_INVALIDARG, if the source value is invalid
282 * DISP_E_OVERFLOW, if the value will not fit in the destination
284 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
286 return _VarI1FromUI1(bIn, pcOut);
289 /************************************************************************
290 * VarI1FromI2 (OLEAUT32.245)
292 * Convert a VT_I2 to a VT_I1.
296 * pcOut [O] Destination
300 * Failure: E_INVALIDARG, if the source value is invalid
301 * DISP_E_OVERFLOW, if the value will not fit in the destination
303 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
305 return _VarI1FromI2(sIn, pcOut);
308 /************************************************************************
309 * VarI1FromI4 (OLEAUT32.246)
311 * Convert a VT_I4 to a VT_I1.
315 * pcOut [O] Destination
319 * Failure: E_INVALIDARG, if the source value is invalid
320 * DISP_E_OVERFLOW, if the value will not fit in the destination
322 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
324 return _VarI1FromI4(iIn, pcOut);
327 /************************************************************************
328 * VarI1FromR4 (OLEAUT32.247)
330 * Convert a VT_R4 to a VT_I1.
334 * pcOut [O] Destination
338 * Failure: E_INVALIDARG, if the source value is invalid
339 * DISP_E_OVERFLOW, if the value will not fit in the destination
341 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
343 return VarI1FromR8(fltIn, pcOut);
346 /************************************************************************
347 * VarI1FromR8 (OLEAUT32.248)
349 * Convert a VT_R8 to a VT_I1.
353 * pcOut [O] Destination
357 * Failure: E_INVALIDARG, if the source value is invalid
358 * DISP_E_OVERFLOW, if the value will not fit in the destination
361 * See VarI8FromR8() for details concerning rounding.
363 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
365 if (dblIn < (double)I1_MIN || dblIn > (double)I1_MAX)
366 return DISP_E_OVERFLOW;
367 VARIANT_DutchRound(CHAR, dblIn, *pcOut);
371 /************************************************************************
372 * VarI1FromDate (OLEAUT32.249)
374 * Convert a VT_DATE to a VT_I1.
378 * pcOut [O] Destination
382 * Failure: E_INVALIDARG, if the source value is invalid
383 * DISP_E_OVERFLOW, if the value will not fit in the destination
385 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
387 return VarI1FromR8(dateIn, pcOut);
390 /************************************************************************
391 * VarI1FromCy (OLEAUT32.250)
393 * Convert a VT_CY to a VT_I1.
397 * pcOut [O] Destination
401 * Failure: E_INVALIDARG, if the source value is invalid
402 * DISP_E_OVERFLOW, if the value will not fit in the destination
404 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
408 VarI4FromCy(cyIn, &i);
409 return _VarI1FromI4(i, pcOut);
412 /************************************************************************
413 * VarI1FromStr (OLEAUT32.251)
415 * Convert a VT_BSTR to a VT_I1.
419 * lcid [I] LCID for the conversion
420 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
421 * pcOut [O] Destination
425 * Failure: E_INVALIDARG, if the source value is invalid
426 * DISP_E_OVERFLOW, if the value will not fit in the destination
427 * DISP_E_TYPEMISMATCH, if the type cannot be converted
429 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
431 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
434 /************************************************************************
435 * VarI1FromDisp (OLEAUT32.252)
437 * Convert a VT_DISPATCH to a VT_I1.
441 * lcid [I] LCID for conversion
442 * pcOut [O] Destination
446 * Failure: E_INVALIDARG, if the source value is invalid
447 * DISP_E_OVERFLOW, if the value will not fit in the destination
448 * DISP_E_TYPEMISMATCH, if the type cannot be converted
450 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
452 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0);
455 /************************************************************************
456 * VarI1FromBool (OLEAUT32.253)
458 * Convert a VT_BOOL to a VT_I1.
462 * pcOut [O] Destination
467 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
469 return _VarI1FromBool(boolIn, pcOut);
472 /************************************************************************
473 * VarI1FromUI2 (OLEAUT32.254)
475 * Convert a VT_UI2 to a VT_I1.
479 * pcOut [O] Destination
483 * Failure: E_INVALIDARG, if the source value is invalid
484 * DISP_E_OVERFLOW, if the value will not fit in the destination
486 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
488 return _VarI1FromUI2(usIn, pcOut);
491 /************************************************************************
492 * VarI1FromUI4 (OLEAUT32.255)
494 * Convert a VT_UI4 to a VT_I1.
498 * pcOut [O] Destination
502 * Failure: E_INVALIDARG, if the source value is invalid
503 * DISP_E_OVERFLOW, if the value will not fit in the destination
504 * DISP_E_TYPEMISMATCH, if the type cannot be converted
506 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
508 return _VarI1FromUI4(ulIn, pcOut);
511 /************************************************************************
512 * VarI1FromDec (OLEAUT32.256)
514 * Convert a VT_DECIMAL to a VT_I1.
518 * pcOut [O] Destination
522 * Failure: E_INVALIDARG, if the source value is invalid
523 * DISP_E_OVERFLOW, if the value will not fit in the destination
525 HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut)
530 hRet = VarI8FromDec(pdecIn, &i64);
533 hRet = _VarI1FromI8(i64, pcOut);
537 /************************************************************************
538 * VarI1FromI8 (OLEAUT32.376)
540 * Convert a VT_I8 to a VT_I1.
544 * pcOut [O] Destination
548 * Failure: E_INVALIDARG, if the source value is invalid
549 * DISP_E_OVERFLOW, if the value will not fit in the destination
551 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
553 return _VarI1FromI8(llIn, pcOut);
556 /************************************************************************
557 * VarI1FromUI8 (OLEAUT32.377)
559 * Convert a VT_UI8 to a VT_I1.
563 * pcOut [O] Destination
567 * Failure: E_INVALIDARG, if the source value is invalid
568 * DISP_E_OVERFLOW, if the value will not fit in the destination
570 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
572 return _VarI1FromUI8(ullIn, pcOut);
578 /************************************************************************
579 * VarUI1FromI2 (OLEAUT32.130)
581 * Convert a VT_I2 to a VT_UI1.
585 * pbOut [O] Destination
589 * Failure: E_INVALIDARG, if the source value is invalid
590 * DISP_E_OVERFLOW, if the value will not fit in the destination
592 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
594 return _VarUI1FromI2(sIn, pbOut);
597 /************************************************************************
598 * VarUI1FromI4 (OLEAUT32.131)
600 * Convert a VT_I4 to a VT_UI1.
604 * pbOut [O] Destination
608 * Failure: E_INVALIDARG, if the source value is invalid
609 * DISP_E_OVERFLOW, if the value will not fit in the destination
611 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
613 return _VarUI1FromI4(iIn, pbOut);
616 /************************************************************************
617 * VarUI1FromR4 (OLEAUT32.132)
619 * Convert a VT_R4 to a VT_UI1.
623 * pbOut [O] Destination
627 * Failure: E_INVALIDARG, if the source value is invalid
628 * DISP_E_OVERFLOW, if the value will not fit in the destination
629 * DISP_E_TYPEMISMATCH, if the type cannot be converted
631 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
633 return VarUI1FromR8(fltIn, pbOut);
636 /************************************************************************
637 * VarUI1FromR8 (OLEAUT32.133)
639 * Convert a VT_R8 to a VT_UI1.
643 * pbOut [O] Destination
647 * Failure: E_INVALIDARG, if the source value is invalid
648 * DISP_E_OVERFLOW, if the value will not fit in the destination
651 * See VarI8FromR8() for details concerning rounding.
653 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
655 if (dblIn < -0.5 || dblIn > (double)UI1_MAX)
656 return DISP_E_OVERFLOW;
657 VARIANT_DutchRound(BYTE, dblIn, *pbOut);
661 /************************************************************************
662 * VarUI1FromCy (OLEAUT32.134)
664 * Convert a VT_CY to a VT_UI1.
668 * pbOut [O] Destination
672 * Failure: E_INVALIDARG, if the source value is invalid
673 * DISP_E_OVERFLOW, if the value will not fit in the destination
676 * Negative values >= -5000 will be converted to 0.
678 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
680 ULONG i = UI1_MAX + 1;
682 VarUI4FromCy(cyIn, &i);
683 return _VarUI1FromUI4(i, pbOut);
686 /************************************************************************
687 * VarUI1FromDate (OLEAUT32.135)
689 * Convert a VT_DATE to a VT_UI1.
693 * pbOut [O] Destination
697 * Failure: E_INVALIDARG, if the source value is invalid
698 * DISP_E_OVERFLOW, if the value will not fit in the destination
700 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
702 return VarUI1FromR8(dateIn, pbOut);
705 /************************************************************************
706 * VarUI1FromStr (OLEAUT32.136)
708 * Convert a VT_BSTR to a VT_UI1.
712 * lcid [I] LCID for the conversion
713 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
714 * pbOut [O] Destination
718 * Failure: E_INVALIDARG, if the source value is invalid
719 * DISP_E_OVERFLOW, if the value will not fit in the destination
720 * DISP_E_TYPEMISMATCH, if the type cannot be converted
722 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
724 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
727 /************************************************************************
728 * VarUI1FromDisp (OLEAUT32.137)
730 * Convert a VT_DISPATCH to a VT_UI1.
734 * lcid [I] LCID for conversion
735 * pbOut [O] Destination
739 * Failure: E_INVALIDARG, if the source value is invalid
740 * DISP_E_OVERFLOW, if the value will not fit in the destination
741 * DISP_E_TYPEMISMATCH, if the type cannot be converted
743 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
745 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0);
748 /************************************************************************
749 * VarUI1FromBool (OLEAUT32.138)
751 * Convert a VT_BOOL to a VT_UI1.
755 * pbOut [O] Destination
760 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
762 return _VarUI1FromBool(boolIn, pbOut);
765 /************************************************************************
766 * VarUI1FromI1 (OLEAUT32.237)
768 * Convert a VT_I1 to a VT_UI1.
772 * pbOut [O] Destination
776 * Failure: E_INVALIDARG, if the source value is invalid
777 * DISP_E_OVERFLOW, if the value will not fit in the destination
779 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
781 return _VarUI1FromI1(cIn, pbOut);
784 /************************************************************************
785 * VarUI1FromUI2 (OLEAUT32.238)
787 * Convert a VT_UI2 to a VT_UI1.
791 * pbOut [O] Destination
795 * Failure: E_INVALIDARG, if the source value is invalid
796 * DISP_E_OVERFLOW, if the value will not fit in the destination
798 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
800 return _VarUI1FromUI2(usIn, pbOut);
803 /************************************************************************
804 * VarUI1FromUI4 (OLEAUT32.239)
806 * Convert a VT_UI4 to a VT_UI1.
810 * pbOut [O] Destination
814 * Failure: E_INVALIDARG, if the source value is invalid
815 * DISP_E_OVERFLOW, if the value will not fit in the destination
817 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
819 return _VarUI1FromUI4(ulIn, pbOut);
822 /************************************************************************
823 * VarUI1FromDec (OLEAUT32.240)
825 * Convert a VT_DECIMAL to a VT_UI1.
829 * pbOut [O] Destination
833 * Failure: E_INVALIDARG, if the source value is invalid
834 * DISP_E_OVERFLOW, if the value will not fit in the destination
836 HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut)
841 hRet = VarI8FromDec(pdecIn, &i64);
844 hRet = _VarUI1FromI8(i64, pbOut);
848 /************************************************************************
849 * VarUI1FromI8 (OLEAUT32.372)
851 * Convert a VT_I8 to a VT_UI1.
855 * pbOut [O] Destination
859 * Failure: E_INVALIDARG, if the source value is invalid
860 * DISP_E_OVERFLOW, if the value will not fit in the destination
862 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
864 return _VarUI1FromI8(llIn, pbOut);
867 /************************************************************************
868 * VarUI1FromUI8 (OLEAUT32.373)
870 * Convert a VT_UI8 to a VT_UI1.
874 * pbOut [O] Destination
878 * Failure: E_INVALIDARG, if the source value is invalid
879 * DISP_E_OVERFLOW, if the value will not fit in the destination
881 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
883 return _VarUI1FromUI8(ullIn, pbOut);
890 /************************************************************************
891 * VarI2FromUI1 (OLEAUT32.48)
893 * Convert a VT_UI2 to a VT_I2.
897 * psOut [O] Destination
902 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
904 return _VarI2FromUI1(bIn, psOut);
907 /************************************************************************
908 * VarI2FromI4 (OLEAUT32.49)
910 * Convert a VT_I4 to a VT_I2.
914 * psOut [O] Destination
918 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
920 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
922 return _VarI2FromI4(iIn, psOut);
925 /************************************************************************
926 * VarI2FromR4 (OLEAUT32.50)
928 * Convert a VT_R4 to a VT_I2.
932 * psOut [O] Destination
936 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
938 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
940 return VarI2FromR8(fltIn, psOut);
943 /************************************************************************
944 * VarI2FromR8 (OLEAUT32.51)
946 * Convert a VT_R8 to a VT_I2.
950 * psOut [O] Destination
954 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
957 * See VarI8FromR8() for details concerning rounding.
959 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
961 if (dblIn < (double)I2_MIN || dblIn > (double)I2_MAX)
962 return DISP_E_OVERFLOW;
963 VARIANT_DutchRound(SHORT, dblIn, *psOut);
967 /************************************************************************
968 * VarI2FromCy (OLEAUT32.52)
970 * Convert a VT_CY to a VT_I2.
974 * psOut [O] Destination
978 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
980 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
984 VarI4FromCy(cyIn, &i);
985 return _VarI2FromI4(i, psOut);
988 /************************************************************************
989 * VarI2FromDate (OLEAUT32.53)
991 * Convert a VT_DATE to a VT_I2.
995 * psOut [O] Destination
999 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1001 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
1003 return VarI2FromR8(dateIn, psOut);
1006 /************************************************************************
1007 * VarI2FromStr (OLEAUT32.54)
1009 * Convert a VT_BSTR to a VT_I2.
1013 * lcid [I] LCID for the conversion
1014 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1015 * psOut [O] Destination
1019 * Failure: E_INVALIDARG, if any parameter is invalid
1020 * DISP_E_OVERFLOW, if the value will not fit in the destination
1021 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1023 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
1025 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
1028 /************************************************************************
1029 * VarI2FromDisp (OLEAUT32.55)
1031 * Convert a VT_DISPATCH to a VT_I2.
1034 * pdispIn [I] Source
1035 * lcid [I] LCID for conversion
1036 * psOut [O] Destination
1040 * Failure: E_INVALIDARG, if pdispIn is invalid,
1041 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1042 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1044 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
1046 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0);
1049 /************************************************************************
1050 * VarI2FromBool (OLEAUT32.56)
1052 * Convert a VT_BOOL to a VT_I2.
1056 * psOut [O] Destination
1061 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
1063 return _VarI2FromBool(boolIn, psOut);
1066 /************************************************************************
1067 * VarI2FromI1 (OLEAUT32.205)
1069 * Convert a VT_I1 to a VT_I2.
1073 * psOut [O] Destination
1078 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
1080 return _VarI2FromI1(cIn, psOut);
1083 /************************************************************************
1084 * VarI2FromUI2 (OLEAUT32.206)
1086 * Convert a VT_UI2 to a VT_I2.
1090 * psOut [O] Destination
1094 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1096 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
1098 return _VarI2FromUI2(usIn, psOut);
1101 /************************************************************************
1102 * VarI2FromUI4 (OLEAUT32.207)
1104 * Convert a VT_UI4 to a VT_I2.
1108 * psOut [O] Destination
1112 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1114 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
1116 return _VarI2FromUI4(ulIn, psOut);
1119 /************************************************************************
1120 * VarI2FromDec (OLEAUT32.208)
1122 * Convert a VT_DECIMAL to a VT_I2.
1126 * psOut [O] Destination
1130 * Failure: E_INVALIDARG, if the source value is invalid
1131 * DISP_E_OVERFLOW, if the value will not fit in the destination
1133 HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut)
1138 hRet = VarI8FromDec(pdecIn, &i64);
1140 if (SUCCEEDED(hRet))
1141 hRet = _VarI2FromI8(i64, psOut);
1145 /************************************************************************
1146 * VarI2FromI8 (OLEAUT32.346)
1148 * Convert a VT_I8 to a VT_I2.
1152 * psOut [O] Destination
1156 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1158 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
1160 return _VarI2FromI8(llIn, psOut);
1163 /************************************************************************
1164 * VarI2FromUI8 (OLEAUT32.347)
1166 * Convert a VT_UI8 to a VT_I2.
1170 * psOut [O] Destination
1174 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1176 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
1178 return _VarI2FromUI8(ullIn, psOut);
1184 /************************************************************************
1185 * VarUI2FromUI1 (OLEAUT32.257)
1187 * Convert a VT_UI1 to a VT_UI2.
1191 * pusOut [O] Destination
1196 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
1198 return _VarUI2FromUI1(bIn, pusOut);
1201 /************************************************************************
1202 * VarUI2FromI2 (OLEAUT32.258)
1204 * Convert a VT_I2 to a VT_UI2.
1208 * pusOut [O] Destination
1212 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1214 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
1216 return _VarUI2FromI2(sIn, pusOut);
1219 /************************************************************************
1220 * VarUI2FromI4 (OLEAUT32.259)
1222 * Convert a VT_I4 to a VT_UI2.
1226 * pusOut [O] Destination
1230 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1232 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
1234 return _VarUI2FromI4(iIn, pusOut);
1237 /************************************************************************
1238 * VarUI2FromR4 (OLEAUT32.260)
1240 * Convert a VT_R4 to a VT_UI2.
1244 * pusOut [O] Destination
1248 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1250 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
1252 return VarUI2FromR8(fltIn, pusOut);
1255 /************************************************************************
1256 * VarUI2FromR8 (OLEAUT32.261)
1258 * Convert a VT_R8 to a VT_UI2.
1262 * pusOut [O] Destination
1266 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1269 * See VarI8FromR8() for details concerning rounding.
1271 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
1273 if (dblIn < -0.5 || dblIn > (double)UI2_MAX)
1274 return DISP_E_OVERFLOW;
1275 VARIANT_DutchRound(USHORT, dblIn, *pusOut);
1279 /************************************************************************
1280 * VarUI2FromDate (OLEAUT32.262)
1282 * Convert a VT_DATE to a VT_UI2.
1286 * pusOut [O] Destination
1290 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1292 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
1294 return VarUI2FromR8(dateIn, pusOut);
1297 /************************************************************************
1298 * VarUI2FromCy (OLEAUT32.263)
1300 * Convert a VT_CY to a VT_UI2.
1304 * pusOut [O] Destination
1308 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1311 * Negative values >= -5000 will be converted to 0.
1313 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
1315 ULONG i = UI2_MAX + 1;
1317 VarUI4FromCy(cyIn, &i);
1318 return _VarUI2FromUI4(i, pusOut);
1321 /************************************************************************
1322 * VarUI2FromStr (OLEAUT32.264)
1324 * Convert a VT_BSTR to a VT_UI2.
1328 * lcid [I] LCID for the conversion
1329 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1330 * pusOut [O] Destination
1334 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1335 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1337 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
1339 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
1342 /************************************************************************
1343 * VarUI2FromDisp (OLEAUT32.265)
1345 * Convert a VT_DISPATCH to a VT_UI2.
1348 * pdispIn [I] Source
1349 * lcid [I] LCID for conversion
1350 * pusOut [O] Destination
1354 * Failure: E_INVALIDARG, if the source value is invalid
1355 * DISP_E_OVERFLOW, if the value will not fit in the destination
1356 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1358 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
1360 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0);
1363 /************************************************************************
1364 * VarUI2FromBool (OLEAUT32.266)
1366 * Convert a VT_BOOL to a VT_UI2.
1370 * pusOut [O] Destination
1375 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
1377 return _VarUI2FromBool(boolIn, pusOut);
1380 /************************************************************************
1381 * VarUI2FromI1 (OLEAUT32.267)
1383 * Convert a VT_I1 to a VT_UI2.
1387 * pusOut [O] Destination
1391 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1393 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
1395 return _VarUI2FromI1(cIn, pusOut);
1398 /************************************************************************
1399 * VarUI2FromUI4 (OLEAUT32.268)
1401 * Convert a VT_UI4 to a VT_UI2.
1405 * pusOut [O] Destination
1409 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1411 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
1413 return _VarUI2FromUI4(ulIn, pusOut);
1416 /************************************************************************
1417 * VarUI2FromDec (OLEAUT32.269)
1419 * Convert a VT_DECIMAL to a VT_UI2.
1423 * pusOut [O] Destination
1427 * Failure: E_INVALIDARG, if the source value is invalid
1428 * DISP_E_OVERFLOW, if the value will not fit in the destination
1430 HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut)
1435 hRet = VarI8FromDec(pdecIn, &i64);
1437 if (SUCCEEDED(hRet))
1438 hRet = _VarUI2FromI8(i64, pusOut);
1442 /************************************************************************
1443 * VarUI2FromI8 (OLEAUT32.378)
1445 * Convert a VT_I8 to a VT_UI2.
1449 * pusOut [O] Destination
1453 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1455 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
1457 return _VarUI2FromI8(llIn, pusOut);
1460 /************************************************************************
1461 * VarUI2FromUI8 (OLEAUT32.379)
1463 * Convert a VT_UI8 to a VT_UI2.
1467 * pusOut [O] Destination
1471 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1473 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
1475 return _VarUI2FromUI8(ullIn, pusOut);
1481 /************************************************************************
1482 * VarI4FromUI1 (OLEAUT32.58)
1484 * Convert a VT_UI1 to a VT_I4.
1488 * piOut [O] Destination
1493 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
1495 return _VarI4FromUI1(bIn, piOut);
1498 /************************************************************************
1499 * VarI4FromI2 (OLEAUT32.59)
1501 * Convert a VT_I2 to a VT_I4.
1505 * piOut [O] Destination
1509 * Failure: E_INVALIDARG, if the source value is invalid
1510 * DISP_E_OVERFLOW, if the value will not fit in the destination
1512 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
1514 return _VarI4FromI2(sIn, piOut);
1517 /************************************************************************
1518 * VarI4FromR4 (OLEAUT32.60)
1520 * Convert a VT_R4 to a VT_I4.
1524 * piOut [O] Destination
1528 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1530 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
1532 return VarI4FromR8(fltIn, piOut);
1535 /************************************************************************
1536 * VarI4FromR8 (OLEAUT32.61)
1538 * Convert a VT_R8 to a VT_I4.
1542 * piOut [O] Destination
1546 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1549 * See VarI8FromR8() for details concerning rounding.
1551 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
1553 if (dblIn < (double)I4_MIN || dblIn > (double)I4_MAX)
1554 return DISP_E_OVERFLOW;
1555 VARIANT_DutchRound(LONG, dblIn, *piOut);
1559 /************************************************************************
1560 * VarI4FromCy (OLEAUT32.62)
1562 * Convert a VT_CY to a VT_I4.
1566 * piOut [O] Destination
1570 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1572 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
1574 double d = cyIn.int64 / CY_MULTIPLIER_F;
1575 return VarI4FromR8(d, piOut);
1578 /************************************************************************
1579 * VarI4FromDate (OLEAUT32.63)
1581 * Convert a VT_DATE to a VT_I4.
1585 * piOut [O] Destination
1589 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1591 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
1593 return VarI4FromR8(dateIn, piOut);
1596 /************************************************************************
1597 * VarI4FromStr (OLEAUT32.64)
1599 * Convert a VT_BSTR to a VT_I4.
1603 * lcid [I] LCID for the conversion
1604 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1605 * piOut [O] Destination
1609 * Failure: E_INVALIDARG, if any parameter is invalid
1610 * DISP_E_OVERFLOW, if the value will not fit in the destination
1611 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1613 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
1615 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
1618 /************************************************************************
1619 * VarI4FromDisp (OLEAUT32.65)
1621 * Convert a VT_DISPATCH to a VT_I4.
1624 * pdispIn [I] Source
1625 * lcid [I] LCID for conversion
1626 * piOut [O] Destination
1630 * Failure: E_INVALIDARG, if the source value is invalid
1631 * DISP_E_OVERFLOW, if the value will not fit in the destination
1632 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1634 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
1636 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0);
1639 /************************************************************************
1640 * VarI4FromBool (OLEAUT32.66)
1642 * Convert a VT_BOOL to a VT_I4.
1646 * piOut [O] Destination
1651 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
1653 return _VarI4FromBool(boolIn, piOut);
1656 /************************************************************************
1657 * VarI4FromI1 (OLEAUT32.209)
1659 * Convert a VT_I4 to a VT_I4.
1663 * piOut [O] Destination
1668 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
1670 return _VarI4FromI1(cIn, piOut);
1673 /************************************************************************
1674 * VarI4FromUI2 (OLEAUT32.210)
1676 * Convert a VT_UI2 to a VT_I4.
1680 * piOut [O] Destination
1685 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
1687 return _VarI4FromUI2(usIn, piOut);
1690 /************************************************************************
1691 * VarI4FromUI4 (OLEAUT32.211)
1693 * Convert a VT_UI4 to a VT_I4.
1697 * piOut [O] Destination
1701 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1703 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
1705 return _VarI4FromUI4(ulIn, piOut);
1708 /************************************************************************
1709 * VarI4FromDec (OLEAUT32.212)
1711 * Convert a VT_DECIMAL to a VT_I4.
1715 * piOut [O] Destination
1719 * Failure: E_INVALIDARG, if pdecIn is invalid
1720 * DISP_E_OVERFLOW, if the value will not fit in the destination
1722 HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut)
1727 hRet = VarI8FromDec(pdecIn, &i64);
1729 if (SUCCEEDED(hRet))
1730 hRet = _VarI4FromI8(i64, piOut);
1734 /************************************************************************
1735 * VarI4FromI8 (OLEAUT32.348)
1737 * Convert a VT_I8 to a VT_I4.
1741 * piOut [O] Destination
1745 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1747 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
1749 return _VarI4FromI8(llIn, piOut);
1752 /************************************************************************
1753 * VarI4FromUI8 (OLEAUT32.349)
1755 * Convert a VT_UI8 to a VT_I4.
1759 * piOut [O] Destination
1763 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1765 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
1767 return _VarI4FromUI8(ullIn, piOut);
1773 /************************************************************************
1774 * VarUI4FromUI1 (OLEAUT32.270)
1776 * Convert a VT_UI1 to a VT_UI4.
1780 * pulOut [O] Destination
1785 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
1787 return _VarUI4FromUI1(bIn, pulOut);
1790 /************************************************************************
1791 * VarUI4FromI2 (OLEAUT32.271)
1793 * Convert a VT_I2 to a VT_UI4.
1797 * pulOut [O] Destination
1801 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1803 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
1805 return _VarUI4FromI2(sIn, pulOut);
1808 /************************************************************************
1809 * VarUI4FromI4 (OLEAUT32.272)
1811 * Convert a VT_I4 to a VT_UI4.
1815 * pulOut [O] Destination
1819 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1821 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
1823 return _VarUI4FromI4(iIn, pulOut);
1826 /************************************************************************
1827 * VarUI4FromR4 (OLEAUT32.273)
1829 * Convert a VT_R4 to a VT_UI4.
1833 * pulOut [O] Destination
1837 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1839 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
1841 return VarUI4FromR8(fltIn, pulOut);
1844 /************************************************************************
1845 * VarUI4FromR8 (OLEAUT32.274)
1847 * Convert a VT_R8 to a VT_UI4.
1851 * pulOut [O] Destination
1855 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1858 * See VarI8FromR8() for details concerning rounding.
1860 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
1862 if (dblIn < -0.5 || dblIn > (double)UI4_MAX)
1863 return DISP_E_OVERFLOW;
1864 VARIANT_DutchRound(ULONG, dblIn, *pulOut);
1868 /************************************************************************
1869 * VarUI4FromDate (OLEAUT32.275)
1871 * Convert a VT_DATE to a VT_UI4.
1875 * pulOut [O] Destination
1879 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1881 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
1883 return VarUI4FromR8(dateIn, pulOut);
1886 /************************************************************************
1887 * VarUI4FromCy (OLEAUT32.276)
1889 * Convert a VT_CY to a VT_UI4.
1893 * pulOut [O] Destination
1897 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1899 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
1901 double d = cyIn.int64 / CY_MULTIPLIER_F;
1902 return VarUI4FromR8(d, pulOut);
1905 /************************************************************************
1906 * VarUI4FromStr (OLEAUT32.277)
1908 * Convert a VT_BSTR to a VT_UI4.
1912 * lcid [I] LCID for the conversion
1913 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1914 * pulOut [O] Destination
1918 * Failure: E_INVALIDARG, if any parameter is invalid
1919 * DISP_E_OVERFLOW, if the value will not fit in the destination
1920 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1922 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
1924 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
1927 /************************************************************************
1928 * VarUI4FromDisp (OLEAUT32.278)
1930 * Convert a VT_DISPATCH to a VT_UI4.
1933 * pdispIn [I] Source
1934 * lcid [I] LCID for conversion
1935 * pulOut [O] Destination
1939 * Failure: E_INVALIDARG, if the source value is invalid
1940 * DISP_E_OVERFLOW, if the value will not fit in the destination
1941 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1943 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
1945 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0);
1948 /************************************************************************
1949 * VarUI4FromBool (OLEAUT32.279)
1951 * Convert a VT_BOOL to a VT_UI4.
1955 * pulOut [O] Destination
1960 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
1962 return _VarUI4FromBool(boolIn, pulOut);
1965 /************************************************************************
1966 * VarUI4FromI1 (OLEAUT32.280)
1968 * Convert a VT_I1 to a VT_UI4.
1972 * pulOut [O] Destination
1976 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1978 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
1980 return _VarUI4FromI1(cIn, pulOut);
1983 /************************************************************************
1984 * VarUI4FromUI2 (OLEAUT32.281)
1986 * Convert a VT_UI2 to a VT_UI4.
1990 * pulOut [O] Destination
1995 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
1997 return _VarUI4FromUI2(usIn, pulOut);
2000 /************************************************************************
2001 * VarUI4FromDec (OLEAUT32.282)
2003 * Convert a VT_DECIMAL to a VT_UI4.
2007 * pulOut [O] Destination
2011 * Failure: E_INVALIDARG, if pdecIn is invalid
2012 * DISP_E_OVERFLOW, if the value will not fit in the destination
2014 HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut)
2019 hRet = VarI8FromDec(pdecIn, &i64);
2021 if (SUCCEEDED(hRet))
2022 hRet = _VarUI4FromI8(i64, pulOut);
2026 /************************************************************************
2027 * VarUI4FromI8 (OLEAUT32.425)
2029 * Convert a VT_I8 to a VT_UI4.
2033 * pulOut [O] Destination
2037 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2039 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
2041 return _VarUI4FromI8(llIn, pulOut);
2044 /************************************************************************
2045 * VarUI4FromUI8 (OLEAUT32.426)
2047 * Convert a VT_UI8 to a VT_UI4.
2051 * pulOut [O] Destination
2055 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2057 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
2059 return _VarUI4FromUI8(ullIn, pulOut);
2065 /************************************************************************
2066 * VarI8FromUI1 (OLEAUT32.333)
2068 * Convert a VT_UI1 to a VT_I8.
2072 * pi64Out [O] Destination
2077 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
2079 return _VarI8FromUI1(bIn, pi64Out);
2083 /************************************************************************
2084 * VarI8FromI2 (OLEAUT32.334)
2086 * Convert a VT_I2 to a VT_I8.
2090 * pi64Out [O] Destination
2095 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
2097 return _VarI8FromI2(sIn, pi64Out);
2100 /************************************************************************
2101 * VarI8FromR4 (OLEAUT32.335)
2103 * Convert a VT_R4 to a VT_I8.
2107 * pi64Out [O] Destination
2111 * Failure: E_INVALIDARG, if the source value is invalid
2112 * DISP_E_OVERFLOW, if the value will not fit in the destination
2114 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
2116 return VarI8FromR8(fltIn, pi64Out);
2119 /************************************************************************
2120 * VarI8FromR8 (OLEAUT32.336)
2122 * Convert a VT_R8 to a VT_I8.
2126 * pi64Out [O] Destination
2130 * Failure: E_INVALIDARG, if the source value is invalid
2131 * DISP_E_OVERFLOW, if the value will not fit in the destination
2134 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2135 * very high or low values will not be accurately converted.
2137 * Numbers are rounded using Dutch rounding, as follows:
2139 *| Fractional Part Sign Direction Example
2140 *| --------------- ---- --------- -------
2141 *| < 0.5 + Down 0.4 -> 0.0
2142 *| < 0.5 - Up -0.4 -> 0.0
2143 *| > 0.5 + Up 0.6 -> 1.0
2144 *| < 0.5 - Up -0.6 -> -1.0
2145 *| = 0.5 + Up/Down Down if even, Up if odd
2146 *| = 0.5 - Up/Down Up if even, Down if odd
2148 * This system is often used in supermarkets.
2150 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
2152 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
2153 return DISP_E_OVERFLOW;
2154 VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
2158 /************************************************************************
2159 * VarI8FromCy (OLEAUT32.337)
2161 * Convert a VT_CY to a VT_I8.
2165 * pi64Out [O] Destination
2171 * All negative numbers are rounded down by 1, including those that are
2172 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2173 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2176 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
2178 *pi64Out = cyIn.int64 / CY_MULTIPLIER;
2181 (*pi64Out)--; /* Mimic Win32 bug */
2184 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2186 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1)))
2192 /************************************************************************
2193 * VarI8FromDate (OLEAUT32.338)
2195 * Convert a VT_DATE to a VT_I8.
2199 * pi64Out [O] Destination
2203 * Failure: E_INVALIDARG, if the source value is invalid
2204 * DISP_E_OVERFLOW, if the value will not fit in the destination
2205 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2207 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
2209 return VarI8FromR8(dateIn, pi64Out);
2212 /************************************************************************
2213 * VarI8FromStr (OLEAUT32.339)
2215 * Convert a VT_BSTR to a VT_I8.
2219 * lcid [I] LCID for the conversion
2220 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2221 * pi64Out [O] Destination
2225 * Failure: E_INVALIDARG, if the source value is invalid
2226 * DISP_E_OVERFLOW, if the value will not fit in the destination
2227 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2229 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
2231 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
2234 /************************************************************************
2235 * VarI8FromDisp (OLEAUT32.340)
2237 * Convert a VT_DISPATCH to a VT_I8.
2240 * pdispIn [I] Source
2241 * lcid [I] LCID for conversion
2242 * pi64Out [O] Destination
2246 * Failure: E_INVALIDARG, if the source value is invalid
2247 * DISP_E_OVERFLOW, if the value will not fit in the destination
2248 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2250 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
2252 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0);
2255 /************************************************************************
2256 * VarI8FromBool (OLEAUT32.341)
2258 * Convert a VT_BOOL to a VT_I8.
2262 * pi64Out [O] Destination
2267 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
2269 return VarI8FromI2(boolIn, pi64Out);
2272 /************************************************************************
2273 * VarI8FromI1 (OLEAUT32.342)
2275 * Convert a VT_I1 to a VT_I8.
2279 * pi64Out [O] Destination
2284 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
2286 return _VarI8FromI1(cIn, pi64Out);
2289 /************************************************************************
2290 * VarI8FromUI2 (OLEAUT32.343)
2292 * Convert a VT_UI2 to a VT_I8.
2296 * pi64Out [O] Destination
2301 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
2303 return _VarI8FromUI2(usIn, pi64Out);
2306 /************************************************************************
2307 * VarI8FromUI4 (OLEAUT32.344)
2309 * Convert a VT_UI4 to a VT_I8.
2313 * pi64Out [O] Destination
2318 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
2320 return _VarI8FromUI4(ulIn, pi64Out);
2323 /************************************************************************
2324 * VarI8FromDec (OLEAUT32.345)
2326 * Convert a VT_DECIMAL to a VT_I8.
2330 * pi64Out [O] Destination
2334 * Failure: E_INVALIDARG, if the source value is invalid
2335 * DISP_E_OVERFLOW, if the value will not fit in the destination
2337 HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out)
2339 if (!DEC_SCALE(pdecIn))
2341 /* This decimal is just a 96 bit integer */
2342 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2343 return E_INVALIDARG;
2345 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000)
2346 return DISP_E_OVERFLOW;
2348 if (DEC_SIGN(pdecIn))
2349 *pi64Out = -DEC_LO64(pdecIn);
2351 *pi64Out = DEC_LO64(pdecIn);
2356 /* Decimal contains a floating point number */
2360 hRet = VarR8FromDec(pdecIn, &dbl);
2361 if (SUCCEEDED(hRet))
2362 hRet = VarI8FromR8(dbl, pi64Out);
2367 /************************************************************************
2368 * VarI8FromUI8 (OLEAUT32.427)
2370 * Convert a VT_UI8 to a VT_I8.
2374 * pi64Out [O] Destination
2378 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2380 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
2382 return _VarI8FromUI8(ullIn, pi64Out);
2388 /************************************************************************
2389 * VarUI8FromI8 (OLEAUT32.428)
2391 * Convert a VT_I8 to a VT_UI8.
2395 * pui64Out [O] Destination
2399 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2401 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
2403 return _VarUI8FromI8(llIn, pui64Out);
2406 /************************************************************************
2407 * VarUI8FromUI1 (OLEAUT32.429)
2409 * Convert a VT_UI1 to a VT_UI8.
2413 * pui64Out [O] Destination
2418 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
2420 return _VarUI8FromUI1(bIn, pui64Out);
2423 /************************************************************************
2424 * VarUI8FromI2 (OLEAUT32.430)
2426 * Convert a VT_I2 to a VT_UI8.
2430 * pui64Out [O] Destination
2435 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
2437 return _VarUI8FromI2(sIn, pui64Out);
2440 /************************************************************************
2441 * VarUI8FromR4 (OLEAUT32.431)
2443 * Convert a VT_R4 to a VT_UI8.
2447 * pui64Out [O] Destination
2451 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2453 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
2455 return VarUI8FromR8(fltIn, pui64Out);
2458 /************************************************************************
2459 * VarUI8FromR8 (OLEAUT32.432)
2461 * Convert a VT_R8 to a VT_UI8.
2465 * pui64Out [O] Destination
2469 * Failure: E_INVALIDARG, if the source value is invalid
2470 * DISP_E_OVERFLOW, if the value will not fit in the destination
2473 * See VarI8FromR8() for details concerning rounding.
2475 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
2477 if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
2478 return DISP_E_OVERFLOW;
2479 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
2483 /************************************************************************
2484 * VarUI8FromCy (OLEAUT32.433)
2486 * Convert a VT_CY to a VT_UI8.
2490 * pui64Out [O] Destination
2494 * Failure: E_INVALIDARG, if the source value is invalid
2495 * DISP_E_OVERFLOW, if the value will not fit in the destination
2498 * Negative values >= -5000 will be converted to 0.
2500 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
2504 if (cyIn.int64 < -CY_HALF)
2505 return DISP_E_OVERFLOW;
2510 *pui64Out = cyIn.int64 / CY_MULTIPLIER;
2512 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2514 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1)))
2520 /************************************************************************
2521 * VarUI8FromDate (OLEAUT32.434)
2523 * Convert a VT_DATE to a VT_UI8.
2527 * pui64Out [O] Destination
2531 * Failure: E_INVALIDARG, if the source value is invalid
2532 * DISP_E_OVERFLOW, if the value will not fit in the destination
2533 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2535 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
2537 return VarUI8FromR8(dateIn, pui64Out);
2540 /************************************************************************
2541 * VarUI8FromStr (OLEAUT32.435)
2543 * Convert a VT_BSTR to a VT_UI8.
2547 * lcid [I] LCID for the conversion
2548 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2549 * pui64Out [O] Destination
2553 * Failure: E_INVALIDARG, if the source value is invalid
2554 * DISP_E_OVERFLOW, if the value will not fit in the destination
2555 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2557 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
2559 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
2562 /************************************************************************
2563 * VarUI8FromDisp (OLEAUT32.436)
2565 * Convert a VT_DISPATCH to a VT_UI8.
2568 * pdispIn [I] Source
2569 * lcid [I] LCID for conversion
2570 * pui64Out [O] Destination
2574 * Failure: E_INVALIDARG, if the source value is invalid
2575 * DISP_E_OVERFLOW, if the value will not fit in the destination
2576 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2578 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
2580 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0);
2583 /************************************************************************
2584 * VarUI8FromBool (OLEAUT32.437)
2586 * Convert a VT_BOOL to a VT_UI8.
2590 * pui64Out [O] Destination
2594 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2596 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
2598 return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
2600 /************************************************************************
2601 * VarUI8FromI1 (OLEAUT32.438)
2603 * Convert a VT_I1 to a VT_UI8.
2607 * pui64Out [O] Destination
2611 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2613 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
2615 return _VarUI8FromI1(cIn, pui64Out);
2618 /************************************************************************
2619 * VarUI8FromUI2 (OLEAUT32.439)
2621 * Convert a VT_UI2 to a VT_UI8.
2625 * pui64Out [O] Destination
2630 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
2632 return _VarUI8FromUI2(usIn, pui64Out);
2635 /************************************************************************
2636 * VarUI8FromUI4 (OLEAUT32.440)
2638 * Convert a VT_UI4 to a VT_UI8.
2642 * pui64Out [O] Destination
2647 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
2649 return _VarUI8FromUI4(ulIn, pui64Out);
2652 /************************************************************************
2653 * VarUI8FromDec (OLEAUT32.441)
2655 * Convert a VT_DECIMAL to a VT_UI8.
2659 * pui64Out [O] Destination
2663 * Failure: E_INVALIDARG, if the source value is invalid
2664 * DISP_E_OVERFLOW, if the value will not fit in the destination
2667 * Under native Win32, if the source value has a scale of 0, its sign is
2668 * ignored, i.e. this function takes the absolute value rather than fail
2669 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2670 * (use VarAbs() on pDecIn first if you really want this behaviour).
2672 HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out)
2674 if (!DEC_SCALE(pdecIn))
2676 /* This decimal is just a 96 bit integer */
2677 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2678 return E_INVALIDARG;
2680 if (DEC_HI32(pdecIn))
2681 return DISP_E_OVERFLOW;
2683 if (DEC_SIGN(pdecIn))
2685 WARN("Sign would be ignored under Win32!\n");
2686 return DISP_E_OVERFLOW;
2689 *pui64Out = DEC_LO64(pdecIn);
2694 /* Decimal contains a floating point number */
2698 hRet = VarR8FromDec(pdecIn, &dbl);
2699 if (SUCCEEDED(hRet))
2700 hRet = VarUI8FromR8(dbl, pui64Out);
2708 /************************************************************************
2709 * VarR4FromUI1 (OLEAUT32.68)
2711 * Convert a VT_UI1 to a VT_R4.
2715 * pFltOut [O] Destination
2720 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
2722 return _VarR4FromUI1(bIn, pFltOut);
2725 /************************************************************************
2726 * VarR4FromI2 (OLEAUT32.69)
2728 * Convert a VT_I2 to a VT_R4.
2732 * pFltOut [O] Destination
2737 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
2739 return _VarR4FromI2(sIn, pFltOut);
2742 /************************************************************************
2743 * VarR4FromI4 (OLEAUT32.70)
2745 * Convert a VT_I4 to a VT_R4.
2749 * pFltOut [O] Destination
2754 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
2756 return _VarR4FromI4(lIn, pFltOut);
2759 /************************************************************************
2760 * VarR4FromR8 (OLEAUT32.71)
2762 * Convert a VT_R8 to a VT_R4.
2766 * pFltOut [O] Destination
2770 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2772 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
2774 double d = dblIn < 0.0 ? -dblIn : dblIn;
2775 if (d > R4_MAX) return DISP_E_OVERFLOW;
2780 /************************************************************************
2781 * VarR4FromCy (OLEAUT32.72)
2783 * Convert a VT_CY to a VT_R4.
2787 * pFltOut [O] Destination
2792 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
2794 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
2798 /************************************************************************
2799 * VarR4FromDate (OLEAUT32.73)
2801 * Convert a VT_DATE to a VT_R4.
2805 * pFltOut [O] Destination
2809 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2811 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
2813 return VarR4FromR8(dateIn, pFltOut);
2816 /************************************************************************
2817 * VarR4FromStr (OLEAUT32.74)
2819 * Convert a VT_BSTR to a VT_R4.
2823 * lcid [I] LCID for the conversion
2824 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2825 * pFltOut [O] Destination
2829 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2830 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2832 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
2834 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
2837 /************************************************************************
2838 * VarR4FromDisp (OLEAUT32.75)
2840 * Convert a VT_DISPATCH to a VT_R4.
2843 * pdispIn [I] Source
2844 * lcid [I] LCID for conversion
2845 * pFltOut [O] Destination
2849 * Failure: E_INVALIDARG, if the source value is invalid
2850 * DISP_E_OVERFLOW, if the value will not fit in the destination
2851 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2853 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
2855 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0);
2858 /************************************************************************
2859 * VarR4FromBool (OLEAUT32.76)
2861 * Convert a VT_BOOL to a VT_R4.
2865 * pFltOut [O] Destination
2870 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2872 return VarR4FromI2(boolIn, pFltOut);
2875 /************************************************************************
2876 * VarR4FromI1 (OLEAUT32.213)
2878 * Convert a VT_I1 to a VT_R4.
2882 * pFltOut [O] Destination
2886 * Failure: E_INVALIDARG, if the source value is invalid
2887 * DISP_E_OVERFLOW, if the value will not fit in the destination
2888 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2890 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2892 return _VarR4FromI1(cIn, pFltOut);
2895 /************************************************************************
2896 * VarR4FromUI2 (OLEAUT32.214)
2898 * Convert a VT_UI2 to a VT_R4.
2902 * pFltOut [O] Destination
2906 * Failure: E_INVALIDARG, if the source value is invalid
2907 * DISP_E_OVERFLOW, if the value will not fit in the destination
2908 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2910 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2912 return _VarR4FromUI2(usIn, pFltOut);
2915 /************************************************************************
2916 * VarR4FromUI4 (OLEAUT32.215)
2918 * Convert a VT_UI4 to a VT_R4.
2922 * pFltOut [O] Destination
2926 * Failure: E_INVALIDARG, if the source value is invalid
2927 * DISP_E_OVERFLOW, if the value will not fit in the destination
2928 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2930 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2932 return _VarR4FromUI4(ulIn, pFltOut);
2935 /************************************************************************
2936 * VarR4FromDec (OLEAUT32.216)
2938 * Convert a VT_DECIMAL to a VT_R4.
2942 * pFltOut [O] Destination
2946 * Failure: E_INVALIDARG, if the source value is invalid.
2948 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
2950 BYTE scale = DEC_SCALE(pDecIn);
2954 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2955 return E_INVALIDARG;
2960 if (DEC_SIGN(pDecIn))
2963 if (DEC_HI32(pDecIn))
2965 highPart = (double)DEC_HI32(pDecIn) / (double)divisor;
2966 highPart *= 4294967296.0F;
2967 highPart *= 4294967296.0F;
2972 *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart;
2976 /************************************************************************
2977 * VarR4FromI8 (OLEAUT32.360)
2979 * Convert a VT_I8 to a VT_R4.
2983 * pFltOut [O] Destination
2988 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2990 return _VarR4FromI8(llIn, pFltOut);
2993 /************************************************************************
2994 * VarR4FromUI8 (OLEAUT32.361)
2996 * Convert a VT_UI8 to a VT_R4.
3000 * pFltOut [O] Destination
3005 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
3007 return _VarR4FromUI8(ullIn, pFltOut);
3010 /************************************************************************
3011 * VarR4CmpR8 (OLEAUT32.316)
3013 * Compare a VT_R4 to a VT_R8.
3016 * fltLeft [I] Source
3017 * dblRight [I] Value to compare
3020 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3021 * equal to or greater than dblRight respectively.
3023 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3025 if (fltLeft < dblRight)
3027 else if (fltLeft > dblRight)
3035 /************************************************************************
3036 * VarR8FromUI1 (OLEAUT32.78)
3038 * Convert a VT_UI1 to a VT_R8.
3042 * pDblOut [O] Destination
3047 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3049 return _VarR8FromUI1(bIn, pDblOut);
3052 /************************************************************************
3053 * VarR8FromI2 (OLEAUT32.79)
3055 * Convert a VT_I2 to a VT_R8.
3059 * pDblOut [O] Destination
3064 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3066 return _VarR8FromI2(sIn, pDblOut);
3069 /************************************************************************
3070 * VarR8FromI4 (OLEAUT32.80)
3072 * Convert a VT_I4 to a VT_R8.
3076 * pDblOut [O] Destination
3081 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3083 return _VarR8FromI4(lIn, pDblOut);
3086 /************************************************************************
3087 * VarR8FromR4 (OLEAUT32.81)
3089 * Convert a VT_R4 to a VT_R8.
3093 * pDblOut [O] Destination
3098 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3100 return _VarR8FromR4(fltIn, pDblOut);
3103 /************************************************************************
3104 * VarR8FromCy (OLEAUT32.82)
3106 * Convert a VT_CY to a VT_R8.
3110 * pDblOut [O] Destination
3115 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3117 return _VarR8FromCy(cyIn, pDblOut);
3120 /************************************************************************
3121 * VarR8FromDate (OLEAUT32.83)
3123 * Convert a VT_DATE to a VT_R8.
3127 * pDblOut [O] Destination
3132 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3134 return _VarR8FromDate(dateIn, pDblOut);
3137 /************************************************************************
3138 * VarR8FromStr (OLEAUT32.84)
3140 * Convert a VT_BSTR to a VT_R8.
3144 * lcid [I] LCID for the conversion
3145 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3146 * pDblOut [O] Destination
3150 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3151 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3153 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3155 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3158 /************************************************************************
3159 * VarR8FromDisp (OLEAUT32.85)
3161 * Convert a VT_DISPATCH to a VT_R8.
3164 * pdispIn [I] Source
3165 * lcid [I] LCID for conversion
3166 * pDblOut [O] Destination
3170 * Failure: E_INVALIDARG, if the source value is invalid
3171 * DISP_E_OVERFLOW, if the value will not fit in the destination
3172 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3174 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3176 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0);
3179 /************************************************************************
3180 * VarR8FromBool (OLEAUT32.86)
3182 * Convert a VT_BOOL to a VT_R8.
3186 * pDblOut [O] Destination
3191 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3193 return VarR8FromI2(boolIn, pDblOut);
3196 /************************************************************************
3197 * VarR8FromI1 (OLEAUT32.217)
3199 * Convert a VT_I1 to a VT_R8.
3203 * pDblOut [O] Destination
3207 * Failure: E_INVALIDARG, if the source value is invalid
3208 * DISP_E_OVERFLOW, if the value will not fit in the destination
3209 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3211 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3213 return _VarR8FromI1(cIn, pDblOut);
3216 /************************************************************************
3217 * VarR8FromUI2 (OLEAUT32.218)
3219 * Convert a VT_UI2 to a VT_R8.
3223 * pDblOut [O] Destination
3227 * Failure: E_INVALIDARG, if the source value is invalid
3228 * DISP_E_OVERFLOW, if the value will not fit in the destination
3229 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3231 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3233 return _VarR8FromUI2(usIn, pDblOut);
3236 /************************************************************************
3237 * VarR8FromUI4 (OLEAUT32.219)
3239 * Convert a VT_UI4 to a VT_R8.
3243 * pDblOut [O] Destination
3247 * Failure: E_INVALIDARG, if the source value is invalid
3248 * DISP_E_OVERFLOW, if the value will not fit in the destination
3249 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3251 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3253 return _VarR8FromUI4(ulIn, pDblOut);
3256 /************************************************************************
3257 * VarR8FromDec (OLEAUT32.220)
3259 * Convert a VT_DECIMAL to a VT_R8.
3263 * pDblOut [O] Destination
3267 * Failure: E_INVALIDARG, if the source value is invalid.
3269 HRESULT WINAPI VarR8FromDec(DECIMAL* pDecIn, double *pDblOut)
3271 BYTE scale = DEC_SCALE(pDecIn);
3272 double divisor = 1.0, highPart;
3274 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3275 return E_INVALIDARG;
3280 if (DEC_SIGN(pDecIn))
3283 if (DEC_HI32(pDecIn))
3285 highPart = (double)DEC_HI32(pDecIn) / divisor;
3286 highPart *= 4294967296.0F;
3287 highPart *= 4294967296.0F;
3292 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3296 /************************************************************************
3297 * VarR8FromI8 (OLEAUT32.362)
3299 * Convert a VT_I8 to a VT_R8.
3303 * pDblOut [O] Destination
3308 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3310 return _VarR8FromI8(llIn, pDblOut);
3313 /************************************************************************
3314 * VarR8FromUI8 (OLEAUT32.363)
3316 * Convert a VT_UI8 to a VT_R8.
3320 * pDblOut [O] Destination
3325 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3327 return _VarR8FromUI8(ullIn, pDblOut);
3330 /************************************************************************
3331 * VarR8Pow (OLEAUT32.315)
3333 * Raise a VT_R8 to a power.
3336 * dblLeft [I] Source
3337 * dblPow [I] Power to raise dblLeft by
3338 * pDblOut [O] Destination
3341 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3343 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3345 *pDblOut = pow(dblLeft, dblPow);
3349 /************************************************************************
3350 * VarR8Round (OLEAUT32.317)
3352 * Round a VT_R8 to a given number of decimal points.
3356 * nDig [I] Number of decimal points to round to
3357 * pDblOut [O] Destination for rounded number
3360 * Success: S_OK. pDblOut is rounded to nDig digits.
3361 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3364 * The native version of this function rounds using the internal
3365 * binary representation of the number. Wine uses the dutch rounding
3366 * convention, so therefore small differences can occur in the value returned.
3367 * MSDN says that you should use your own rounding function if you want
3368 * rounding to be predictable in your application.
3370 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3372 double scale, whole, fract;
3375 return E_INVALIDARG;
3377 scale = pow(10.0, nDig);
3380 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3381 fract = dblIn - whole;
3384 dblIn = whole + 1.0;
3385 else if (fract == 0.5)
3386 dblIn = whole + fmod(whole, 2.0);
3387 else if (fract >= 0.0)
3389 else if (fract == -0.5)
3390 dblIn = whole - fmod(whole, 2.0);
3391 else if (fract > -0.5)
3394 dblIn = whole - 1.0;
3396 *pDblOut = dblIn / scale;
3403 /* Powers of 10 from 0..4 D.P. */
3404 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3405 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3407 /************************************************************************
3408 * VarCyFromUI1 (OLEAUT32.98)
3410 * Convert a VT_UI1 to a VT_CY.
3414 * pCyOut [O] Destination
3418 * Failure: E_INVALIDARG, if the source value is invalid
3419 * DISP_E_OVERFLOW, if the value will not fit in the destination
3420 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3422 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3424 return VarCyFromR8(bIn, pCyOut);
3427 /************************************************************************
3428 * VarCyFromI2 (OLEAUT32.99)
3430 * Convert a VT_I2 to a VT_CY.
3434 * pCyOut [O] Destination
3438 * Failure: E_INVALIDARG, if the source value is invalid
3439 * DISP_E_OVERFLOW, if the value will not fit in the destination
3440 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3442 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3444 return VarCyFromR8(sIn, pCyOut);
3447 /************************************************************************
3448 * VarCyFromI4 (OLEAUT32.100)
3450 * Convert a VT_I4 to a VT_CY.
3454 * pCyOut [O] Destination
3458 * Failure: E_INVALIDARG, if the source value is invalid
3459 * DISP_E_OVERFLOW, if the value will not fit in the destination
3460 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3462 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3464 return VarCyFromR8(lIn, pCyOut);
3467 /************************************************************************
3468 * VarCyFromR4 (OLEAUT32.101)
3470 * Convert a VT_R4 to a VT_CY.
3474 * pCyOut [O] Destination
3478 * Failure: E_INVALIDARG, if the source value is invalid
3479 * DISP_E_OVERFLOW, if the value will not fit in the destination
3480 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3482 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3484 return VarCyFromR8(fltIn, pCyOut);
3487 /************************************************************************
3488 * VarCyFromR8 (OLEAUT32.102)
3490 * Convert a VT_R8 to a VT_CY.
3494 * pCyOut [O] Destination
3498 * Failure: E_INVALIDARG, if the source value is invalid
3499 * DISP_E_OVERFLOW, if the value will not fit in the destination
3500 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3502 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3504 #if defined(__GNUC__) && defined(__i386__)
3505 /* This code gives identical results to Win32 on Intel.
3506 * Here we use fp exceptions to catch overflows when storing the value.
3508 static const unsigned short r8_fpcontrol = 0x137f;
3509 static const double r8_multiplier = CY_MULTIPLIER_F;
3510 unsigned short old_fpcontrol, result_fpstatus;
3512 /* Clear exceptions, save the old fp state and load the new state */
3513 __asm__ __volatile__( "fnclex" );
3514 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3515 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3516 /* Perform the conversion. */
3517 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3518 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3519 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3520 /* Save the resulting fp state, load the old state and clear exceptions */
3521 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3522 __asm__ __volatile__( "fnclex" );
3523 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3525 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3526 return DISP_E_OVERFLOW;
3529 /* This version produces slightly different results for boundary cases */
3530 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3531 return DISP_E_OVERFLOW;
3532 dblIn *= CY_MULTIPLIER_F;
3533 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3538 /************************************************************************
3539 * VarCyFromDate (OLEAUT32.103)
3541 * Convert a VT_DATE to a VT_CY.
3545 * pCyOut [O] Destination
3549 * Failure: E_INVALIDARG, if the source value is invalid
3550 * DISP_E_OVERFLOW, if the value will not fit in the destination
3551 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3553 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3555 return VarCyFromR8(dateIn, pCyOut);
3558 /************************************************************************
3559 * VarCyFromStr (OLEAUT32.104)
3561 * Convert a VT_BSTR to a VT_CY.
3565 * lcid [I] LCID for the conversion
3566 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3567 * pCyOut [O] Destination
3571 * Failure: E_INVALIDARG, if the source value is invalid
3572 * DISP_E_OVERFLOW, if the value will not fit in the destination
3573 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3575 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3577 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3580 /************************************************************************
3581 * VarCyFromDisp (OLEAUT32.105)
3583 * Convert a VT_DISPATCH to a VT_CY.
3586 * pdispIn [I] Source
3587 * lcid [I] LCID for conversion
3588 * pCyOut [O] Destination
3592 * Failure: E_INVALIDARG, if the source value is invalid
3593 * DISP_E_OVERFLOW, if the value will not fit in the destination
3594 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3596 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3598 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0);
3601 /************************************************************************
3602 * VarCyFromBool (OLEAUT32.106)
3604 * Convert a VT_BOOL to a VT_CY.
3608 * pCyOut [O] Destination
3612 * Failure: E_INVALIDARG, if the source value is invalid
3613 * DISP_E_OVERFLOW, if the value will not fit in the destination
3614 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3617 * While the sign of the boolean is stored in the currency, the value is
3618 * converted to either 0 or 1.
3620 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3622 return VarCyFromR8(boolIn, pCyOut);
3625 /************************************************************************
3626 * VarCyFromI1 (OLEAUT32.225)
3628 * Convert a VT_I1 to a VT_CY.
3632 * pCyOut [O] Destination
3636 * Failure: E_INVALIDARG, if the source value is invalid
3637 * DISP_E_OVERFLOW, if the value will not fit in the destination
3638 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3640 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3642 return VarCyFromR8(cIn, pCyOut);
3645 /************************************************************************
3646 * VarCyFromUI2 (OLEAUT32.226)
3648 * Convert a VT_UI2 to a VT_CY.
3652 * pCyOut [O] Destination
3656 * Failure: E_INVALIDARG, if the source value is invalid
3657 * DISP_E_OVERFLOW, if the value will not fit in the destination
3658 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3660 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3662 return VarCyFromR8(usIn, pCyOut);
3665 /************************************************************************
3666 * VarCyFromUI4 (OLEAUT32.227)
3668 * Convert a VT_UI4 to a VT_CY.
3672 * pCyOut [O] Destination
3676 * Failure: E_INVALIDARG, if the source value is invalid
3677 * DISP_E_OVERFLOW, if the value will not fit in the destination
3678 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3680 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3682 return VarCyFromR8(ulIn, pCyOut);
3685 /************************************************************************
3686 * VarCyFromDec (OLEAUT32.228)
3688 * Convert a VT_DECIMAL to a VT_CY.
3692 * pCyOut [O] Destination
3696 * Failure: E_INVALIDARG, if the source value is invalid
3697 * DISP_E_OVERFLOW, if the value will not fit in the destination
3698 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3700 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
3705 hRet = VarDecRound(pdecIn, 4, &rounded);
3707 if (SUCCEEDED(hRet))
3711 if (DEC_HI32(&rounded))
3712 return DISP_E_OVERFLOW;
3714 /* Note: Without the casts this promotes to int64 which loses precision */
3715 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3716 if (DEC_SIGN(&rounded))
3718 return VarCyFromR8(d, pCyOut);
3723 /************************************************************************
3724 * VarCyFromI8 (OLEAUT32.366)
3726 * Convert a VT_I8 to a VT_CY.
3730 * pCyOut [O] Destination
3734 * Failure: E_INVALIDARG, if the source value is invalid
3735 * DISP_E_OVERFLOW, if the value will not fit in the destination
3736 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3738 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3740 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3741 pCyOut->int64 = llIn * CY_MULTIPLIER;
3745 /************************************************************************
3746 * VarCyFromUI8 (OLEAUT32.375)
3748 * Convert a VT_UI8 to a VT_CY.
3752 * pCyOut [O] Destination
3756 * Failure: E_INVALIDARG, if the source value is invalid
3757 * DISP_E_OVERFLOW, if the value will not fit in the destination
3758 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3760 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3762 return VarCyFromR8(ullIn, pCyOut);
3765 /************************************************************************
3766 * VarCyAdd (OLEAUT32.299)
3768 * Add one CY to another.
3772 * cyRight [I] Value to add
3773 * pCyOut [O] Destination
3777 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3779 HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut)
3782 _VarR8FromCy(cyLeft, &l);
3783 _VarR8FromCy(cyRight, &r);
3785 return VarCyFromR8(l, pCyOut);
3788 /************************************************************************
3789 * VarCyMul (OLEAUT32.303)
3791 * Multiply one CY by another.
3795 * cyRight [I] Value to multiply by
3796 * pCyOut [O] Destination
3800 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3802 HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut)
3805 _VarR8FromCy(cyLeft, &l);
3806 _VarR8FromCy(cyRight, &r);
3808 return VarCyFromR8(l, pCyOut);
3811 /************************************************************************
3812 * VarCyMulI4 (OLEAUT32.304)
3814 * Multiply one CY by a VT_I4.
3818 * lRight [I] Value to multiply by
3819 * pCyOut [O] Destination
3823 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3825 HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut)
3829 _VarR8FromCy(cyLeft, &d);
3831 return VarCyFromR8(d, pCyOut);
3834 /************************************************************************
3835 * VarCySub (OLEAUT32.305)
3837 * Subtract one CY from another.
3841 * cyRight [I] Value to subtract
3842 * pCyOut [O] Destination
3846 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3848 HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut)
3851 _VarR8FromCy(cyLeft, &l);
3852 _VarR8FromCy(cyRight, &r);
3854 return VarCyFromR8(l, pCyOut);
3857 /************************************************************************
3858 * VarCyAbs (OLEAUT32.306)
3860 * Convert a VT_CY into its absolute value.
3864 * pCyOut [O] Destination
3867 * Success: S_OK. pCyOut contains the absolute value.
3868 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3870 HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut)
3872 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3873 return DISP_E_OVERFLOW;
3875 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3879 /************************************************************************
3880 * VarCyFix (OLEAUT32.307)
3882 * Return the integer part of a VT_CY.
3886 * pCyOut [O] Destination
3890 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3893 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3894 * negative numbers away from 0, while this function rounds them towards zero.
3896 HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut)
3898 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3899 pCyOut->int64 *= CY_MULTIPLIER;
3903 /************************************************************************
3904 * VarCyInt (OLEAUT32.308)
3906 * Return the integer part of a VT_CY.
3910 * pCyOut [O] Destination
3914 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3917 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3918 * negative numbers towards 0, while this function rounds them away from zero.
3920 HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut)
3922 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3923 pCyOut->int64 *= CY_MULTIPLIER;
3925 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3927 pCyOut->int64 -= CY_MULTIPLIER;
3932 /************************************************************************
3933 * VarCyNeg (OLEAUT32.309)
3935 * Change the sign of a VT_CY.
3939 * pCyOut [O] Destination
3943 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3945 HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut)
3947 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3948 return DISP_E_OVERFLOW;
3950 pCyOut->int64 = -cyIn.int64;
3954 /************************************************************************
3955 * VarCyRound (OLEAUT32.310)
3957 * Change the precision of a VT_CY.
3961 * cDecimals [I] New number of decimals to keep
3962 * pCyOut [O] Destination
3966 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3968 HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
3971 return E_INVALIDARG;
3975 /* Rounding to more precision than we have */
3981 double d, div = CY_Divisors[cDecimals];
3983 _VarR8FromCy(cyIn, &d);
3985 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3986 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3987 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3992 /************************************************************************
3993 * VarCyCmp (OLEAUT32.311)
3995 * Compare two VT_CY values.
3999 * cyRight [I] Value to compare
4002 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4003 * compare is less, equal or greater than source respectively.
4004 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4006 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
4011 /* Subtract right from left, and compare the result to 0 */
4012 hRet = VarCySub(cyLeft, cyRight, &result);
4014 if (SUCCEEDED(hRet))
4016 if (result.int64 < 0)
4017 hRet = (HRESULT)VARCMP_LT;
4018 else if (result.int64 > 0)
4019 hRet = (HRESULT)VARCMP_GT;
4021 hRet = (HRESULT)VARCMP_EQ;
4026 /************************************************************************
4027 * VarCyCmpR8 (OLEAUT32.312)
4029 * Compare a VT_CY to a double
4032 * cyLeft [I] Currency Source
4033 * dblRight [I] double to compare to cyLeft
4036 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4037 * less than, equal to or greater than cyLeft respectively.
4038 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4040 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight)
4045 hRet = VarCyFromR8(dblRight, &cyRight);
4047 if (SUCCEEDED(hRet))
4048 hRet = VarCyCmp(cyLeft, cyRight);
4053 /************************************************************************
4054 * VarCyMulI8 (OLEAUT32.329)
4056 * Multiply a VT_CY by a VT_I8.
4060 * llRight [I] Value to multiply by
4061 * pCyOut [O] Destination
4065 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4067 HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
4071 _VarR8FromCy(cyLeft, &d);
4072 d = d * (double)llRight;
4073 return VarCyFromR8(d, pCyOut);
4079 /************************************************************************
4080 * VarDecFromUI1 (OLEAUT32.190)
4082 * Convert a VT_UI1 to a DECIMAL.
4086 * pDecOut [O] Destination
4091 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4093 return VarDecFromUI4(bIn, pDecOut);
4096 /************************************************************************
4097 * VarDecFromI2 (OLEAUT32.191)
4099 * Convert a VT_I2 to a DECIMAL.
4103 * pDecOut [O] Destination
4108 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4110 return VarDecFromI4(sIn, pDecOut);
4113 /************************************************************************
4114 * VarDecFromI4 (OLEAUT32.192)
4116 * Convert a VT_I4 to a DECIMAL.
4120 * pDecOut [O] Destination
4125 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4127 DEC_HI32(pDecOut) = 0;
4128 DEC_MID32(pDecOut) = 0;
4132 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4133 DEC_LO32(pDecOut) = -lIn;
4137 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4138 DEC_LO32(pDecOut) = lIn;
4143 #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT))
4145 /************************************************************************
4146 * VarDecFromR4 (OLEAUT32.193)
4148 * Convert a VT_R4 to a DECIMAL.
4152 * pDecOut [O] Destination
4157 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4161 sprintfW( buff, szFloatFormatW, fltIn );
4162 return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut);
4165 /************************************************************************
4166 * VarDecFromR8 (OLEAUT32.194)
4168 * Convert a VT_R8 to a DECIMAL.
4172 * pDecOut [O] Destination
4177 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4181 sprintfW( buff, szDoubleFormatW, dblIn );
4182 return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut);
4185 /************************************************************************
4186 * VarDecFromDate (OLEAUT32.195)
4188 * Convert a VT_DATE to a DECIMAL.
4192 * pDecOut [O] Destination
4197 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4199 return VarDecFromR8(dateIn, pDecOut);
4202 /************************************************************************
4203 * VarDecFromCy (OLEAUT32.196)
4205 * Convert a VT_CY to a DECIMAL.
4209 * pDecOut [O] Destination
4214 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4216 DEC_HI32(pDecOut) = 0;
4218 /* Note: This assumes 2s complement integer representation */
4219 if (cyIn.s.Hi & 0x80000000)
4221 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4222 DEC_LO64(pDecOut) = -cyIn.int64;
4226 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4227 DEC_MID32(pDecOut) = cyIn.s.Hi;
4228 DEC_LO32(pDecOut) = cyIn.s.Lo;
4233 /************************************************************************
4234 * VarDecFromStr (OLEAUT32.197)
4236 * Convert a VT_BSTR to a DECIMAL.
4240 * lcid [I] LCID for the conversion
4241 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4242 * pDecOut [O] Destination
4246 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4248 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4250 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4253 /************************************************************************
4254 * VarDecFromDisp (OLEAUT32.198)
4256 * Convert a VT_DISPATCH to a DECIMAL.
4259 * pdispIn [I] Source
4260 * lcid [I] LCID for conversion
4261 * pDecOut [O] Destination
4265 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4267 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4269 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0);
4272 /************************************************************************
4273 * VarDecFromBool (OLEAUT32.199)
4275 * Convert a VT_BOOL to a DECIMAL.
4279 * pDecOut [O] Destination
4285 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4287 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4289 DEC_HI32(pDecOut) = 0;
4290 DEC_MID32(pDecOut) = 0;
4293 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4294 DEC_LO32(pDecOut) = 1;
4298 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4299 DEC_LO32(pDecOut) = 0;
4304 /************************************************************************
4305 * VarDecFromI1 (OLEAUT32.241)
4307 * Convert a VT_I1 to a DECIMAL.
4311 * pDecOut [O] Destination
4316 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4318 return VarDecFromI4(cIn, pDecOut);
4321 /************************************************************************
4322 * VarDecFromUI2 (OLEAUT32.242)
4324 * Convert a VT_UI2 to a DECIMAL.
4328 * pDecOut [O] Destination
4333 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4335 return VarDecFromUI4(usIn, pDecOut);
4338 /************************************************************************
4339 * VarDecFromUI4 (OLEAUT32.243)
4341 * Convert a VT_UI4 to a DECIMAL.
4345 * pDecOut [O] Destination
4350 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4352 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4353 DEC_HI32(pDecOut) = 0;
4354 DEC_MID32(pDecOut) = 0;
4355 DEC_LO32(pDecOut) = ulIn;
4359 /************************************************************************
4360 * VarDecFromI8 (OLEAUT32.374)
4362 * Convert a VT_I8 to a DECIMAL.
4366 * pDecOut [O] Destination
4371 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4373 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4375 DEC_HI32(pDecOut) = 0;
4377 /* Note: This assumes 2s complement integer representation */
4378 if (pLi->u.HighPart & 0x80000000)
4380 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4381 DEC_LO64(pDecOut) = -pLi->QuadPart;
4385 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4386 DEC_MID32(pDecOut) = pLi->u.HighPart;
4387 DEC_LO32(pDecOut) = pLi->u.LowPart;
4392 /************************************************************************
4393 * VarDecFromUI8 (OLEAUT32.375)
4395 * Convert a VT_UI8 to a DECIMAL.
4399 * pDecOut [O] Destination
4404 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4406 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4407 DEC_HI32(pDecOut) = 0;
4408 DEC_LO64(pDecOut) = ullIn;
4412 /* Make two DECIMALS the same scale; used by math functions below */
4413 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4414 const DECIMAL** ppDecRight,
4417 static DECIMAL scaleFactor;
4420 HRESULT hRet = S_OK;
4422 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4423 return E_INVALIDARG;
4425 DEC_LO32(&scaleFactor) = 10;
4427 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4430 return S_OK; /* Same scale */
4432 if (scaleAmount > 0)
4434 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4435 *ppDecRight = pDecOut;
4439 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4440 *ppDecLeft = pDecOut;
4441 i = scaleAmount = -scaleAmount;
4444 if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE)
4445 return DISP_E_OVERFLOW; /* Can't scale up */
4447 /* Multiply up the value to be scaled by the correct amount */
4448 while (SUCCEEDED(hRet) && i--)
4450 /* Note we are multiplying by a value with a scale of 0, so we don't recurse */
4451 hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut);
4454 DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */
4458 /* Add two unsigned 32 bit values with overflow */
4459 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4461 ULARGE_INTEGER ul64;
4463 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4464 *pulHigh = ul64.u.HighPart;
4465 return ul64.u.LowPart;
4468 /* Subtract two unsigned 32 bit values with underflow */
4469 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4472 ULARGE_INTEGER ul64;
4474 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4475 if (ulLeft < ulRight)
4478 if (ul64.QuadPart > (ULONG64)*pulHigh)
4479 ul64.QuadPart -= (ULONG64)*pulHigh;
4482 ul64.QuadPart -= (ULONG64)*pulHigh;
4486 ul64.u.HighPart = -ul64.u.HighPart ;
4488 *pulHigh = ul64.u.HighPart;
4489 return ul64.u.LowPart;
4492 /* Multiply two unsigned 32 bit values with overflow */
4493 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4495 ULARGE_INTEGER ul64;
4497 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4498 *pulHigh = ul64.u.HighPart;
4499 return ul64.u.LowPart;
4502 /* Compare two decimals that have the same scale */
4503 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4505 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4506 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4508 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4513 /************************************************************************
4514 * VarDecAdd (OLEAUT32.177)
4516 * Add one DECIMAL to another.
4519 * pDecLeft [I] Source
4520 * pDecRight [I] Value to add
4521 * pDecOut [O] Destination
4525 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4527 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4532 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled);
4534 if (SUCCEEDED(hRet))
4536 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4538 BYTE sign = DECIMAL_POS;
4540 /* Correct for the sign of the result */
4541 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4543 /* -x + -y : Negative */
4545 goto VarDecAdd_AsPositive;
4547 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4549 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4551 /* -x + y : Negative if x > y */
4555 VarDecAdd_AsNegative:
4556 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4557 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4558 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4562 VarDecAdd_AsInvertedNegative:
4563 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4564 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4565 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4568 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4570 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4572 /* x + -y : Negative if x <= y */
4576 goto VarDecAdd_AsInvertedNegative;
4578 goto VarDecAdd_AsNegative;
4582 /* x + y : Positive */
4583 VarDecAdd_AsPositive:
4584 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4585 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4586 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4590 return DISP_E_OVERFLOW; /* overflowed */
4592 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4593 DEC_SIGN(pDecOut) = sign;
4598 /* internal representation of the value stored in a DECIMAL. The bytes are
4599 stored from LSB at index 0 to MSB at index 11
4601 typedef struct DECIMAL_internal
4603 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4604 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4605 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4608 /* translate from external DECIMAL format into an internal representation */
4609 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4611 to->scale = DEC_SCALE(from);
4612 to->sign = DEC_SIGN(from) ? 1 : 0;
4614 to->bitsnum[0] = DEC_LO32(from);
4615 to->bitsnum[1] = DEC_MID32(from);
4616 to->bitsnum[2] = DEC_HI32(from);
4619 static void VARIANT_DecFromDI(VARIANT_DI * from, DECIMAL * to)
4622 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4624 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4627 DEC_LO32(to) = from->bitsnum[0];
4628 DEC_MID32(to) = from->bitsnum[1];
4629 DEC_HI32(to) = from->bitsnum[2];
4632 /* clear an internal representation of a DECIMAL */
4633 static void VARIANT_DI_clear(VARIANT_DI * i)
4635 memset(i, 0, sizeof(VARIANT_DI));
4638 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4639 size is supported. The value in p is replaced by the quotient of the division, and
4640 the remainder is returned as a result. This routine is most often used with a divisor
4641 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4643 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4648 } else if (divisor == 1) {
4649 /* dividend remains unchanged */
4652 unsigned char remainder = 0;
4653 ULONGLONG iTempDividend;
4656 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4657 for (; i >= 0; i--) {
4658 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4659 remainder = iTempDividend % divisor;
4660 p[i] = iTempDividend / divisor;
4667 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4668 static int VARIANT_int_iszero(DWORD * p, unsigned int n)
4670 for (; n > 0; n--) if (*p++ != 0) return 0;
4674 /* multiply two DECIMALS, without changing either one, and place result in third
4675 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4676 digits when scale > 0 in order to fit an overflowing result. Final overflow
4679 static int VARIANT_DI_mul(VARIANT_DI * a, VARIANT_DI * b, VARIANT_DI * result)
4683 signed int mulstart;
4685 VARIANT_DI_clear(result);
4686 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4688 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4689 of the result is formed by adding the scales of the operands.
4691 result->scale = a->scale + b->scale;
4692 memset(running, 0, sizeof(running));
4694 /* count number of leading zero-bytes in operand A */
4695 for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4697 /* result is 0, because operand A is 0 */
4701 unsigned char remainder = 0;
4704 /* perform actual multiplication */
4705 for (iA = 0; iA <= mulstart; iA++) {
4709 for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
4713 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4716 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4722 /* Too bad - native oleaut does not do this, so we should not either */
4724 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4725 This operation should not lose significant digits, and gives an
4726 opportunity to reduce the possibility of overflows in future
4727 operations issued by the application.
4729 while (result->scale > 0) {
4730 memcpy(quotient, running, sizeof(quotient));
4731 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4732 if (remainder > 0) break;
4733 memcpy(running, quotient, sizeof(quotient));
4737 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4738 This operation *will* lose significant digits of the result because
4739 all the factors of 10 were consumed by the previous operation.
4741 while (result->scale > 0 && !VARIANT_int_iszero(
4742 running + sizeof(result->bitsnum) / sizeof(DWORD),
4743 (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
4745 remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
4746 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4750 /* round up the result - native oleaut32 does this */
4751 if (remainder >= 5) {
4753 for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
4754 ULONGLONG digit = running[i] + 1;
4755 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4756 running[i] = digit & 0xFFFFFFFF;
4760 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4761 and copy result bits into result structure
4763 r_overflow = !VARIANT_int_iszero(
4764 running + sizeof(result->bitsnum)/sizeof(DWORD),
4765 (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
4766 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4771 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4772 hardcoded (period for decimal separator, dash as negative sign). Returns 0 for
4773 success, nonzero if insufficient space in output buffer.
4775 static int VARIANT_DI_tostringW(VARIANT_DI * a, WCHAR * s, unsigned int n)
4779 unsigned char remainder;
4782 /* place negative sign */
4783 if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
4791 /* prepare initial 0 */
4796 } else overflow = 1;
4800 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4801 while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
4802 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4806 s[i++] = '0' + remainder;
4811 if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
4813 /* reverse order of digits */
4814 WCHAR * x = s; WCHAR * y = s + i - 1;
4821 /* check for decimal point. "i" now has string length */
4822 if (i <= a->scale) {
4823 unsigned int numzeroes = a->scale + 1 - i;
4824 if (i + 1 + numzeroes >= n) {
4827 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4829 while (numzeroes > 0) {
4830 s[--numzeroes] = '0';
4835 /* place decimal point */
4837 unsigned int periodpos = i - a->scale;
4841 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4842 s[periodpos] = '.'; i++;
4844 /* remove extra zeros at the end, if any */
4845 while (s[i - 1] == '0') s[--i] = '\0';
4846 if (s[i - 1] == '.') s[--i] = '\0';
4854 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4855 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4860 /* shift whole DWORDs to the left */
4863 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4864 *p = 0; shift -= 32;
4867 /* shift remainder (1..31 bits) */
4869 if (shift > 0) for (i = 0; i < n; i++)
4872 b = p[i] >> (32 - shift);
4873 p[i] = (p[i] << shift) | shifted;
4878 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4879 Value at v is incremented by the value at p. Any size is supported, provided
4880 that v is not shorter than p. Any unapplied carry is returned as a result.
4882 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, DWORD * p,
4885 unsigned char carry = 0;
4891 for (i = 0; i < np; i++) {
4892 sum = (ULONGLONG)v[i]
4895 v[i] = sum & 0xffffffff;
4898 for (; i < nv && carry; i++) {
4899 sum = (ULONGLONG)v[i]
4901 v[i] = sum & 0xffffffff;
4908 /* perform integral division with operand p as dividend. Parameter n indicates
4909 number of available DWORDs in divisor p, but available space in p must be
4910 actually at least 2 * n DWORDs, because the remainder of the integral
4911 division is built in the next n DWORDs past the start of the quotient. This
4912 routine replaces the dividend in p with the quotient, and appends n
4913 additional DWORDs for the remainder.
4915 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4916 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4917 source code to the VLI (Very Large Integer) division operator. This algorithm
4918 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4919 variably-scaled integers such as the MS DECIMAL representation.
4921 static void VARIANT_int_div(DWORD * p, unsigned int n, DWORD * divisor,
4926 DWORD * negdivisor = tempsub + n;
4928 /* build 2s-complement of divisor */
4929 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
4931 VARIANT_int_add(negdivisor, n, p + n, 1);
4932 memset(p + n, 0, n * sizeof(DWORD));
4934 /* skip all leading zero DWORDs in quotient */
4935 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
4936 /* i is now number of DWORDs left to process */
4937 for (i <<= 5; i < (n << 5); i++) {
4938 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
4940 /* trial subtraction */
4941 memcpy(tempsub, p + n, n * sizeof(DWORD));
4942 VARIANT_int_add(tempsub, n, negdivisor, n);
4944 /* check whether result of subtraction was negative */
4945 if ((tempsub[n - 1] & 0x80000000) == 0) {
4946 memcpy(p + n, tempsub, n * sizeof(DWORD));
4952 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4953 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
4958 for (iOverflowMul = 0, i = 0; i < n; i++)
4959 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
4960 return (unsigned char)iOverflowMul;
4963 /* increment value in A by the value indicated in B, with scale adjusting.
4964 Modifies parameters by adjusting scales. Returns 0 if addition was
4965 successful, nonzero if a parameter underflowed before it could be
4966 successfully used in the addition.
4968 static int VARIANT_int_addlossy(
4969 DWORD * a, int * ascale, unsigned int an,
4970 DWORD * b, int * bscale, unsigned int bn)
4974 if (VARIANT_int_iszero(a, an)) {
4975 /* if A is zero, copy B into A, after removing digits */
4976 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
4977 VARIANT_int_divbychar(b, bn, 10);
4980 memcpy(a, b, an * sizeof(DWORD));
4982 } else if (!VARIANT_int_iszero(b, bn)) {
4983 unsigned int tn = an + 1;
4986 if (bn + 1 > tn) tn = bn + 1;
4987 if (*ascale != *bscale) {
4988 /* first (optimistic) try - try to scale down the one with the bigger
4989 scale, while this number is divisible by 10 */
4990 DWORD * digitchosen;
4991 unsigned int nchosen;
4995 if (*ascale < *bscale) {
4996 targetscale = *ascale;
4997 scalechosen = bscale;
5001 targetscale = *bscale;
5002 scalechosen = ascale;
5006 memset(t, 0, tn * sizeof(DWORD));
5007 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5009 /* divide by 10 until target scale is reached */
5010 while (*scalechosen > targetscale) {
5011 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5014 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5019 if (*ascale != *bscale) {
5020 DWORD * digitchosen;
5021 unsigned int nchosen;
5025 /* try to scale up the one with the smaller scale */
5026 if (*ascale > *bscale) {
5027 targetscale = *ascale;
5028 scalechosen = bscale;
5032 targetscale = *bscale;
5033 scalechosen = ascale;
5037 memset(t, 0, tn * sizeof(DWORD));
5038 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5040 /* multiply by 10 until target scale is reached, or
5041 significant bytes overflow the number
5043 while (*scalechosen < targetscale && t[nchosen] == 0) {
5044 VARIANT_int_mulbychar(t, tn, 10);
5045 if (t[nchosen] == 0) {
5046 /* still does not overflow */
5048 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5053 if (*ascale != *bscale) {
5054 /* still different? try to scale down the one with the bigger scale
5055 (this *will* lose significant digits) */
5056 DWORD * digitchosen;
5057 unsigned int nchosen;
5061 if (*ascale < *bscale) {
5062 targetscale = *ascale;
5063 scalechosen = bscale;
5067 targetscale = *bscale;
5068 scalechosen = ascale;
5072 memset(t, 0, tn * sizeof(DWORD));
5073 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5075 /* divide by 10 until target scale is reached */
5076 while (*scalechosen > targetscale) {
5077 VARIANT_int_divbychar(t, tn, 10);
5079 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5083 /* check whether any of the operands still has significant digits
5086 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5089 /* at this step, both numbers have the same scale and can be added
5090 as integers. However, the result might not fit in A, so further
5091 scaling down might be necessary.
5093 while (!underflow) {
5094 memset(t, 0, tn * sizeof(DWORD));
5095 memcpy(t, a, an * sizeof(DWORD));
5097 VARIANT_int_add(t, tn, b, bn);
5098 if (VARIANT_int_iszero(t + an, tn - an)) {
5099 /* addition was successful */
5100 memcpy(a, t, an * sizeof(DWORD));
5103 /* addition overflowed - remove significant digits
5104 from both operands and try again */
5105 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5106 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5107 /* check whether any operand keeps significant digits after
5108 scaledown (underflow case 2)
5110 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5118 /* perform complete DECIMAL division in the internal representation. Returns
5119 0 if the division was completed (even if quotient is set to 0), or nonzero
5120 in case of quotient overflow.
5122 static HRESULT VARIANT_DI_div(VARIANT_DI * dividend, VARIANT_DI * divisor, VARIANT_DI * quotient)
5124 HRESULT r_overflow = S_OK;
5126 if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
5128 r_overflow = DISP_E_DIVBYZERO;
5129 } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
5130 VARIANT_DI_clear(quotient);
5132 int quotientscale, remainderscale, tempquotientscale;
5133 DWORD remainderplusquotient[8];
5136 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5137 tempquotientscale = quotientscale;
5138 VARIANT_DI_clear(quotient);
5139 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5141 /* The following strategy is used for division
5142 1) if there was a nonzero remainder from previous iteration, use it as
5143 dividend for this iteration, else (for first iteration) use intended
5145 2) perform integer division in temporary buffer, develop quotient in
5146 low-order part, remainder in high-order part
5147 3) add quotient from step 2 to final result, with possible loss of
5149 4) multiply integer part of remainder by 10, while incrementing the
5150 scale of the remainder. This operation preserves the intended value
5152 5) loop to step 1 until one of the following is true:
5153 a) remainder is zero (exact division achieved)
5154 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5156 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5157 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5160 remainderplusquotient, 4,
5161 divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
5162 underflow = VARIANT_int_addlossy(
5163 quotient->bitsnum, "ientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
5164 remainderplusquotient, &tempquotientscale, 4);
5165 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5166 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5167 tempquotientscale = ++remainderscale;
5168 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5170 /* quotient scale might now be negative (extremely big number). If, so, try
5171 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5172 until scale is 0. If this cannot be done, it is a real overflow.
5174 while (!r_overflow && quotientscale < 0) {
5175 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5176 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5177 VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
5178 if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
5179 (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
5181 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5182 } else r_overflow = DISP_E_OVERFLOW;
5185 if (quotientscale <= 255) quotient->scale = quotientscale;
5186 else VARIANT_DI_clear(quotient);
5192 /************************************************************************
5193 * VarDecDiv (OLEAUT32.178)
5195 * Divide one DECIMAL by another.
5198 * pDecLeft [I] Source
5199 * pDecRight [I] Value to divide by
5200 * pDecOut [O] Destination
5204 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5206 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5208 HRESULT hRet = S_OK;
5209 VARIANT_DI di_left, di_right, di_result;
5212 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5214 VARIANT_DIFromDec(pDecLeft, &di_left);
5215 VARIANT_DIFromDec(pDecRight, &di_right);
5216 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result);
5219 /* division actually overflowed */
5226 if (di_result.scale > DEC_MAX_SCALE)
5228 unsigned char remainder = 0;
5230 /* division underflowed. In order to comply with the MSDN
5231 specifications for DECIMAL ranges, some significant digits
5234 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5236 while (di_result.scale > DEC_MAX_SCALE &&
5237 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
5239 remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
5242 if (di_result.scale > DEC_MAX_SCALE)
5244 WARN("result underflowed, setting to 0\n");
5245 di_result.scale = 0;
5248 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5251 for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
5252 ULONGLONG digit = di_result.bitsnum[i] + 1;
5253 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5254 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5258 VARIANT_DecFromDI(&di_result, pDecOut);
5263 /************************************************************************
5264 * VarDecMul (OLEAUT32.179)
5266 * Multiply one DECIMAL by another.
5269 * pDecLeft [I] Source
5270 * pDecRight [I] Value to multiply by
5271 * pDecOut [O] Destination
5275 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5277 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5279 HRESULT hRet = S_OK;
5280 VARIANT_DI di_left, di_right, di_result;
5283 VARIANT_DIFromDec(pDecLeft, &di_left);
5284 VARIANT_DIFromDec(pDecRight, &di_right);
5285 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5288 /* multiplication actually overflowed */
5289 hRet = DISP_E_OVERFLOW;
5293 if (di_result.scale > DEC_MAX_SCALE)
5295 /* multiplication underflowed. In order to comply with the MSDN
5296 specifications for DECIMAL ranges, some significant digits
5299 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5301 while (di_result.scale > DEC_MAX_SCALE &&
5302 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
5304 VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
5307 if (di_result.scale > DEC_MAX_SCALE)
5309 WARN("result underflowed, setting to 0\n");
5310 di_result.scale = 0;
5314 VARIANT_DecFromDI(&di_result, pDecOut);
5319 /************************************************************************
5320 * VarDecSub (OLEAUT32.181)
5322 * Subtract one DECIMAL from another.
5325 * pDecLeft [I] Source
5326 * pDecRight [I] DECIMAL to subtract from pDecLeft
5327 * pDecOut [O] Destination
5330 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5332 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5336 /* Implement as addition of the negative */
5337 VarDecNeg(pDecRight, &decRight);
5338 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5341 /************************************************************************
5342 * VarDecAbs (OLEAUT32.182)
5344 * Convert a DECIMAL into its absolute value.
5348 * pDecOut [O] Destination
5351 * S_OK. This function does not fail.
5353 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5356 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5360 /************************************************************************
5361 * VarDecFix (OLEAUT32.187)
5363 * Return the integer portion of a DECIMAL.
5367 * pDecOut [O] Destination
5371 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5374 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5375 * negative numbers away from 0, while this function rounds them towards zero.
5377 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5379 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5380 return E_INVALIDARG;
5382 if (!DEC_SCALE(pDecIn))
5384 *pDecOut = *pDecIn; /* Already an integer */
5388 FIXME("semi-stub!\n");
5389 return DISP_E_OVERFLOW;
5392 /************************************************************************
5393 * VarDecInt (OLEAUT32.188)
5395 * Return the integer portion of a DECIMAL.
5399 * pDecOut [O] Destination
5403 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5406 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5407 * negative numbers towards 0, while this function rounds them away from zero.
5409 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5411 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5412 return E_INVALIDARG;
5414 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5415 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5417 FIXME("semi-stub!\n");
5418 return DISP_E_OVERFLOW;
5421 /************************************************************************
5422 * VarDecNeg (OLEAUT32.189)
5424 * Change the sign of a DECIMAL.
5428 * pDecOut [O] Destination
5431 * S_OK. This function does not fail.
5433 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5436 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5440 /************************************************************************
5441 * VarDecRound (OLEAUT32.203)
5443 * Change the precision of a DECIMAL.
5447 * cDecimals [I] New number of decimals to keep
5448 * pDecOut [O] Destination
5451 * Success: S_OK. pDecOut contains the rounded value.
5452 * Failure: E_INVALIDARG if any argument is invalid.
5454 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5456 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5457 return E_INVALIDARG;
5459 if (cDecimals >= DEC_SCALE(pDecIn))
5461 *pDecOut = *pDecIn; /* More precision than we have */
5465 FIXME("semi-stub!\n");
5467 return DISP_E_OVERFLOW;
5470 /************************************************************************
5471 * VarDecCmp (OLEAUT32.204)
5473 * Compare two DECIMAL values.
5476 * pDecLeft [I] Source
5477 * pDecRight [I] Value to compare
5480 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5481 * is less than, equal to or greater than pDecRight respectively.
5482 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5484 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5489 /* Subtract right from left, and compare the result to 0 */
5490 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5492 if (SUCCEEDED(hRet))
5494 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5496 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5497 hRet = (HRESULT)VARCMP_LT;
5499 hRet = (HRESULT)VARCMP_GT;
5501 hRet = (HRESULT)VARCMP_EQ;
5506 /************************************************************************
5507 * VarDecCmpR8 (OLEAUT32.298)
5509 * Compare a DECIMAL to a double
5512 * pDecLeft [I] DECIMAL Source
5513 * dblRight [I] double to compare to pDecLeft
5516 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5517 * is less than, equal to or greater than pDecLeft respectively.
5518 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5520 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5525 hRet = VarDecFromR8(dblRight, &decRight);
5527 if (SUCCEEDED(hRet))
5528 hRet = VarDecCmp(pDecLeft, &decRight);
5536 /************************************************************************
5537 * VarBoolFromUI1 (OLEAUT32.118)
5539 * Convert a VT_UI1 to a VT_BOOL.
5543 * pBoolOut [O] Destination
5548 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5550 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5554 /************************************************************************
5555 * VarBoolFromI2 (OLEAUT32.119)
5557 * Convert a VT_I2 to a VT_BOOL.
5561 * pBoolOut [O] Destination
5566 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5568 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5572 /************************************************************************
5573 * VarBoolFromI4 (OLEAUT32.120)
5575 * Convert a VT_I4 to a VT_BOOL.
5579 * pBoolOut [O] Destination
5584 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
5586 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
5590 /************************************************************************
5591 * VarBoolFromR4 (OLEAUT32.121)
5593 * Convert a VT_R4 to a VT_BOOL.
5597 * pBoolOut [O] Destination
5602 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
5604 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
5608 /************************************************************************
5609 * VarBoolFromR8 (OLEAUT32.122)
5611 * Convert a VT_R8 to a VT_BOOL.
5615 * pBoolOut [O] Destination
5620 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
5622 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
5626 /************************************************************************
5627 * VarBoolFromDate (OLEAUT32.123)
5629 * Convert a VT_DATE to a VT_BOOL.
5633 * pBoolOut [O] Destination
5638 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
5640 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
5644 /************************************************************************
5645 * VarBoolFromCy (OLEAUT32.124)
5647 * Convert a VT_CY to a VT_BOOL.
5651 * pBoolOut [O] Destination
5656 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
5658 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
5662 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
5666 hrsrc = FindResourceExW( OLEAUT32_hModule, (LPWSTR)RT_STRING,
5667 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
5670 HGLOBAL hmem = LoadResource( OLEAUT32_hModule, hrsrc );
5677 p = LockResource( hmem );
5678 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
5680 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
5681 lpszDest[*p] = '\0';
5682 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
5689 /************************************************************************
5690 * VarBoolFromStr (OLEAUT32.125)
5692 * Convert a VT_BSTR to a VT_BOOL.
5696 * lcid [I] LCID for the conversion
5697 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5698 * pBoolOut [O] Destination
5702 * Failure: E_INVALIDARG, if pBoolOut is invalid.
5703 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5706 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
5707 * it may contain (in any case mapping) the text "true" or "false".
5708 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
5709 * localised text of "True" or "False" in the language specified by lcid.
5710 * - If none of these matches occur, the string is treated as a numeric string
5711 * and the boolean pBoolOut will be set according to whether the number is zero
5712 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
5713 * - If the text is not numeric and does not match any of the above, then
5714 * DISP_E_TYPEMISMATCH is returned.
5716 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
5718 /* Any VB/VBA programmers out there should recognise these strings... */
5719 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
5720 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
5722 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5723 HRESULT hRes = S_OK;
5725 if (!strIn || !pBoolOut)
5726 return DISP_E_TYPEMISMATCH;
5728 /* Check if we should be comparing against localised text */
5729 if (dwFlags & VAR_LOCALBOOL)
5731 /* Convert our LCID into a usable value */
5732 lcid = ConvertDefaultLocale(lcid);
5734 langId = LANGIDFROMLCID(lcid);
5736 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
5737 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5739 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
5740 * I don't think this is needed unless any of the localised text strings
5741 * contain characters that can be so mapped. In the event that this is
5742 * true for a given language (possibly some Asian languages), then strIn
5743 * should be mapped here _only_ if langId is an Id for which this can occur.
5747 /* Note that if we are not comparing against localised strings, langId
5748 * will have its default value of LANG_ENGLISH. This allows us to mimic
5749 * the native behaviour of always checking against English strings even
5750 * after we've checked for localised ones.
5752 VarBoolFromStr_CheckLocalised:
5753 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
5755 /* Compare against localised strings, ignoring case */
5756 if (!strcmpiW(strIn, szBuff))
5758 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
5761 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
5762 if (!strcmpiW(strIn, szBuff))
5764 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
5769 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
5771 /* We have checked the localised text, now check English */
5772 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5773 goto VarBoolFromStr_CheckLocalised;
5776 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
5777 if (!strcmpW(strIn, szFalse))
5778 *pBoolOut = VARIANT_FALSE;
5779 else if (!strcmpW(strIn, szTrue))
5780 *pBoolOut = VARIANT_TRUE;
5785 /* If this string is a number, convert it as one */
5786 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
5787 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
5792 /************************************************************************
5793 * VarBoolFromDisp (OLEAUT32.126)
5795 * Convert a VT_DISPATCH to a VT_BOOL.
5798 * pdispIn [I] Source
5799 * lcid [I] LCID for conversion
5800 * pBoolOut [O] Destination
5804 * Failure: E_INVALIDARG, if the source value is invalid
5805 * DISP_E_OVERFLOW, if the value will not fit in the destination
5806 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5808 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
5810 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
5813 /************************************************************************
5814 * VarBoolFromI1 (OLEAUT32.233)
5816 * Convert a VT_I1 to a VT_BOOL.
5820 * pBoolOut [O] Destination
5825 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
5827 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
5831 /************************************************************************
5832 * VarBoolFromUI2 (OLEAUT32.234)
5834 * Convert a VT_UI2 to a VT_BOOL.
5838 * pBoolOut [O] Destination
5843 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
5845 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
5849 /************************************************************************
5850 * VarBoolFromUI4 (OLEAUT32.235)
5852 * Convert a VT_UI4 to a VT_BOOL.
5856 * pBoolOut [O] Destination
5861 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
5863 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
5867 /************************************************************************
5868 * VarBoolFromDec (OLEAUT32.236)
5870 * Convert a VT_DECIMAL to a VT_BOOL.
5874 * pBoolOut [O] Destination
5878 * Failure: E_INVALIDARG, if pDecIn is invalid.
5880 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
5882 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
5883 return E_INVALIDARG;
5885 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
5886 *pBoolOut = VARIANT_TRUE;
5888 *pBoolOut = VARIANT_FALSE;
5892 /************************************************************************
5893 * VarBoolFromI8 (OLEAUT32.370)
5895 * Convert a VT_I8 to a VT_BOOL.
5899 * pBoolOut [O] Destination
5904 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
5906 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
5910 /************************************************************************
5911 * VarBoolFromUI8 (OLEAUT32.371)
5913 * Convert a VT_UI8 to a VT_BOOL.
5917 * pBoolOut [O] Destination
5922 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
5924 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
5931 /* Write a number from a UI8 and sign */
5932 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
5936 WCHAR ulNextDigit = ulVal % 10;
5938 *szOut-- = '0' + ulNextDigit;
5939 ulVal = (ulVal - ulNextDigit) / 10;
5946 /* Create a (possibly localised) BSTR from a UI8 and sign */
5947 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
5949 WCHAR szConverted[256];
5951 if (dwFlags & VAR_NEGATIVE)
5954 if (dwFlags & LOCALE_USE_NLS)
5956 /* Format the number for the locale */
5957 szConverted[0] = '\0';
5958 GetNumberFormatW(lcid,
5959 dwFlags & LOCALE_NOUSEROVERRIDE,
5960 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
5961 szOut = szConverted;
5963 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
5966 /* Create a (possibly localised) BSTR from a UI8 and sign */
5967 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
5969 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
5972 return E_INVALIDARG;
5974 /* Create the basic number string */
5976 szOut = VARIANT_WriteNumber(ulVal, szOut);
5978 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
5979 TRACE("returning %s\n", debugstr_w(*pbstrOut));
5980 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
5983 /******************************************************************************
5984 * VarBstrFromUI1 (OLEAUT32.108)
5986 * Convert a VT_UI1 to a VT_BSTR.
5990 * lcid [I] LCID for the conversion
5991 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5992 * pbstrOut [O] Destination
5996 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5997 * E_OUTOFMEMORY, if memory allocation fails.
5999 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6001 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6004 /******************************************************************************
6005 * VarBstrFromI2 (OLEAUT32.109)
6007 * Convert a VT_I2 to a VT_BSTR.
6011 * lcid [I] LCID for the conversion
6012 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6013 * pbstrOut [O] Destination
6017 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6018 * E_OUTOFMEMORY, if memory allocation fails.
6020 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6027 dwFlags |= VAR_NEGATIVE;
6029 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6032 /******************************************************************************
6033 * VarBstrFromI4 (OLEAUT32.110)
6035 * Convert a VT_I4 to a VT_BSTR.
6039 * lcid [I] LCID for the conversion
6040 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6041 * pbstrOut [O] Destination
6045 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6046 * E_OUTOFMEMORY, if memory allocation fails.
6048 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6055 dwFlags |= VAR_NEGATIVE;
6057 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6060 static BSTR VARIANT_BstrReplaceDecimal(WCHAR * buff, LCID lcid, ULONG dwFlags)
6063 WCHAR lpDecimalSep[16];
6065 /* Native oleaut32 uses the locale-specific decimal separator even in the
6066 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6067 American locales will see "one thousand and one tenth" as "1000,1"
6068 instead of "1000.1" (notice the comma). The following code checks for
6069 the need to replace the decimal separator, and if so, will prepare an
6070 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6072 GetLocaleInfoW(lcid, LOCALE_SDECIMAL, lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
6073 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6075 /* locale is compatible with English - return original string */
6076 bstrOut = SysAllocString(buff);
6082 WCHAR empty[1] = {'\0'};
6083 NUMBERFMTW minFormat;
6085 minFormat.NumDigits = 0;
6086 minFormat.LeadingZero = 0;
6087 minFormat.Grouping = 0;
6088 minFormat.lpDecimalSep = lpDecimalSep;
6089 minFormat.lpThousandSep = empty;
6090 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6092 /* count number of decimal digits in string */
6093 p = strchrW( buff, '.' );
6094 if (p) minFormat.NumDigits = strlenW(p + 1);
6097 if (!GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6098 buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
6100 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6101 bstrOut = SysAllocString(buff);
6105 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6106 bstrOut = SysAllocString(numbuff);
6112 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6113 BSTR* pbstrOut, LPCWSTR lpszFormat)
6118 return E_INVALIDARG;
6120 sprintfW( buff, lpszFormat, dblIn );
6122 /* Negative zeroes are disallowed (some applications depend on this).
6123 If buff starts with a minus, and then nothing follows but zeroes
6124 and/or a period, it is a negative zero and is replaced with a
6125 canonical zero. This duplicates native oleaut32 behavior.
6129 const WCHAR szAccept[] = {'0', '.', '\0'};
6130 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
6131 { buff[0] = '0'; buff[1] = '\0'; }
6134 TRACE("created string %s\n", debugstr_w(buff));
6135 if (dwFlags & LOCALE_USE_NLS)
6139 /* Format the number for the locale */
6141 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6142 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6143 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6144 *pbstrOut = SysAllocString(numbuff);
6148 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6150 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6153 /******************************************************************************
6154 * VarBstrFromR4 (OLEAUT32.111)
6156 * Convert a VT_R4 to a VT_BSTR.
6160 * lcid [I] LCID for the conversion
6161 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6162 * pbstrOut [O] Destination
6166 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6167 * E_OUTOFMEMORY, if memory allocation fails.
6169 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6171 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
6174 /******************************************************************************
6175 * VarBstrFromR8 (OLEAUT32.112)
6177 * Convert a VT_R8 to a VT_BSTR.
6181 * lcid [I] LCID for the conversion
6182 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6183 * pbstrOut [O] Destination
6187 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6188 * E_OUTOFMEMORY, if memory allocation fails.
6190 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6192 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
6195 /******************************************************************************
6196 * VarBstrFromCy [OLEAUT32.113]
6198 * Convert a VT_CY to a VT_BSTR.
6202 * lcid [I] LCID for the conversion
6203 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6204 * pbstrOut [O] Destination
6208 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6209 * E_OUTOFMEMORY, if memory allocation fails.
6211 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6217 return E_INVALIDARG;
6219 VarR8FromCy(cyIn, &dblVal);
6220 sprintfW(buff, szDoubleFormatW, dblVal);
6222 if (dwFlags & LOCALE_USE_NLS)
6226 /* Format the currency for the locale */
6228 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6229 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR));
6230 *pbstrOut = SysAllocString(cybuff);
6233 *pbstrOut = SysAllocString(buff);
6235 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6238 /******************************************************************************
6239 * VarBstrFromDate [OLEAUT32.114]
6241 * Convert a VT_DATE to a VT_BSTR.
6245 * lcid [I] LCID for the conversion
6246 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6247 * pbstrOut [O] Destination
6251 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6252 * E_OUTOFMEMORY, if memory allocation fails.
6254 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6257 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6258 WCHAR date[128], *time;
6260 TRACE("(%g,0x%08lx,0x%08lx,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
6262 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6263 return E_INVALIDARG;
6267 if (dwFlags & VAR_CALENDAR_THAI)
6268 st.wYear += 553; /* Use the Thai buddhist calendar year */
6269 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6270 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6272 if (dwFlags & LOCALE_USE_NLS)
6273 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6276 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6277 double partial = dateIn - whole;
6280 dwFlags |= VAR_TIMEVALUEONLY;
6281 else if (partial < 1e-12)
6282 dwFlags |= VAR_DATEVALUEONLY;
6285 if (dwFlags & VAR_TIMEVALUEONLY)
6288 if (!GetDateFormatW(lcid, dwFormatFlags|DATE_SHORTDATE, &st, NULL, date,
6289 sizeof(date)/sizeof(WCHAR)))
6290 return E_INVALIDARG;
6292 if (!(dwFlags & VAR_DATEVALUEONLY))
6294 time = date + strlenW(date);
6297 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
6298 sizeof(date)/sizeof(WCHAR)-(time-date)))
6299 return E_INVALIDARG;
6302 *pbstrOut = SysAllocString(date);
6304 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6305 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6308 /******************************************************************************
6309 * VarBstrFromBool (OLEAUT32.116)
6311 * Convert a VT_BOOL to a VT_BSTR.
6315 * lcid [I] LCID for the conversion
6316 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6317 * pbstrOut [O] Destination
6321 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6322 * E_OUTOFMEMORY, if memory allocation fails.
6325 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6326 * localised text of "True" or "False". To convert a bool into a
6327 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6329 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6332 DWORD dwResId = IDS_TRUE;
6335 TRACE("%d,0x%08lx,0x%08lx,%p\n", boolIn, lcid, dwFlags, pbstrOut);
6338 return E_INVALIDARG;
6340 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6341 * for variant formatting */
6342 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6353 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6356 lcid = ConvertDefaultLocale(lcid);
6357 langId = LANGIDFROMLCID(lcid);
6358 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6359 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6361 if (boolIn == VARIANT_FALSE)
6362 dwResId++; /* Use negative form */
6364 VarBstrFromBool_GetLocalised:
6365 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6367 *pbstrOut = SysAllocString(szBuff);
6368 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6371 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6373 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6374 goto VarBstrFromBool_GetLocalised;
6377 /* Should never get here */
6378 WARN("Failed to load bool text!\n");
6379 return E_OUTOFMEMORY;
6382 /******************************************************************************
6383 * VarBstrFromI1 (OLEAUT32.229)
6385 * Convert a VT_I1 to a VT_BSTR.
6389 * lcid [I] LCID for the conversion
6390 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6391 * pbstrOut [O] Destination
6395 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6396 * E_OUTOFMEMORY, if memory allocation fails.
6398 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6405 dwFlags |= VAR_NEGATIVE;
6407 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6410 /******************************************************************************
6411 * VarBstrFromUI2 (OLEAUT32.230)
6413 * Convert a VT_UI2 to a VT_BSTR.
6417 * lcid [I] LCID for the conversion
6418 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6419 * pbstrOut [O] Destination
6423 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6424 * E_OUTOFMEMORY, if memory allocation fails.
6426 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6428 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6431 /******************************************************************************
6432 * VarBstrFromUI4 (OLEAUT32.231)
6434 * Convert a VT_UI4 to a VT_BSTR.
6438 * lcid [I] LCID for the conversion
6439 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6440 * pbstrOut [O] Destination
6444 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6445 * E_OUTOFMEMORY, if memory allocation fails.
6447 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6449 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
6452 /******************************************************************************
6453 * VarBstrFromDec (OLEAUT32.232)
6455 * Convert a VT_DECIMAL to a VT_BSTR.
6459 * lcid [I] LCID for the conversion
6460 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6461 * pbstrOut [O] Destination
6465 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6466 * E_OUTOFMEMORY, if memory allocation fails.
6468 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6474 return E_INVALIDARG;
6476 VARIANT_DIFromDec(pDecIn, &temp);
6477 VARIANT_DI_tostringW(&temp, buff, 256);
6479 if (dwFlags & LOCALE_USE_NLS)
6483 /* Format the number for the locale */
6485 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6486 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6487 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6488 *pbstrOut = SysAllocString(numbuff);
6492 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6495 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6496 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6499 /************************************************************************
6500 * VarBstrFromI8 (OLEAUT32.370)
6502 * Convert a VT_I8 to a VT_BSTR.
6506 * lcid [I] LCID for the conversion
6507 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6508 * pbstrOut [O] Destination
6512 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6513 * E_OUTOFMEMORY, if memory allocation fails.
6515 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6517 ULONG64 ul64 = llIn;
6522 dwFlags |= VAR_NEGATIVE;
6524 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6527 /************************************************************************
6528 * VarBstrFromUI8 (OLEAUT32.371)
6530 * Convert a VT_UI8 to a VT_BSTR.
6534 * lcid [I] LCID for the conversion
6535 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6536 * pbstrOut [O] Destination
6540 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6541 * E_OUTOFMEMORY, if memory allocation fails.
6543 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6545 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
6548 /************************************************************************
6549 * VarBstrFromDisp (OLEAUT32.115)
6551 * Convert a VT_DISPATCH to a BSTR.
6554 * pdispIn [I] Source
6555 * lcid [I] LCID for conversion
6556 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6557 * pbstrOut [O] Destination
6561 * Failure: E_INVALIDARG, if the source value is invalid
6562 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6564 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6566 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
6569 /**********************************************************************
6570 * VarBstrCat (OLEAUT32.313)
6572 * Concatenate two BSTR values.
6575 * pbstrLeft [I] Source
6576 * pbstrRight [I] Value to concatenate
6577 * pbstrOut [O] Destination
6581 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6582 * E_OUTOFMEMORY, if memory allocation fails.
6584 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
6589 return E_INVALIDARG;
6591 len = pbstrLeft ? strlenW(pbstrLeft) : 0;
6593 len += strlenW(pbstrRight);
6595 *pbstrOut = SysAllocStringLen(NULL, len);
6597 return E_OUTOFMEMORY;
6599 (*pbstrOut)[0] = '\0';
6602 strcpyW(*pbstrOut, pbstrLeft);
6605 strcatW(*pbstrOut, pbstrRight);
6610 /**********************************************************************
6611 * VarBstrCmp (OLEAUT32.314)
6613 * Compare two BSTR values.
6616 * pbstrLeft [I] Source
6617 * pbstrRight [I] Value to compare
6618 * lcid [I] LCID for the comparison
6619 * dwFlags [I] Flags to pass directly to CompareStringW().
6622 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
6623 * than, equal to or greater than pbstrRight respectively.
6626 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
6627 * states. A NULL BSTR pointer is equivalent to an empty string.
6629 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
6631 if (!pbstrLeft || !*pbstrLeft)
6633 if (!pbstrRight || !*pbstrRight)
6637 else if (!pbstrRight || !*pbstrRight)
6640 return CompareStringW(lcid, dwFlags, pbstrLeft, -1, pbstrRight, -1) - 1;
6647 /******************************************************************************
6648 * VarDateFromUI1 (OLEAUT32.88)
6650 * Convert a VT_UI1 to a VT_DATE.
6654 * pdateOut [O] Destination
6659 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
6661 return VarR8FromUI1(bIn, pdateOut);
6664 /******************************************************************************
6665 * VarDateFromI2 (OLEAUT32.89)
6667 * Convert a VT_I2 to a VT_DATE.
6671 * pdateOut [O] Destination
6676 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
6678 return VarR8FromI2(sIn, pdateOut);
6681 /******************************************************************************
6682 * VarDateFromI4 (OLEAUT32.90)
6684 * Convert a VT_I4 to a VT_DATE.
6688 * pdateOut [O] Destination
6693 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
6695 return VarDateFromR8(lIn, pdateOut);
6698 /******************************************************************************
6699 * VarDateFromR4 (OLEAUT32.91)
6701 * Convert a VT_R4 to a VT_DATE.
6705 * pdateOut [O] Destination
6710 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
6712 return VarR8FromR4(fltIn, pdateOut);
6715 /******************************************************************************
6716 * VarDateFromR8 (OLEAUT32.92)
6718 * Convert a VT_R8 to a VT_DATE.
6722 * pdateOut [O] Destination
6727 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
6729 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
6730 *pdateOut = (DATE)dblIn;
6734 /**********************************************************************
6735 * VarDateFromDisp (OLEAUT32.95)
6737 * Convert a VT_DISPATCH to a VT_DATE.
6740 * pdispIn [I] Source
6741 * lcid [I] LCID for conversion
6742 * pdateOut [O] Destination
6746 * Failure: E_INVALIDARG, if the source value is invalid
6747 * DISP_E_OVERFLOW, if the value will not fit in the destination
6748 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6750 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
6752 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
6755 /******************************************************************************
6756 * VarDateFromBool (OLEAUT32.96)
6758 * Convert a VT_BOOL to a VT_DATE.
6762 * pdateOut [O] Destination
6767 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
6769 return VarR8FromBool(boolIn, pdateOut);
6772 /**********************************************************************
6773 * VarDateFromCy (OLEAUT32.93)
6775 * Convert a VT_CY to a VT_DATE.
6779 * pdateOut [O] Destination
6784 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
6786 return VarR8FromCy(cyIn, pdateOut);
6789 /* Date string parsing */
6790 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
6791 #define DP_DATESEP 0x02 /* Date separator */
6792 #define DP_MONTH 0x04 /* Month name */
6793 #define DP_AM 0x08 /* AM */
6794 #define DP_PM 0x10 /* PM */
6796 typedef struct tagDATEPARSE
6798 DWORD dwCount; /* Number of fields found so far (maximum 6) */
6799 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
6800 DWORD dwFlags[6]; /* Flags for each field */
6801 DWORD dwValues[6]; /* Value of each field */
6804 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
6806 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
6808 /* Determine if a day is valid in a given month of a given year */
6809 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
6811 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
6813 if (day && month && month < 13)
6815 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
6821 /* Possible orders for 3 numbers making up a date */
6822 #define ORDER_MDY 0x01
6823 #define ORDER_YMD 0x02
6824 #define ORDER_YDM 0x04
6825 #define ORDER_DMY 0x08
6826 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
6828 /* Determine a date for a particular locale, from 3 numbers */
6829 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
6830 DWORD offset, SYSTEMTIME *st)
6832 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
6836 v1 = 30; /* Default to (Variant) 0 date part */
6839 goto VARIANT_MakeDate_OK;
6842 v1 = dp->dwValues[offset + 0];
6843 v2 = dp->dwValues[offset + 1];
6844 if (dp->dwCount == 2)
6847 GetSystemTime(¤t);
6851 v3 = dp->dwValues[offset + 2];
6853 TRACE("(%ld,%ld,%ld,%ld,%ld)\n", v1, v2, v3, iDate, offset);
6855 /* If one number must be a month (Because a month name was given), then only
6856 * consider orders with the month in that position.
6857 * If we took the current year as 'v3', then only allow a year in that position.
6859 if (dp->dwFlags[offset + 0] & DP_MONTH)
6861 dwAllOrders = ORDER_MDY;
6863 else if (dp->dwFlags[offset + 1] & DP_MONTH)
6865 dwAllOrders = ORDER_DMY;
6866 if (dp->dwCount > 2)
6867 dwAllOrders |= ORDER_YMD;
6869 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
6871 dwAllOrders = ORDER_YDM;
6875 dwAllOrders = ORDER_MDY|ORDER_DMY;
6876 if (dp->dwCount > 2)
6877 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
6880 VARIANT_MakeDate_Start:
6881 TRACE("dwAllOrders is 0x%08lx\n", dwAllOrders);
6889 /* First: Try the order given by iDate */
6892 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
6893 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
6894 default: dwTry = dwAllOrders & ORDER_YMD; break;
6897 else if (dwCount == 1)
6899 /* Second: Try all the orders compatible with iDate */
6902 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
6903 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break;
6904 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
6909 /* Finally: Try any remaining orders */
6910 dwTry = dwAllOrders;
6913 TRACE("Attempt %ld, dwTry is 0x%08lx\n", dwCount, dwTry);
6919 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
6921 if (dwTry & ORDER_MDY)
6923 if (VARIANT_IsValidMonthDay(v2,v1,v3))
6926 goto VARIANT_MakeDate_OK;
6928 dwAllOrders &= ~ORDER_MDY;
6930 if (dwTry & ORDER_YMD)
6932 if (VARIANT_IsValidMonthDay(v3,v2,v1))
6935 goto VARIANT_MakeDate_OK;
6937 dwAllOrders &= ~ORDER_YMD;
6939 if (dwTry & ORDER_YDM)
6941 if (VARIANT_IsValidMonthDay(v2,v3,v1))
6945 goto VARIANT_MakeDate_OK;
6947 dwAllOrders &= ~ORDER_YDM;
6949 if (dwTry & ORDER_DMY)
6951 if (VARIANT_IsValidMonthDay(v1,v2,v3))
6952 goto VARIANT_MakeDate_OK;
6953 dwAllOrders &= ~ORDER_DMY;
6955 if (dwTry & ORDER_MYD)
6957 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
6958 if (VARIANT_IsValidMonthDay(v3,v1,v2))
6962 goto VARIANT_MakeDate_OK;
6964 dwAllOrders &= ~ORDER_MYD;
6968 if (dp->dwCount == 2)
6970 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
6971 v3 = 1; /* 1st of the month */
6972 dwAllOrders = ORDER_YMD|ORDER_MYD;
6973 dp->dwCount = 0; /* Don't return to this code path again */
6975 goto VARIANT_MakeDate_Start;
6978 /* No valid dates were able to be constructed */
6979 return DISP_E_TYPEMISMATCH;
6981 VARIANT_MakeDate_OK:
6983 /* Check that the time part is ok */
6984 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
6985 return DISP_E_TYPEMISMATCH;
6987 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
6988 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
6990 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
6992 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
6996 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
6997 * be retrieved from:
6998 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
6999 * But Wine doesn't have/use that key as at the time of writing.
7001 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
7002 TRACE("Returning date %ld/%ld/%d\n", v1, v2, st->wYear);
7006 /******************************************************************************
7007 * VarDateFromStr [OLEAUT32.94]
7009 * Convert a VT_BSTR to at VT_DATE.
7012 * strIn [I] String to convert
7013 * lcid [I] Locale identifier for the conversion
7014 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7015 * pdateOut [O] Destination for the converted value
7018 * Success: S_OK. pdateOut contains the converted value.
7019 * FAILURE: An HRESULT error code indicating the prolem.
7022 * Any date format that can be created using the date formats from lcid
7023 * (Either from kernel Nls functions, variant conversion or formatting) is a
7024 * valid input to this function. In addition, a few more esoteric formats are
7025 * also supported for compatibility with the native version. The date is
7026 * interpreted according to the date settings in the control panel, unless
7027 * the date is invalid in that format, in which the most compatible format
7028 * that produces a valid date will be used.
7030 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7032 static const USHORT ParseDateTokens[] =
7034 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7035 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7036 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7037 LOCALE_SMONTHNAME13,
7038 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7039 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7040 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7041 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7042 LOCALE_SABBREVMONTHNAME13,
7043 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7044 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7045 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7046 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7047 LOCALE_SABBREVDAYNAME7,
7048 LOCALE_S1159, LOCALE_S2359
7050 static const BYTE ParseDateMonths[] =
7052 1,2,3,4,5,6,7,8,9,10,11,12,13,
7053 1,2,3,4,5,6,7,8,9,10,11,12,13
7056 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
7058 DWORD dwDateSeps = 0, iDate = 0;
7059 HRESULT hRet = S_OK;
7061 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7062 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7063 return E_INVALIDARG;
7066 return DISP_E_TYPEMISMATCH;
7070 TRACE("(%s,0x%08lx,0x%08lx,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7072 memset(&dp, 0, sizeof(dp));
7074 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7075 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7076 TRACE("iDate is %ld\n", iDate);
7078 /* Get the month/day/am/pm tokens for this locale */
7079 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7082 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7084 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7085 * GetAltMonthNames(). We should really cache these strings too.
7088 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
7089 tokens[i] = SysAllocString(buff);
7090 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7093 /* Parse the string into our structure */
7099 if (isdigitW(*strIn))
7101 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
7105 else if (isalpha(*strIn))
7107 BOOL bFound = FALSE;
7109 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7111 DWORD dwLen = strlenW(tokens[i]);
7112 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
7116 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7117 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7122 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7123 hRet = DISP_E_TYPEMISMATCH;
7126 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7127 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7130 strIn += (dwLen - 1);
7138 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7139 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7141 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7142 if (*strIn == 'a' || *strIn == 'A')
7144 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7145 dp.dwParseFlags |= DP_AM;
7149 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7150 dp.dwParseFlags |= DP_PM;
7156 TRACE("No matching token for %s\n", debugstr_w(strIn));
7157 hRet = DISP_E_TYPEMISMATCH;
7162 else if (*strIn == ':' || *strIn == '.')
7164 if (!dp.dwCount || !strIn[1])
7165 hRet = DISP_E_TYPEMISMATCH;
7167 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7169 else if (*strIn == '-' || *strIn == '/')
7172 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7173 hRet = DISP_E_TYPEMISMATCH;
7175 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7177 else if (*strIn == ',' || isspaceW(*strIn))
7179 if (*strIn == ',' && !strIn[1])
7180 hRet = DISP_E_TYPEMISMATCH;
7184 hRet = DISP_E_TYPEMISMATCH;
7189 if (!dp.dwCount || dp.dwCount > 6 ||
7190 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7191 hRet = DISP_E_TYPEMISMATCH;
7193 if (SUCCEEDED(hRet))
7196 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7198 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7200 /* Figure out which numbers correspond to which fields.
7202 * This switch statement works based on the fact that native interprets any
7203 * fields that are not joined with a time separator ('.' or ':') as date
7204 * fields. Thus we construct a value from 0-32 where each set bit indicates
7205 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7206 * For valid permutations, we set dwOffset to point to the first date field
7207 * and shorten dp.dwCount by the number of time fields found. The real
7208 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7209 * each date number must represent in the context of iDate.
7211 TRACE("0x%08lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7213 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7215 case 0x1: /* TT TTDD TTDDD */
7216 if (dp.dwCount > 3 &&
7217 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7218 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7219 hRet = DISP_E_TYPEMISMATCH;
7220 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7221 hRet = DISP_E_TYPEMISMATCH;
7222 st.wHour = dp.dwValues[0];
7223 st.wMinute = dp.dwValues[1];
7228 case 0x3: /* TTT TTTDD TTTDDD */
7229 if (dp.dwCount > 4 &&
7230 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7231 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7232 hRet = DISP_E_TYPEMISMATCH;
7233 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7234 hRet = DISP_E_TYPEMISMATCH;
7235 st.wHour = dp.dwValues[0];
7236 st.wMinute = dp.dwValues[1];
7237 st.wSecond = dp.dwValues[2];
7242 case 0x4: /* DDTT */
7243 if (dp.dwCount != 4 ||
7244 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7245 hRet = DISP_E_TYPEMISMATCH;
7247 st.wHour = dp.dwValues[2];
7248 st.wMinute = dp.dwValues[3];
7252 case 0x0: /* T DD DDD TDDD TDDD */
7253 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7255 st.wHour = dp.dwValues[0]; /* T */
7259 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7261 hRet = DISP_E_TYPEMISMATCH;
7263 else if (dp.dwCount == 3)
7265 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7268 st.wHour = dp.dwValues[0];
7272 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7275 st.wHour = dp.dwValues[2];
7278 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7279 hRet = DISP_E_TYPEMISMATCH;
7281 else if (dp.dwCount == 4)
7284 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7286 st.wHour = dp.dwValues[0];
7289 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7291 st.wHour = dp.dwValues[3];
7294 hRet = DISP_E_TYPEMISMATCH;
7297 /* .. fall through .. */
7299 case 0x8: /* DDDTT */
7300 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7301 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7302 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7303 dp.dwCount == 4 || dp.dwCount == 6)
7304 hRet = DISP_E_TYPEMISMATCH;
7305 st.wHour = dp.dwValues[3];
7306 st.wMinute = dp.dwValues[4];
7307 if (dp.dwCount == 5)
7311 case 0xC: /* DDTTT */
7312 if (dp.dwCount != 5 ||
7313 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7314 hRet = DISP_E_TYPEMISMATCH;
7315 st.wHour = dp.dwValues[2];
7316 st.wMinute = dp.dwValues[3];
7317 st.wSecond = dp.dwValues[4];
7321 case 0x18: /* DDDTTT */
7322 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7323 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7324 hRet = DISP_E_TYPEMISMATCH;
7325 st.wHour = dp.dwValues[3];
7326 st.wMinute = dp.dwValues[4];
7327 st.wSecond = dp.dwValues[5];
7332 hRet = DISP_E_TYPEMISMATCH;
7336 if (SUCCEEDED(hRet))
7338 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7340 if (dwFlags & VAR_TIMEVALUEONLY)
7346 else if (dwFlags & VAR_DATEVALUEONLY)
7347 st.wHour = st.wMinute = st.wSecond = 0;
7349 /* Finally, convert the value to a VT_DATE */
7350 if (SUCCEEDED(hRet))
7351 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7355 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7356 SysFreeString(tokens[i]);
7360 /******************************************************************************
7361 * VarDateFromI1 (OLEAUT32.221)
7363 * Convert a VT_I1 to a VT_DATE.
7367 * pdateOut [O] Destination
7372 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7374 return VarR8FromI1(cIn, pdateOut);
7377 /******************************************************************************
7378 * VarDateFromUI2 (OLEAUT32.222)
7380 * Convert a VT_UI2 to a VT_DATE.
7384 * pdateOut [O] Destination
7389 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7391 return VarR8FromUI2(uiIn, pdateOut);
7394 /******************************************************************************
7395 * VarDateFromUI4 (OLEAUT32.223)
7397 * Convert a VT_UI4 to a VT_DATE.
7401 * pdateOut [O] Destination
7406 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7408 return VarDateFromR8(ulIn, pdateOut);
7411 /**********************************************************************
7412 * VarDateFromDec (OLEAUT32.224)
7414 * Convert a VT_DECIMAL to a VT_DATE.
7418 * pdateOut [O] Destination
7423 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
7425 return VarR8FromDec(pdecIn, pdateOut);
7428 /******************************************************************************
7429 * VarDateFromI8 (OLEAUT32.364)
7431 * Convert a VT_I8 to a VT_DATE.
7435 * pdateOut [O] Destination
7439 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7441 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
7443 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
7444 *pdateOut = (DATE)llIn;
7448 /******************************************************************************
7449 * VarDateFromUI8 (OLEAUT32.365)
7451 * Convert a VT_UI8 to a VT_DATE.
7455 * pdateOut [O] Destination
7459 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7461 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
7463 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
7464 *pdateOut = (DATE)ullIn;