2 * Low level variant functions
4 * Copyright 2003 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
25 #include "wine/debug.h"
26 #include "wine/unicode.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(variant
);
35 extern HMODULE hProxyDll DECLSPEC_HIDDEN
;
37 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
38 #define CY_MULTIPLIER_F 10000.0
39 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
40 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
42 static const WCHAR szFloatFormatW
[] = { '%','.','7','G','\0' };
43 static const WCHAR szDoubleFormatW
[] = { '%','.','1','5','G','\0' };
45 /* Copy data from one variant to another. */
46 static inline void VARIANT_CopyData(const VARIANT
*srcVar
, VARTYPE vt
, void *pOut
)
51 case VT_UI1
: memcpy(pOut
, &V_UI1(srcVar
), sizeof(BYTE
)); break;
54 case VT_UI2
: memcpy(pOut
, &V_UI2(srcVar
), sizeof(SHORT
)); break;
59 case VT_UI4
: memcpy(pOut
, &V_UI4(srcVar
), sizeof (LONG
)); break;
64 case VT_UI8
: memcpy(pOut
, &V_UI8(srcVar
), sizeof (LONG64
)); break;
65 case VT_INT_PTR
: memcpy(pOut
, &V_INT_PTR(srcVar
), sizeof (INT_PTR
)); break;
66 case VT_DECIMAL
: memcpy(pOut
, &V_DECIMAL(srcVar
), sizeof (DECIMAL
)); break;
67 case VT_BSTR
: memcpy(pOut
, &V_BSTR(srcVar
), sizeof(BSTR
)); break;
69 FIXME("VT_ type %d unhandled, please report!\n", vt
);
73 /* Macro to inline conversion from a float or double to any integer type,
74 * rounding according to the 'dutch' convention.
76 #define VARIANT_DutchRound(typ, value, res) do { \
77 double whole = value < 0 ? ceil(value) : floor(value); \
78 double fract = value - whole; \
79 if (fract > 0.5) res = (typ)whole + (typ)1; \
80 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
81 else if (fract >= 0.0) res = (typ)whole; \
82 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
83 else if (fract > -0.5) res = (typ)whole; \
84 else res = (typ)whole - (typ)1; \
88 /* Coerce VT_BSTR to a numeric type */
89 static HRESULT
VARIANT_NumberFromBstr(OLECHAR
* pStrIn
, LCID lcid
, ULONG ulFlags
,
90 void* pOut
, VARTYPE vt
)
97 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
98 np
.cDig
= sizeof(rgb
) / sizeof(BYTE
);
99 np
.dwInFlags
= NUMPRS_STD
;
101 hRet
= VarParseNumFromStr(pStrIn
, lcid
, ulFlags
, &np
, rgb
);
105 /* 1 << vt gives us the VTBIT constant for the destination number type */
106 hRet
= VarNumFromParseNum(&np
, rgb
, 1 << vt
, &dstVar
);
108 VARIANT_CopyData(&dstVar
, vt
, pOut
);
113 /* Coerce VT_DISPATCH to another type */
114 static HRESULT
VARIANT_FromDisp(IDispatch
* pdispIn
, LCID lcid
, void* pOut
,
115 VARTYPE vt
, DWORD dwFlags
)
117 static DISPPARAMS emptyParams
= { NULL
, NULL
, 0, 0 };
118 VARIANTARG srcVar
, dstVar
;
122 return DISP_E_BADVARTYPE
;
124 /* Get the default 'value' property from the IDispatch */
125 hRet
= IDispatch_Invoke(pdispIn
, DISPID_VALUE
, &IID_NULL
, lcid
, DISPATCH_PROPERTYGET
,
126 &emptyParams
, &srcVar
, NULL
, NULL
);
130 /* Convert the property to the requested type */
131 V_VT(&dstVar
) = VT_EMPTY
;
132 hRet
= VariantChangeTypeEx(&dstVar
, &srcVar
, lcid
, dwFlags
, vt
);
133 VariantClear(&srcVar
);
137 VARIANT_CopyData(&dstVar
, vt
, pOut
);
138 VariantClear(&srcVar
);
142 hRet
= DISP_E_TYPEMISMATCH
;
146 /* Inline return type */
147 #define RETTYP static inline HRESULT
150 /* Simple compiler cast from one type to another */
151 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
152 *out = in; return S_OK; }
154 /* Compiler cast where input cannot be negative */
155 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
156 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
158 /* Compiler cast where input cannot be > some number */
159 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
160 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
162 /* Compiler cast where input cannot be < some number or >= some other number */
163 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
164 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
167 POSTST(signed char, BYTE
, VarI1FromUI1
, I1_MAX
)
168 BOTHTST(signed char, SHORT
, VarI1FromI2
, I1_MIN
, I1_MAX
)
169 BOTHTST(signed char, LONG
, VarI1FromI4
, I1_MIN
, I1_MAX
)
170 SIMPLE(signed char, VARIANT_BOOL
, VarI1FromBool
)
171 POSTST(signed char, USHORT
, VarI1FromUI2
, I1_MAX
)
172 POSTST(signed char, ULONG
, VarI1FromUI4
, I1_MAX
)
173 BOTHTST(signed char, LONG64
, VarI1FromI8
, I1_MIN
, I1_MAX
)
174 POSTST(signed char, ULONG64
, VarI1FromUI8
, I1_MAX
)
177 BOTHTST(BYTE
, SHORT
, VarUI1FromI2
, UI1_MIN
, UI1_MAX
)
178 SIMPLE(BYTE
, VARIANT_BOOL
, VarUI1FromBool
)
179 NEGTST(BYTE
, signed char, VarUI1FromI1
)
180 POSTST(BYTE
, USHORT
, VarUI1FromUI2
, UI1_MAX
)
181 BOTHTST(BYTE
, LONG
, VarUI1FromI4
, UI1_MIN
, UI1_MAX
)
182 POSTST(BYTE
, ULONG
, VarUI1FromUI4
, UI1_MAX
)
183 BOTHTST(BYTE
, LONG64
, VarUI1FromI8
, UI1_MIN
, UI1_MAX
)
184 POSTST(BYTE
, ULONG64
, VarUI1FromUI8
, UI1_MAX
)
187 SIMPLE(SHORT
, BYTE
, VarI2FromUI1
)
188 BOTHTST(SHORT
, LONG
, VarI2FromI4
, I2_MIN
, I2_MAX
)
189 SIMPLE(SHORT
, VARIANT_BOOL
, VarI2FromBool
)
190 SIMPLE(SHORT
, signed char, VarI2FromI1
)
191 POSTST(SHORT
, USHORT
, VarI2FromUI2
, I2_MAX
)
192 POSTST(SHORT
, ULONG
, VarI2FromUI4
, I2_MAX
)
193 BOTHTST(SHORT
, LONG64
, VarI2FromI8
, I2_MIN
, I2_MAX
)
194 POSTST(SHORT
, ULONG64
, VarI2FromUI8
, I2_MAX
)
197 SIMPLE(USHORT
, BYTE
, VarUI2FromUI1
)
198 NEGTST(USHORT
, SHORT
, VarUI2FromI2
)
199 BOTHTST(USHORT
, LONG
, VarUI2FromI4
, UI2_MIN
, UI2_MAX
)
200 SIMPLE(USHORT
, VARIANT_BOOL
, VarUI2FromBool
)
201 NEGTST(USHORT
, signed char, VarUI2FromI1
)
202 POSTST(USHORT
, ULONG
, VarUI2FromUI4
, UI2_MAX
)
203 BOTHTST(USHORT
, LONG64
, VarUI2FromI8
, UI2_MIN
, UI2_MAX
)
204 POSTST(USHORT
, ULONG64
, VarUI2FromUI8
, UI2_MAX
)
207 SIMPLE(LONG
, BYTE
, VarI4FromUI1
)
208 SIMPLE(LONG
, SHORT
, VarI4FromI2
)
209 SIMPLE(LONG
, VARIANT_BOOL
, VarI4FromBool
)
210 SIMPLE(LONG
, signed char, VarI4FromI1
)
211 SIMPLE(LONG
, USHORT
, VarI4FromUI2
)
212 POSTST(LONG
, ULONG
, VarI4FromUI4
, I4_MAX
)
213 BOTHTST(LONG
, LONG64
, VarI4FromI8
, I4_MIN
, I4_MAX
)
214 POSTST(LONG
, ULONG64
, VarI4FromUI8
, I4_MAX
)
217 SIMPLE(ULONG
, BYTE
, VarUI4FromUI1
)
218 NEGTST(ULONG
, SHORT
, VarUI4FromI2
)
219 NEGTST(ULONG
, LONG
, VarUI4FromI4
)
220 SIMPLE(ULONG
, VARIANT_BOOL
, VarUI4FromBool
)
221 NEGTST(ULONG
, signed char, VarUI4FromI1
)
222 SIMPLE(ULONG
, USHORT
, VarUI4FromUI2
)
223 BOTHTST(ULONG
, LONG64
, VarUI4FromI8
, UI4_MIN
, UI4_MAX
)
224 POSTST(ULONG
, ULONG64
, VarUI4FromUI8
, UI4_MAX
)
227 SIMPLE(LONG64
, BYTE
, VarI8FromUI1
)
228 SIMPLE(LONG64
, SHORT
, VarI8FromI2
)
229 SIMPLE(LONG64
, signed char, VarI8FromI1
)
230 SIMPLE(LONG64
, USHORT
, VarI8FromUI2
)
231 SIMPLE(LONG64
, ULONG
, VarI8FromUI4
)
232 POSTST(LONG64
, ULONG64
, VarI8FromUI8
, I8_MAX
)
235 SIMPLE(ULONG64
, BYTE
, VarUI8FromUI1
)
236 NEGTST(ULONG64
, SHORT
, VarUI8FromI2
)
237 NEGTST(ULONG64
, signed char, VarUI8FromI1
)
238 SIMPLE(ULONG64
, USHORT
, VarUI8FromUI2
)
239 SIMPLE(ULONG64
, ULONG
, VarUI8FromUI4
)
240 NEGTST(ULONG64
, LONG64
, VarUI8FromI8
)
243 SIMPLE(float, BYTE
, VarR4FromUI1
)
244 SIMPLE(float, SHORT
, VarR4FromI2
)
245 SIMPLE(float, signed char, VarR4FromI1
)
246 SIMPLE(float, USHORT
, VarR4FromUI2
)
247 SIMPLE(float, LONG
, VarR4FromI4
)
248 SIMPLE(float, ULONG
, VarR4FromUI4
)
249 SIMPLE(float, LONG64
, VarR4FromI8
)
250 SIMPLE(float, ULONG64
, VarR4FromUI8
)
253 SIMPLE(double, BYTE
, VarR8FromUI1
)
254 SIMPLE(double, SHORT
, VarR8FromI2
)
255 SIMPLE(double, float, VarR8FromR4
)
256 RETTYP
_VarR8FromCy(CY i
, double* o
) { *o
= (double)i
.int64
/ CY_MULTIPLIER_F
; return S_OK
; }
257 SIMPLE(double, DATE
, VarR8FromDate
)
258 SIMPLE(double, signed char, VarR8FromI1
)
259 SIMPLE(double, USHORT
, VarR8FromUI2
)
260 SIMPLE(double, LONG
, VarR8FromI4
)
261 SIMPLE(double, ULONG
, VarR8FromUI4
)
262 SIMPLE(double, LONG64
, VarR8FromI8
)
263 SIMPLE(double, ULONG64
, VarR8FromUI8
)
269 /************************************************************************
270 * VarI1FromUI1 (OLEAUT32.244)
272 * Convert a VT_UI1 to a VT_I1.
276 * pcOut [O] Destination
280 * Failure: E_INVALIDARG, if the source value is invalid
281 * DISP_E_OVERFLOW, if the value will not fit in the destination
283 HRESULT WINAPI
VarI1FromUI1(BYTE bIn
, signed char* pcOut
)
285 return _VarI1FromUI1(bIn
, pcOut
);
288 /************************************************************************
289 * VarI1FromI2 (OLEAUT32.245)
291 * Convert a VT_I2 to a VT_I1.
295 * pcOut [O] Destination
299 * Failure: E_INVALIDARG, if the source value is invalid
300 * DISP_E_OVERFLOW, if the value will not fit in the destination
302 HRESULT WINAPI
VarI1FromI2(SHORT sIn
, signed char* pcOut
)
304 return _VarI1FromI2(sIn
, pcOut
);
307 /************************************************************************
308 * VarI1FromI4 (OLEAUT32.246)
310 * Convert a VT_I4 to a VT_I1.
314 * pcOut [O] Destination
318 * Failure: E_INVALIDARG, if the source value is invalid
319 * DISP_E_OVERFLOW, if the value will not fit in the destination
321 HRESULT WINAPI
VarI1FromI4(LONG iIn
, signed char* pcOut
)
323 return _VarI1FromI4(iIn
, pcOut
);
326 /************************************************************************
327 * VarI1FromR4 (OLEAUT32.247)
329 * Convert a VT_R4 to a VT_I1.
333 * pcOut [O] Destination
337 * Failure: E_INVALIDARG, if the source value is invalid
338 * DISP_E_OVERFLOW, if the value will not fit in the destination
340 HRESULT WINAPI
VarI1FromR4(FLOAT fltIn
, signed char* pcOut
)
342 return VarI1FromR8(fltIn
, pcOut
);
345 /************************************************************************
346 * VarI1FromR8 (OLEAUT32.248)
348 * Convert a VT_R8 to a VT_I1.
352 * pcOut [O] Destination
356 * Failure: E_INVALIDARG, if the source value is invalid
357 * DISP_E_OVERFLOW, if the value will not fit in the destination
360 * See VarI8FromR8() for details concerning rounding.
362 HRESULT WINAPI
VarI1FromR8(double dblIn
, signed char* pcOut
)
364 if (dblIn
< (double)I1_MIN
|| dblIn
> (double)I1_MAX
)
365 return DISP_E_OVERFLOW
;
366 VARIANT_DutchRound(CHAR
, dblIn
, *pcOut
);
370 /************************************************************************
371 * VarI1FromDate (OLEAUT32.249)
373 * Convert a VT_DATE to a VT_I1.
377 * pcOut [O] Destination
381 * Failure: E_INVALIDARG, if the source value is invalid
382 * DISP_E_OVERFLOW, if the value will not fit in the destination
384 HRESULT WINAPI
VarI1FromDate(DATE dateIn
, signed char* pcOut
)
386 return VarI1FromR8(dateIn
, pcOut
);
389 /************************************************************************
390 * VarI1FromCy (OLEAUT32.250)
392 * Convert a VT_CY to a VT_I1.
396 * pcOut [O] Destination
400 * Failure: E_INVALIDARG, if the source value is invalid
401 * DISP_E_OVERFLOW, if the value will not fit in the destination
403 HRESULT WINAPI
VarI1FromCy(CY cyIn
, signed char* pcOut
)
407 VarI4FromCy(cyIn
, &i
);
408 return _VarI1FromI4(i
, pcOut
);
411 /************************************************************************
412 * VarI1FromStr (OLEAUT32.251)
414 * Convert a VT_BSTR to a VT_I1.
418 * lcid [I] LCID for the conversion
419 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
420 * pcOut [O] Destination
424 * Failure: E_INVALIDARG, if the source value is invalid
425 * DISP_E_OVERFLOW, if the value will not fit in the destination
426 * DISP_E_TYPEMISMATCH, if the type cannot be converted
428 HRESULT WINAPI
VarI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, signed char* pcOut
)
430 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pcOut
, VT_I1
);
433 /************************************************************************
434 * VarI1FromDisp (OLEAUT32.252)
436 * Convert a VT_DISPATCH to a VT_I1.
440 * lcid [I] LCID for conversion
441 * pcOut [O] Destination
445 * Failure: E_INVALIDARG, if the source value is invalid
446 * DISP_E_OVERFLOW, if the value will not fit in the destination
447 * DISP_E_TYPEMISMATCH, if the type cannot be converted
449 HRESULT WINAPI
VarI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, signed char* pcOut
)
451 return VARIANT_FromDisp(pdispIn
, lcid
, pcOut
, VT_I1
, 0);
454 /************************************************************************
455 * VarI1FromBool (OLEAUT32.253)
457 * Convert a VT_BOOL to a VT_I1.
461 * pcOut [O] Destination
466 HRESULT WINAPI
VarI1FromBool(VARIANT_BOOL boolIn
, signed char* pcOut
)
468 return _VarI1FromBool(boolIn
, pcOut
);
471 /************************************************************************
472 * VarI1FromUI2 (OLEAUT32.254)
474 * Convert a VT_UI2 to a VT_I1.
478 * pcOut [O] Destination
482 * Failure: E_INVALIDARG, if the source value is invalid
483 * DISP_E_OVERFLOW, if the value will not fit in the destination
485 HRESULT WINAPI
VarI1FromUI2(USHORT usIn
, signed char* pcOut
)
487 return _VarI1FromUI2(usIn
, pcOut
);
490 /************************************************************************
491 * VarI1FromUI4 (OLEAUT32.255)
493 * Convert a VT_UI4 to a VT_I1.
497 * pcOut [O] Destination
501 * Failure: E_INVALIDARG, if the source value is invalid
502 * DISP_E_OVERFLOW, if the value will not fit in the destination
503 * DISP_E_TYPEMISMATCH, if the type cannot be converted
505 HRESULT WINAPI
VarI1FromUI4(ULONG ulIn
, signed char* pcOut
)
507 return _VarI1FromUI4(ulIn
, pcOut
);
510 /************************************************************************
511 * VarI1FromDec (OLEAUT32.256)
513 * Convert a VT_DECIMAL to a VT_I1.
517 * pcOut [O] Destination
521 * Failure: E_INVALIDARG, if the source value is invalid
522 * DISP_E_OVERFLOW, if the value will not fit in the destination
524 HRESULT WINAPI
VarI1FromDec(DECIMAL
*pdecIn
, signed char* pcOut
)
529 hRet
= VarI8FromDec(pdecIn
, &i64
);
532 hRet
= _VarI1FromI8(i64
, pcOut
);
536 /************************************************************************
537 * VarI1FromI8 (OLEAUT32.376)
539 * Convert a VT_I8 to a VT_I1.
543 * pcOut [O] Destination
547 * Failure: E_INVALIDARG, if the source value is invalid
548 * DISP_E_OVERFLOW, if the value will not fit in the destination
550 HRESULT WINAPI
VarI1FromI8(LONG64 llIn
, signed char* pcOut
)
552 return _VarI1FromI8(llIn
, pcOut
);
555 /************************************************************************
556 * VarI1FromUI8 (OLEAUT32.377)
558 * Convert a VT_UI8 to a VT_I1.
562 * pcOut [O] Destination
566 * Failure: E_INVALIDARG, if the source value is invalid
567 * DISP_E_OVERFLOW, if the value will not fit in the destination
569 HRESULT WINAPI
VarI1FromUI8(ULONG64 ullIn
, signed char* pcOut
)
571 return _VarI1FromUI8(ullIn
, pcOut
);
577 /************************************************************************
578 * VarUI1FromI2 (OLEAUT32.130)
580 * Convert a VT_I2 to a VT_UI1.
584 * pbOut [O] Destination
588 * Failure: E_INVALIDARG, if the source value is invalid
589 * DISP_E_OVERFLOW, if the value will not fit in the destination
591 HRESULT WINAPI
VarUI1FromI2(SHORT sIn
, BYTE
* pbOut
)
593 return _VarUI1FromI2(sIn
, pbOut
);
596 /************************************************************************
597 * VarUI1FromI4 (OLEAUT32.131)
599 * Convert a VT_I4 to a VT_UI1.
603 * pbOut [O] Destination
607 * Failure: E_INVALIDARG, if the source value is invalid
608 * DISP_E_OVERFLOW, if the value will not fit in the destination
610 HRESULT WINAPI
VarUI1FromI4(LONG iIn
, BYTE
* pbOut
)
612 return _VarUI1FromI4(iIn
, pbOut
);
615 /************************************************************************
616 * VarUI1FromR4 (OLEAUT32.132)
618 * Convert a VT_R4 to a VT_UI1.
622 * pbOut [O] Destination
626 * Failure: E_INVALIDARG, if the source value is invalid
627 * DISP_E_OVERFLOW, if the value will not fit in the destination
628 * DISP_E_TYPEMISMATCH, if the type cannot be converted
630 HRESULT WINAPI
VarUI1FromR4(FLOAT fltIn
, BYTE
* pbOut
)
632 return VarUI1FromR8(fltIn
, pbOut
);
635 /************************************************************************
636 * VarUI1FromR8 (OLEAUT32.133)
638 * Convert a VT_R8 to a VT_UI1.
642 * pbOut [O] Destination
646 * Failure: E_INVALIDARG, if the source value is invalid
647 * DISP_E_OVERFLOW, if the value will not fit in the destination
650 * See VarI8FromR8() for details concerning rounding.
652 HRESULT WINAPI
VarUI1FromR8(double dblIn
, BYTE
* pbOut
)
654 if (dblIn
< -0.5 || dblIn
> (double)UI1_MAX
)
655 return DISP_E_OVERFLOW
;
656 VARIANT_DutchRound(BYTE
, dblIn
, *pbOut
);
660 /************************************************************************
661 * VarUI1FromCy (OLEAUT32.134)
663 * Convert a VT_CY to a VT_UI1.
667 * pbOut [O] Destination
671 * Failure: E_INVALIDARG, if the source value is invalid
672 * DISP_E_OVERFLOW, if the value will not fit in the destination
675 * Negative values >= -5000 will be converted to 0.
677 HRESULT WINAPI
VarUI1FromCy(CY cyIn
, BYTE
* pbOut
)
679 ULONG i
= UI1_MAX
+ 1;
681 VarUI4FromCy(cyIn
, &i
);
682 return _VarUI1FromUI4(i
, pbOut
);
685 /************************************************************************
686 * VarUI1FromDate (OLEAUT32.135)
688 * Convert a VT_DATE to a VT_UI1.
692 * pbOut [O] Destination
696 * Failure: E_INVALIDARG, if the source value is invalid
697 * DISP_E_OVERFLOW, if the value will not fit in the destination
699 HRESULT WINAPI
VarUI1FromDate(DATE dateIn
, BYTE
* pbOut
)
701 return VarUI1FromR8(dateIn
, pbOut
);
704 /************************************************************************
705 * VarUI1FromStr (OLEAUT32.136)
707 * Convert a VT_BSTR to a VT_UI1.
711 * lcid [I] LCID for the conversion
712 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
713 * pbOut [O] Destination
717 * Failure: E_INVALIDARG, if the source value is invalid
718 * DISP_E_OVERFLOW, if the value will not fit in the destination
719 * DISP_E_TYPEMISMATCH, if the type cannot be converted
721 HRESULT WINAPI
VarUI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, BYTE
* pbOut
)
723 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pbOut
, VT_UI1
);
726 /************************************************************************
727 * VarUI1FromDisp (OLEAUT32.137)
729 * Convert a VT_DISPATCH to a VT_UI1.
733 * lcid [I] LCID for conversion
734 * pbOut [O] Destination
738 * Failure: E_INVALIDARG, if the source value is invalid
739 * DISP_E_OVERFLOW, if the value will not fit in the destination
740 * DISP_E_TYPEMISMATCH, if the type cannot be converted
742 HRESULT WINAPI
VarUI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, BYTE
* pbOut
)
744 return VARIANT_FromDisp(pdispIn
, lcid
, pbOut
, VT_UI1
, 0);
747 /************************************************************************
748 * VarUI1FromBool (OLEAUT32.138)
750 * Convert a VT_BOOL to a VT_UI1.
754 * pbOut [O] Destination
759 HRESULT WINAPI
VarUI1FromBool(VARIANT_BOOL boolIn
, BYTE
* pbOut
)
761 return _VarUI1FromBool(boolIn
, pbOut
);
764 /************************************************************************
765 * VarUI1FromI1 (OLEAUT32.237)
767 * Convert a VT_I1 to a VT_UI1.
771 * pbOut [O] Destination
775 * Failure: E_INVALIDARG, if the source value is invalid
776 * DISP_E_OVERFLOW, if the value will not fit in the destination
778 HRESULT WINAPI
VarUI1FromI1(signed char cIn
, BYTE
* pbOut
)
780 return _VarUI1FromI1(cIn
, pbOut
);
783 /************************************************************************
784 * VarUI1FromUI2 (OLEAUT32.238)
786 * Convert a VT_UI2 to a VT_UI1.
790 * pbOut [O] Destination
794 * Failure: E_INVALIDARG, if the source value is invalid
795 * DISP_E_OVERFLOW, if the value will not fit in the destination
797 HRESULT WINAPI
VarUI1FromUI2(USHORT usIn
, BYTE
* pbOut
)
799 return _VarUI1FromUI2(usIn
, pbOut
);
802 /************************************************************************
803 * VarUI1FromUI4 (OLEAUT32.239)
805 * Convert a VT_UI4 to a VT_UI1.
809 * pbOut [O] Destination
813 * Failure: E_INVALIDARG, if the source value is invalid
814 * DISP_E_OVERFLOW, if the value will not fit in the destination
816 HRESULT WINAPI
VarUI1FromUI4(ULONG ulIn
, BYTE
* pbOut
)
818 return _VarUI1FromUI4(ulIn
, pbOut
);
821 /************************************************************************
822 * VarUI1FromDec (OLEAUT32.240)
824 * Convert a VT_DECIMAL to a VT_UI1.
828 * pbOut [O] Destination
832 * Failure: E_INVALIDARG, if the source value is invalid
833 * DISP_E_OVERFLOW, if the value will not fit in the destination
835 HRESULT WINAPI
VarUI1FromDec(DECIMAL
*pdecIn
, BYTE
* pbOut
)
840 hRet
= VarI8FromDec(pdecIn
, &i64
);
843 hRet
= _VarUI1FromI8(i64
, pbOut
);
847 /************************************************************************
848 * VarUI1FromI8 (OLEAUT32.372)
850 * Convert a VT_I8 to a VT_UI1.
854 * pbOut [O] Destination
858 * Failure: E_INVALIDARG, if the source value is invalid
859 * DISP_E_OVERFLOW, if the value will not fit in the destination
861 HRESULT WINAPI
VarUI1FromI8(LONG64 llIn
, BYTE
* pbOut
)
863 return _VarUI1FromI8(llIn
, pbOut
);
866 /************************************************************************
867 * VarUI1FromUI8 (OLEAUT32.373)
869 * Convert a VT_UI8 to a VT_UI1.
873 * pbOut [O] Destination
877 * Failure: E_INVALIDARG, if the source value is invalid
878 * DISP_E_OVERFLOW, if the value will not fit in the destination
880 HRESULT WINAPI
VarUI1FromUI8(ULONG64 ullIn
, BYTE
* pbOut
)
882 return _VarUI1FromUI8(ullIn
, pbOut
);
889 /************************************************************************
890 * VarI2FromUI1 (OLEAUT32.48)
892 * Convert a VT_UI2 to a VT_I2.
896 * psOut [O] Destination
901 HRESULT WINAPI
VarI2FromUI1(BYTE bIn
, SHORT
* psOut
)
903 return _VarI2FromUI1(bIn
, psOut
);
906 /************************************************************************
907 * VarI2FromI4 (OLEAUT32.49)
909 * Convert a VT_I4 to a VT_I2.
913 * psOut [O] Destination
917 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
919 HRESULT WINAPI
VarI2FromI4(LONG iIn
, SHORT
* psOut
)
921 return _VarI2FromI4(iIn
, psOut
);
924 /************************************************************************
925 * VarI2FromR4 (OLEAUT32.50)
927 * Convert a VT_R4 to a VT_I2.
931 * psOut [O] Destination
935 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
937 HRESULT WINAPI
VarI2FromR4(FLOAT fltIn
, SHORT
* psOut
)
939 return VarI2FromR8(fltIn
, psOut
);
942 /************************************************************************
943 * VarI2FromR8 (OLEAUT32.51)
945 * Convert a VT_R8 to a VT_I2.
949 * psOut [O] Destination
953 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
956 * See VarI8FromR8() for details concerning rounding.
958 HRESULT WINAPI
VarI2FromR8(double dblIn
, SHORT
* psOut
)
960 if (dblIn
< (double)I2_MIN
|| dblIn
> (double)I2_MAX
)
961 return DISP_E_OVERFLOW
;
962 VARIANT_DutchRound(SHORT
, dblIn
, *psOut
);
966 /************************************************************************
967 * VarI2FromCy (OLEAUT32.52)
969 * Convert a VT_CY to a VT_I2.
973 * psOut [O] Destination
977 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
979 HRESULT WINAPI
VarI2FromCy(CY cyIn
, SHORT
* psOut
)
983 VarI4FromCy(cyIn
, &i
);
984 return _VarI2FromI4(i
, psOut
);
987 /************************************************************************
988 * VarI2FromDate (OLEAUT32.53)
990 * Convert a VT_DATE to a VT_I2.
994 * psOut [O] Destination
998 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1000 HRESULT WINAPI
VarI2FromDate(DATE dateIn
, SHORT
* psOut
)
1002 return VarI2FromR8(dateIn
, psOut
);
1005 /************************************************************************
1006 * VarI2FromStr (OLEAUT32.54)
1008 * Convert a VT_BSTR to a VT_I2.
1012 * lcid [I] LCID for the conversion
1013 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1014 * psOut [O] Destination
1018 * Failure: E_INVALIDARG, if any parameter is invalid
1019 * DISP_E_OVERFLOW, if the value will not fit in the destination
1020 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1022 HRESULT WINAPI
VarI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, SHORT
* psOut
)
1024 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, psOut
, VT_I2
);
1027 /************************************************************************
1028 * VarI2FromDisp (OLEAUT32.55)
1030 * Convert a VT_DISPATCH to a VT_I2.
1033 * pdispIn [I] Source
1034 * lcid [I] LCID for conversion
1035 * psOut [O] Destination
1039 * Failure: E_INVALIDARG, if pdispIn is invalid,
1040 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1041 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1043 HRESULT WINAPI
VarI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, SHORT
* psOut
)
1045 return VARIANT_FromDisp(pdispIn
, lcid
, psOut
, VT_I2
, 0);
1048 /************************************************************************
1049 * VarI2FromBool (OLEAUT32.56)
1051 * Convert a VT_BOOL to a VT_I2.
1055 * psOut [O] Destination
1060 HRESULT WINAPI
VarI2FromBool(VARIANT_BOOL boolIn
, SHORT
* psOut
)
1062 return _VarI2FromBool(boolIn
, psOut
);
1065 /************************************************************************
1066 * VarI2FromI1 (OLEAUT32.205)
1068 * Convert a VT_I1 to a VT_I2.
1072 * psOut [O] Destination
1077 HRESULT WINAPI
VarI2FromI1(signed char cIn
, SHORT
* psOut
)
1079 return _VarI2FromI1(cIn
, psOut
);
1082 /************************************************************************
1083 * VarI2FromUI2 (OLEAUT32.206)
1085 * Convert a VT_UI2 to a VT_I2.
1089 * psOut [O] Destination
1093 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1095 HRESULT WINAPI
VarI2FromUI2(USHORT usIn
, SHORT
* psOut
)
1097 return _VarI2FromUI2(usIn
, psOut
);
1100 /************************************************************************
1101 * VarI2FromUI4 (OLEAUT32.207)
1103 * Convert a VT_UI4 to a VT_I2.
1107 * psOut [O] Destination
1111 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1113 HRESULT WINAPI
VarI2FromUI4(ULONG ulIn
, SHORT
* psOut
)
1115 return _VarI2FromUI4(ulIn
, psOut
);
1118 /************************************************************************
1119 * VarI2FromDec (OLEAUT32.208)
1121 * Convert a VT_DECIMAL to a VT_I2.
1125 * psOut [O] Destination
1129 * Failure: E_INVALIDARG, if the source value is invalid
1130 * DISP_E_OVERFLOW, if the value will not fit in the destination
1132 HRESULT WINAPI
VarI2FromDec(DECIMAL
*pdecIn
, SHORT
* psOut
)
1137 hRet
= VarI8FromDec(pdecIn
, &i64
);
1139 if (SUCCEEDED(hRet
))
1140 hRet
= _VarI2FromI8(i64
, psOut
);
1144 /************************************************************************
1145 * VarI2FromI8 (OLEAUT32.346)
1147 * Convert a VT_I8 to a VT_I2.
1151 * psOut [O] Destination
1155 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1157 HRESULT WINAPI
VarI2FromI8(LONG64 llIn
, SHORT
* psOut
)
1159 return _VarI2FromI8(llIn
, psOut
);
1162 /************************************************************************
1163 * VarI2FromUI8 (OLEAUT32.347)
1165 * Convert a VT_UI8 to a VT_I2.
1169 * psOut [O] Destination
1173 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1175 HRESULT WINAPI
VarI2FromUI8(ULONG64 ullIn
, SHORT
* psOut
)
1177 return _VarI2FromUI8(ullIn
, psOut
);
1183 /************************************************************************
1184 * VarUI2FromUI1 (OLEAUT32.257)
1186 * Convert a VT_UI1 to a VT_UI2.
1190 * pusOut [O] Destination
1195 HRESULT WINAPI
VarUI2FromUI1(BYTE bIn
, USHORT
* pusOut
)
1197 return _VarUI2FromUI1(bIn
, pusOut
);
1200 /************************************************************************
1201 * VarUI2FromI2 (OLEAUT32.258)
1203 * Convert a VT_I2 to a VT_UI2.
1207 * pusOut [O] Destination
1211 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1213 HRESULT WINAPI
VarUI2FromI2(SHORT sIn
, USHORT
* pusOut
)
1215 return _VarUI2FromI2(sIn
, pusOut
);
1218 /************************************************************************
1219 * VarUI2FromI4 (OLEAUT32.259)
1221 * Convert a VT_I4 to a VT_UI2.
1225 * pusOut [O] Destination
1229 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1231 HRESULT WINAPI
VarUI2FromI4(LONG iIn
, USHORT
* pusOut
)
1233 return _VarUI2FromI4(iIn
, pusOut
);
1236 /************************************************************************
1237 * VarUI2FromR4 (OLEAUT32.260)
1239 * Convert a VT_R4 to a VT_UI2.
1243 * pusOut [O] Destination
1247 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1249 HRESULT WINAPI
VarUI2FromR4(FLOAT fltIn
, USHORT
* pusOut
)
1251 return VarUI2FromR8(fltIn
, pusOut
);
1254 /************************************************************************
1255 * VarUI2FromR8 (OLEAUT32.261)
1257 * Convert a VT_R8 to a VT_UI2.
1261 * pusOut [O] Destination
1265 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1268 * See VarI8FromR8() for details concerning rounding.
1270 HRESULT WINAPI
VarUI2FromR8(double dblIn
, USHORT
* pusOut
)
1272 if (dblIn
< -0.5 || dblIn
> (double)UI2_MAX
)
1273 return DISP_E_OVERFLOW
;
1274 VARIANT_DutchRound(USHORT
, dblIn
, *pusOut
);
1278 /************************************************************************
1279 * VarUI2FromDate (OLEAUT32.262)
1281 * Convert a VT_DATE to a VT_UI2.
1285 * pusOut [O] Destination
1289 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1291 HRESULT WINAPI
VarUI2FromDate(DATE dateIn
, USHORT
* pusOut
)
1293 return VarUI2FromR8(dateIn
, pusOut
);
1296 /************************************************************************
1297 * VarUI2FromCy (OLEAUT32.263)
1299 * Convert a VT_CY to a VT_UI2.
1303 * pusOut [O] Destination
1307 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1310 * Negative values >= -5000 will be converted to 0.
1312 HRESULT WINAPI
VarUI2FromCy(CY cyIn
, USHORT
* pusOut
)
1314 ULONG i
= UI2_MAX
+ 1;
1316 VarUI4FromCy(cyIn
, &i
);
1317 return _VarUI2FromUI4(i
, pusOut
);
1320 /************************************************************************
1321 * VarUI2FromStr (OLEAUT32.264)
1323 * Convert a VT_BSTR to a VT_UI2.
1327 * lcid [I] LCID for the conversion
1328 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1329 * pusOut [O] Destination
1333 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1334 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1336 HRESULT WINAPI
VarUI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, USHORT
* pusOut
)
1338 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pusOut
, VT_UI2
);
1341 /************************************************************************
1342 * VarUI2FromDisp (OLEAUT32.265)
1344 * Convert a VT_DISPATCH to a VT_UI2.
1347 * pdispIn [I] Source
1348 * lcid [I] LCID for conversion
1349 * pusOut [O] Destination
1353 * Failure: E_INVALIDARG, if the source value is invalid
1354 * DISP_E_OVERFLOW, if the value will not fit in the destination
1355 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1357 HRESULT WINAPI
VarUI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, USHORT
* pusOut
)
1359 return VARIANT_FromDisp(pdispIn
, lcid
, pusOut
, VT_UI2
, 0);
1362 /************************************************************************
1363 * VarUI2FromBool (OLEAUT32.266)
1365 * Convert a VT_BOOL to a VT_UI2.
1369 * pusOut [O] Destination
1374 HRESULT WINAPI
VarUI2FromBool(VARIANT_BOOL boolIn
, USHORT
* pusOut
)
1376 return _VarUI2FromBool(boolIn
, pusOut
);
1379 /************************************************************************
1380 * VarUI2FromI1 (OLEAUT32.267)
1382 * Convert a VT_I1 to a VT_UI2.
1386 * pusOut [O] Destination
1390 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1392 HRESULT WINAPI
VarUI2FromI1(signed char cIn
, USHORT
* pusOut
)
1394 return _VarUI2FromI1(cIn
, pusOut
);
1397 /************************************************************************
1398 * VarUI2FromUI4 (OLEAUT32.268)
1400 * Convert a VT_UI4 to a VT_UI2.
1404 * pusOut [O] Destination
1408 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1410 HRESULT WINAPI
VarUI2FromUI4(ULONG ulIn
, USHORT
* pusOut
)
1412 return _VarUI2FromUI4(ulIn
, pusOut
);
1415 /************************************************************************
1416 * VarUI2FromDec (OLEAUT32.269)
1418 * Convert a VT_DECIMAL to a VT_UI2.
1422 * pusOut [O] Destination
1426 * Failure: E_INVALIDARG, if the source value is invalid
1427 * DISP_E_OVERFLOW, if the value will not fit in the destination
1429 HRESULT WINAPI
VarUI2FromDec(DECIMAL
*pdecIn
, USHORT
* pusOut
)
1434 hRet
= VarI8FromDec(pdecIn
, &i64
);
1436 if (SUCCEEDED(hRet
))
1437 hRet
= _VarUI2FromI8(i64
, pusOut
);
1441 /************************************************************************
1442 * VarUI2FromI8 (OLEAUT32.378)
1444 * Convert a VT_I8 to a VT_UI2.
1448 * pusOut [O] Destination
1452 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1454 HRESULT WINAPI
VarUI2FromI8(LONG64 llIn
, USHORT
* pusOut
)
1456 return _VarUI2FromI8(llIn
, pusOut
);
1459 /************************************************************************
1460 * VarUI2FromUI8 (OLEAUT32.379)
1462 * Convert a VT_UI8 to a VT_UI2.
1466 * pusOut [O] Destination
1470 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1472 HRESULT WINAPI
VarUI2FromUI8(ULONG64 ullIn
, USHORT
* pusOut
)
1474 return _VarUI2FromUI8(ullIn
, pusOut
);
1480 /************************************************************************
1481 * VarI4FromUI1 (OLEAUT32.58)
1483 * Convert a VT_UI1 to a VT_I4.
1487 * piOut [O] Destination
1492 HRESULT WINAPI
VarI4FromUI1(BYTE bIn
, LONG
*piOut
)
1494 return _VarI4FromUI1(bIn
, piOut
);
1497 /************************************************************************
1498 * VarI4FromI2 (OLEAUT32.59)
1500 * Convert a VT_I2 to a VT_I4.
1504 * piOut [O] Destination
1508 * Failure: E_INVALIDARG, if the source value is invalid
1509 * DISP_E_OVERFLOW, if the value will not fit in the destination
1511 HRESULT WINAPI
VarI4FromI2(SHORT sIn
, LONG
*piOut
)
1513 return _VarI4FromI2(sIn
, piOut
);
1516 /************************************************************************
1517 * VarI4FromR4 (OLEAUT32.60)
1519 * Convert a VT_R4 to a VT_I4.
1523 * piOut [O] Destination
1527 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1529 HRESULT WINAPI
VarI4FromR4(FLOAT fltIn
, LONG
*piOut
)
1531 return VarI4FromR8(fltIn
, piOut
);
1534 /************************************************************************
1535 * VarI4FromR8 (OLEAUT32.61)
1537 * Convert a VT_R8 to a VT_I4.
1541 * piOut [O] Destination
1545 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1548 * See VarI8FromR8() for details concerning rounding.
1550 HRESULT WINAPI
VarI4FromR8(double dblIn
, LONG
*piOut
)
1552 if (dblIn
< (double)I4_MIN
|| dblIn
> (double)I4_MAX
)
1553 return DISP_E_OVERFLOW
;
1554 VARIANT_DutchRound(LONG
, dblIn
, *piOut
);
1558 /************************************************************************
1559 * VarI4FromCy (OLEAUT32.62)
1561 * Convert a VT_CY to a VT_I4.
1565 * piOut [O] Destination
1569 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1571 HRESULT WINAPI
VarI4FromCy(CY cyIn
, LONG
*piOut
)
1573 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1574 return VarI4FromR8(d
, piOut
);
1577 /************************************************************************
1578 * VarI4FromDate (OLEAUT32.63)
1580 * Convert a VT_DATE to a VT_I4.
1584 * piOut [O] Destination
1588 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1590 HRESULT WINAPI
VarI4FromDate(DATE dateIn
, LONG
*piOut
)
1592 return VarI4FromR8(dateIn
, piOut
);
1595 /************************************************************************
1596 * VarI4FromStr (OLEAUT32.64)
1598 * Convert a VT_BSTR to a VT_I4.
1602 * lcid [I] LCID for the conversion
1603 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1604 * piOut [O] Destination
1608 * Failure: E_INVALIDARG, if any parameter is invalid
1609 * DISP_E_OVERFLOW, if the value will not fit in the destination
1610 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1612 HRESULT WINAPI
VarI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG
*piOut
)
1614 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, piOut
, VT_I4
);
1617 /************************************************************************
1618 * VarI4FromDisp (OLEAUT32.65)
1620 * Convert a VT_DISPATCH to a VT_I4.
1623 * pdispIn [I] Source
1624 * lcid [I] LCID for conversion
1625 * piOut [O] Destination
1629 * Failure: E_INVALIDARG, if the source value is invalid
1630 * DISP_E_OVERFLOW, if the value will not fit in the destination
1631 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1633 HRESULT WINAPI
VarI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG
*piOut
)
1635 return VARIANT_FromDisp(pdispIn
, lcid
, piOut
, VT_I4
, 0);
1638 /************************************************************************
1639 * VarI4FromBool (OLEAUT32.66)
1641 * Convert a VT_BOOL to a VT_I4.
1645 * piOut [O] Destination
1650 HRESULT WINAPI
VarI4FromBool(VARIANT_BOOL boolIn
, LONG
*piOut
)
1652 return _VarI4FromBool(boolIn
, piOut
);
1655 /************************************************************************
1656 * VarI4FromI1 (OLEAUT32.209)
1658 * Convert a VT_I4 to a VT_I4.
1662 * piOut [O] Destination
1667 HRESULT WINAPI
VarI4FromI1(signed char cIn
, LONG
*piOut
)
1669 return _VarI4FromI1(cIn
, piOut
);
1672 /************************************************************************
1673 * VarI4FromUI2 (OLEAUT32.210)
1675 * Convert a VT_UI2 to a VT_I4.
1679 * piOut [O] Destination
1684 HRESULT WINAPI
VarI4FromUI2(USHORT usIn
, LONG
*piOut
)
1686 return _VarI4FromUI2(usIn
, piOut
);
1689 /************************************************************************
1690 * VarI4FromUI4 (OLEAUT32.211)
1692 * Convert a VT_UI4 to a VT_I4.
1696 * piOut [O] Destination
1700 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1702 HRESULT WINAPI
VarI4FromUI4(ULONG ulIn
, LONG
*piOut
)
1704 return _VarI4FromUI4(ulIn
, piOut
);
1707 /************************************************************************
1708 * VarI4FromDec (OLEAUT32.212)
1710 * Convert a VT_DECIMAL to a VT_I4.
1714 * piOut [O] Destination
1718 * Failure: E_INVALIDARG, if pdecIn is invalid
1719 * DISP_E_OVERFLOW, if the value will not fit in the destination
1721 HRESULT WINAPI
VarI4FromDec(DECIMAL
*pdecIn
, LONG
*piOut
)
1726 hRet
= VarI8FromDec(pdecIn
, &i64
);
1728 if (SUCCEEDED(hRet
))
1729 hRet
= _VarI4FromI8(i64
, piOut
);
1733 /************************************************************************
1734 * VarI4FromI8 (OLEAUT32.348)
1736 * Convert a VT_I8 to a VT_I4.
1740 * piOut [O] Destination
1744 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1746 HRESULT WINAPI
VarI4FromI8(LONG64 llIn
, LONG
*piOut
)
1748 return _VarI4FromI8(llIn
, piOut
);
1751 /************************************************************************
1752 * VarI4FromUI8 (OLEAUT32.349)
1754 * Convert a VT_UI8 to a VT_I4.
1758 * piOut [O] Destination
1762 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1764 HRESULT WINAPI
VarI4FromUI8(ULONG64 ullIn
, LONG
*piOut
)
1766 return _VarI4FromUI8(ullIn
, piOut
);
1772 /************************************************************************
1773 * VarUI4FromUI1 (OLEAUT32.270)
1775 * Convert a VT_UI1 to a VT_UI4.
1779 * pulOut [O] Destination
1784 HRESULT WINAPI
VarUI4FromUI1(BYTE bIn
, ULONG
*pulOut
)
1786 return _VarUI4FromUI1(bIn
, pulOut
);
1789 /************************************************************************
1790 * VarUI4FromI2 (OLEAUT32.271)
1792 * Convert a VT_I2 to a VT_UI4.
1796 * pulOut [O] Destination
1800 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1802 HRESULT WINAPI
VarUI4FromI2(SHORT sIn
, ULONG
*pulOut
)
1804 return _VarUI4FromI2(sIn
, pulOut
);
1807 /************************************************************************
1808 * VarUI4FromI4 (OLEAUT32.272)
1810 * Convert a VT_I4 to a VT_UI4.
1814 * pulOut [O] Destination
1818 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1820 HRESULT WINAPI
VarUI4FromI4(LONG iIn
, ULONG
*pulOut
)
1822 return _VarUI4FromI4(iIn
, pulOut
);
1825 /************************************************************************
1826 * VarUI4FromR4 (OLEAUT32.273)
1828 * Convert a VT_R4 to a VT_UI4.
1832 * pulOut [O] Destination
1836 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1838 HRESULT WINAPI
VarUI4FromR4(FLOAT fltIn
, ULONG
*pulOut
)
1840 return VarUI4FromR8(fltIn
, pulOut
);
1843 /************************************************************************
1844 * VarUI4FromR8 (OLEAUT32.274)
1846 * Convert a VT_R8 to a VT_UI4.
1850 * pulOut [O] Destination
1854 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1857 * See VarI8FromR8() for details concerning rounding.
1859 HRESULT WINAPI
VarUI4FromR8(double dblIn
, ULONG
*pulOut
)
1861 if (dblIn
< -0.5 || dblIn
> (double)UI4_MAX
)
1862 return DISP_E_OVERFLOW
;
1863 VARIANT_DutchRound(ULONG
, dblIn
, *pulOut
);
1867 /************************************************************************
1868 * VarUI4FromDate (OLEAUT32.275)
1870 * Convert a VT_DATE to a VT_UI4.
1874 * pulOut [O] Destination
1878 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1880 HRESULT WINAPI
VarUI4FromDate(DATE dateIn
, ULONG
*pulOut
)
1882 return VarUI4FromR8(dateIn
, pulOut
);
1885 /************************************************************************
1886 * VarUI4FromCy (OLEAUT32.276)
1888 * Convert a VT_CY to a VT_UI4.
1892 * pulOut [O] Destination
1896 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1898 HRESULT WINAPI
VarUI4FromCy(CY cyIn
, ULONG
*pulOut
)
1900 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1901 return VarUI4FromR8(d
, pulOut
);
1904 /************************************************************************
1905 * VarUI4FromStr (OLEAUT32.277)
1907 * Convert a VT_BSTR to a VT_UI4.
1911 * lcid [I] LCID for the conversion
1912 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1913 * pulOut [O] Destination
1917 * Failure: E_INVALIDARG, if any parameter is invalid
1918 * DISP_E_OVERFLOW, if the value will not fit in the destination
1919 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1921 HRESULT WINAPI
VarUI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG
*pulOut
)
1923 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pulOut
, VT_UI4
);
1926 /************************************************************************
1927 * VarUI4FromDisp (OLEAUT32.278)
1929 * Convert a VT_DISPATCH to a VT_UI4.
1932 * pdispIn [I] Source
1933 * lcid [I] LCID for conversion
1934 * pulOut [O] Destination
1938 * Failure: E_INVALIDARG, if the source value is invalid
1939 * DISP_E_OVERFLOW, if the value will not fit in the destination
1940 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1942 HRESULT WINAPI
VarUI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG
*pulOut
)
1944 return VARIANT_FromDisp(pdispIn
, lcid
, pulOut
, VT_UI4
, 0);
1947 /************************************************************************
1948 * VarUI4FromBool (OLEAUT32.279)
1950 * Convert a VT_BOOL to a VT_UI4.
1954 * pulOut [O] Destination
1959 HRESULT WINAPI
VarUI4FromBool(VARIANT_BOOL boolIn
, ULONG
*pulOut
)
1961 return _VarUI4FromBool(boolIn
, pulOut
);
1964 /************************************************************************
1965 * VarUI4FromI1 (OLEAUT32.280)
1967 * Convert a VT_I1 to a VT_UI4.
1971 * pulOut [O] Destination
1975 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1977 HRESULT WINAPI
VarUI4FromI1(signed char cIn
, ULONG
*pulOut
)
1979 return _VarUI4FromI1(cIn
, pulOut
);
1982 /************************************************************************
1983 * VarUI4FromUI2 (OLEAUT32.281)
1985 * Convert a VT_UI2 to a VT_UI4.
1989 * pulOut [O] Destination
1994 HRESULT WINAPI
VarUI4FromUI2(USHORT usIn
, ULONG
*pulOut
)
1996 return _VarUI4FromUI2(usIn
, pulOut
);
1999 /************************************************************************
2000 * VarUI4FromDec (OLEAUT32.282)
2002 * Convert a VT_DECIMAL to a VT_UI4.
2006 * pulOut [O] Destination
2010 * Failure: E_INVALIDARG, if pdecIn is invalid
2011 * DISP_E_OVERFLOW, if the value will not fit in the destination
2013 HRESULT WINAPI
VarUI4FromDec(DECIMAL
*pdecIn
, ULONG
*pulOut
)
2018 hRet
= VarI8FromDec(pdecIn
, &i64
);
2020 if (SUCCEEDED(hRet
))
2021 hRet
= _VarUI4FromI8(i64
, pulOut
);
2025 /************************************************************************
2026 * VarUI4FromI8 (OLEAUT32.425)
2028 * Convert a VT_I8 to a VT_UI4.
2032 * pulOut [O] Destination
2036 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2038 HRESULT WINAPI
VarUI4FromI8(LONG64 llIn
, ULONG
*pulOut
)
2040 return _VarUI4FromI8(llIn
, pulOut
);
2043 /************************************************************************
2044 * VarUI4FromUI8 (OLEAUT32.426)
2046 * Convert a VT_UI8 to a VT_UI4.
2050 * pulOut [O] Destination
2054 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2056 HRESULT WINAPI
VarUI4FromUI8(ULONG64 ullIn
, ULONG
*pulOut
)
2058 return _VarUI4FromUI8(ullIn
, pulOut
);
2064 /************************************************************************
2065 * VarI8FromUI1 (OLEAUT32.333)
2067 * Convert a VT_UI1 to a VT_I8.
2071 * pi64Out [O] Destination
2076 HRESULT WINAPI
VarI8FromUI1(BYTE bIn
, LONG64
* pi64Out
)
2078 return _VarI8FromUI1(bIn
, pi64Out
);
2082 /************************************************************************
2083 * VarI8FromI2 (OLEAUT32.334)
2085 * Convert a VT_I2 to a VT_I8.
2089 * pi64Out [O] Destination
2094 HRESULT WINAPI
VarI8FromI2(SHORT sIn
, LONG64
* pi64Out
)
2096 return _VarI8FromI2(sIn
, pi64Out
);
2099 /************************************************************************
2100 * VarI8FromR4 (OLEAUT32.335)
2102 * Convert a VT_R4 to a VT_I8.
2106 * pi64Out [O] Destination
2110 * Failure: E_INVALIDARG, if the source value is invalid
2111 * DISP_E_OVERFLOW, if the value will not fit in the destination
2113 HRESULT WINAPI
VarI8FromR4(FLOAT fltIn
, LONG64
* pi64Out
)
2115 return VarI8FromR8(fltIn
, pi64Out
);
2118 /************************************************************************
2119 * VarI8FromR8 (OLEAUT32.336)
2121 * Convert a VT_R8 to a VT_I8.
2125 * pi64Out [O] Destination
2129 * Failure: E_INVALIDARG, if the source value is invalid
2130 * DISP_E_OVERFLOW, if the value will not fit in the destination
2133 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2134 * very high or low values will not be accurately converted.
2136 * Numbers are rounded using Dutch rounding, as follows:
2138 *| Fractional Part Sign Direction Example
2139 *| --------------- ---- --------- -------
2140 *| < 0.5 + Down 0.4 -> 0.0
2141 *| < 0.5 - Up -0.4 -> 0.0
2142 *| > 0.5 + Up 0.6 -> 1.0
2143 *| < 0.5 - Up -0.6 -> -1.0
2144 *| = 0.5 + Up/Down Down if even, Up if odd
2145 *| = 0.5 - Up/Down Up if even, Down if odd
2147 * This system is often used in supermarkets.
2149 HRESULT WINAPI
VarI8FromR8(double dblIn
, LONG64
* pi64Out
)
2151 if ( dblIn
< -4611686018427387904.0 || dblIn
>= 4611686018427387904.0)
2152 return DISP_E_OVERFLOW
;
2153 VARIANT_DutchRound(LONG64
, dblIn
, *pi64Out
);
2157 /************************************************************************
2158 * VarI8FromCy (OLEAUT32.337)
2160 * Convert a VT_CY to a VT_I8.
2164 * pi64Out [O] Destination
2170 * All negative numbers are rounded down by 1, including those that are
2171 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2172 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2175 HRESULT WINAPI
VarI8FromCy(CY cyIn
, LONG64
* pi64Out
)
2177 *pi64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2180 (*pi64Out
)--; /* Mimic Win32 bug */
2183 cyIn
.int64
-= *pi64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2185 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pi64Out
& 0x1)))
2191 /************************************************************************
2192 * VarI8FromDate (OLEAUT32.338)
2194 * Convert a VT_DATE to a VT_I8.
2198 * pi64Out [O] Destination
2202 * Failure: E_INVALIDARG, if the source value is invalid
2203 * DISP_E_OVERFLOW, if the value will not fit in the destination
2204 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2206 HRESULT WINAPI
VarI8FromDate(DATE dateIn
, LONG64
* pi64Out
)
2208 return VarI8FromR8(dateIn
, pi64Out
);
2211 /************************************************************************
2212 * VarI8FromStr (OLEAUT32.339)
2214 * Convert a VT_BSTR to a VT_I8.
2218 * lcid [I] LCID for the conversion
2219 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2220 * pi64Out [O] Destination
2224 * Failure: E_INVALIDARG, if the source value is invalid
2225 * DISP_E_OVERFLOW, if the value will not fit in the destination
2226 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2228 HRESULT WINAPI
VarI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG64
* pi64Out
)
2230 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pi64Out
, VT_I8
);
2233 /************************************************************************
2234 * VarI8FromDisp (OLEAUT32.340)
2236 * Convert a VT_DISPATCH to a VT_I8.
2239 * pdispIn [I] Source
2240 * lcid [I] LCID for conversion
2241 * pi64Out [O] Destination
2245 * Failure: E_INVALIDARG, if the source value is invalid
2246 * DISP_E_OVERFLOW, if the value will not fit in the destination
2247 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2249 HRESULT WINAPI
VarI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG64
* pi64Out
)
2251 return VARIANT_FromDisp(pdispIn
, lcid
, pi64Out
, VT_I8
, 0);
2254 /************************************************************************
2255 * VarI8FromBool (OLEAUT32.341)
2257 * Convert a VT_BOOL to a VT_I8.
2261 * pi64Out [O] Destination
2266 HRESULT WINAPI
VarI8FromBool(VARIANT_BOOL boolIn
, LONG64
* pi64Out
)
2268 return VarI8FromI2(boolIn
, pi64Out
);
2271 /************************************************************************
2272 * VarI8FromI1 (OLEAUT32.342)
2274 * Convert a VT_I1 to a VT_I8.
2278 * pi64Out [O] Destination
2283 HRESULT WINAPI
VarI8FromI1(signed char cIn
, LONG64
* pi64Out
)
2285 return _VarI8FromI1(cIn
, pi64Out
);
2288 /************************************************************************
2289 * VarI8FromUI2 (OLEAUT32.343)
2291 * Convert a VT_UI2 to a VT_I8.
2295 * pi64Out [O] Destination
2300 HRESULT WINAPI
VarI8FromUI2(USHORT usIn
, LONG64
* pi64Out
)
2302 return _VarI8FromUI2(usIn
, pi64Out
);
2305 /************************************************************************
2306 * VarI8FromUI4 (OLEAUT32.344)
2308 * Convert a VT_UI4 to a VT_I8.
2312 * pi64Out [O] Destination
2317 HRESULT WINAPI
VarI8FromUI4(ULONG ulIn
, LONG64
* pi64Out
)
2319 return _VarI8FromUI4(ulIn
, pi64Out
);
2322 /************************************************************************
2323 * VarI8FromDec (OLEAUT32.345)
2325 * Convert a VT_DECIMAL to a VT_I8.
2329 * pi64Out [O] Destination
2333 * Failure: E_INVALIDARG, if the source value is invalid
2334 * DISP_E_OVERFLOW, if the value will not fit in the destination
2336 HRESULT WINAPI
VarI8FromDec(DECIMAL
*pdecIn
, LONG64
* pi64Out
)
2338 if (!DEC_SCALE(pdecIn
))
2340 /* This decimal is just a 96 bit integer */
2341 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2342 return E_INVALIDARG
;
2344 if (DEC_HI32(pdecIn
) || DEC_MID32(pdecIn
) & 0x80000000)
2345 return DISP_E_OVERFLOW
;
2347 if (DEC_SIGN(pdecIn
))
2348 *pi64Out
= -DEC_LO64(pdecIn
);
2350 *pi64Out
= DEC_LO64(pdecIn
);
2355 /* Decimal contains a floating point number */
2359 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2360 if (SUCCEEDED(hRet
))
2361 hRet
= VarI8FromR8(dbl
, pi64Out
);
2366 /************************************************************************
2367 * VarI8FromUI8 (OLEAUT32.427)
2369 * Convert a VT_UI8 to a VT_I8.
2373 * pi64Out [O] Destination
2377 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2379 HRESULT WINAPI
VarI8FromUI8(ULONG64 ullIn
, LONG64
* pi64Out
)
2381 return _VarI8FromUI8(ullIn
, pi64Out
);
2387 /************************************************************************
2388 * VarUI8FromI8 (OLEAUT32.428)
2390 * Convert a VT_I8 to a VT_UI8.
2394 * pui64Out [O] Destination
2398 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2400 HRESULT WINAPI
VarUI8FromI8(LONG64 llIn
, ULONG64
* pui64Out
)
2402 return _VarUI8FromI8(llIn
, pui64Out
);
2405 /************************************************************************
2406 * VarUI8FromUI1 (OLEAUT32.429)
2408 * Convert a VT_UI1 to a VT_UI8.
2412 * pui64Out [O] Destination
2417 HRESULT WINAPI
VarUI8FromUI1(BYTE bIn
, ULONG64
* pui64Out
)
2419 return _VarUI8FromUI1(bIn
, pui64Out
);
2422 /************************************************************************
2423 * VarUI8FromI2 (OLEAUT32.430)
2425 * Convert a VT_I2 to a VT_UI8.
2429 * pui64Out [O] Destination
2434 HRESULT WINAPI
VarUI8FromI2(SHORT sIn
, ULONG64
* pui64Out
)
2436 return _VarUI8FromI2(sIn
, pui64Out
);
2439 /************************************************************************
2440 * VarUI8FromR4 (OLEAUT32.431)
2442 * Convert a VT_R4 to a VT_UI8.
2446 * pui64Out [O] Destination
2450 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2452 HRESULT WINAPI
VarUI8FromR4(FLOAT fltIn
, ULONG64
* pui64Out
)
2454 return VarUI8FromR8(fltIn
, pui64Out
);
2457 /************************************************************************
2458 * VarUI8FromR8 (OLEAUT32.432)
2460 * Convert a VT_R8 to a VT_UI8.
2464 * pui64Out [O] Destination
2468 * Failure: E_INVALIDARG, if the source value is invalid
2469 * DISP_E_OVERFLOW, if the value will not fit in the destination
2472 * See VarI8FromR8() for details concerning rounding.
2474 HRESULT WINAPI
VarUI8FromR8(double dblIn
, ULONG64
* pui64Out
)
2476 if (dblIn
< -0.5 || dblIn
> 1.844674407370955e19
)
2477 return DISP_E_OVERFLOW
;
2478 VARIANT_DutchRound(ULONG64
, dblIn
, *pui64Out
);
2482 /************************************************************************
2483 * VarUI8FromCy (OLEAUT32.433)
2485 * Convert a VT_CY to a VT_UI8.
2489 * pui64Out [O] Destination
2493 * Failure: E_INVALIDARG, if the source value is invalid
2494 * DISP_E_OVERFLOW, if the value will not fit in the destination
2497 * Negative values >= -5000 will be converted to 0.
2499 HRESULT WINAPI
VarUI8FromCy(CY cyIn
, ULONG64
* pui64Out
)
2503 if (cyIn
.int64
< -CY_HALF
)
2504 return DISP_E_OVERFLOW
;
2509 *pui64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2511 cyIn
.int64
-= *pui64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2513 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pui64Out
& 0x1)))
2519 /************************************************************************
2520 * VarUI8FromDate (OLEAUT32.434)
2522 * Convert a VT_DATE to a VT_UI8.
2526 * pui64Out [O] Destination
2530 * Failure: E_INVALIDARG, if the source value is invalid
2531 * DISP_E_OVERFLOW, if the value will not fit in the destination
2532 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2534 HRESULT WINAPI
VarUI8FromDate(DATE dateIn
, ULONG64
* pui64Out
)
2536 return VarUI8FromR8(dateIn
, pui64Out
);
2539 /************************************************************************
2540 * VarUI8FromStr (OLEAUT32.435)
2542 * Convert a VT_BSTR to a VT_UI8.
2546 * lcid [I] LCID for the conversion
2547 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2548 * pui64Out [O] Destination
2552 * Failure: E_INVALIDARG, if the source value is invalid
2553 * DISP_E_OVERFLOW, if the value will not fit in the destination
2554 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2556 HRESULT WINAPI
VarUI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG64
* pui64Out
)
2558 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pui64Out
, VT_UI8
);
2561 /************************************************************************
2562 * VarUI8FromDisp (OLEAUT32.436)
2564 * Convert a VT_DISPATCH to a VT_UI8.
2567 * pdispIn [I] Source
2568 * lcid [I] LCID for conversion
2569 * pui64Out [O] Destination
2573 * Failure: E_INVALIDARG, if the source value is invalid
2574 * DISP_E_OVERFLOW, if the value will not fit in the destination
2575 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2577 HRESULT WINAPI
VarUI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG64
* pui64Out
)
2579 return VARIANT_FromDisp(pdispIn
, lcid
, pui64Out
, VT_UI8
, 0);
2582 /************************************************************************
2583 * VarUI8FromBool (OLEAUT32.437)
2585 * Convert a VT_BOOL to a VT_UI8.
2589 * pui64Out [O] Destination
2593 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2595 HRESULT WINAPI
VarUI8FromBool(VARIANT_BOOL boolIn
, ULONG64
* pui64Out
)
2597 return VarI8FromI2(boolIn
, (LONG64
*)pui64Out
);
2599 /************************************************************************
2600 * VarUI8FromI1 (OLEAUT32.438)
2602 * Convert a VT_I1 to a VT_UI8.
2606 * pui64Out [O] Destination
2610 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2612 HRESULT WINAPI
VarUI8FromI1(signed char cIn
, ULONG64
* pui64Out
)
2614 return _VarUI8FromI1(cIn
, pui64Out
);
2617 /************************************************************************
2618 * VarUI8FromUI2 (OLEAUT32.439)
2620 * Convert a VT_UI2 to a VT_UI8.
2624 * pui64Out [O] Destination
2629 HRESULT WINAPI
VarUI8FromUI2(USHORT usIn
, ULONG64
* pui64Out
)
2631 return _VarUI8FromUI2(usIn
, pui64Out
);
2634 /************************************************************************
2635 * VarUI8FromUI4 (OLEAUT32.440)
2637 * Convert a VT_UI4 to a VT_UI8.
2641 * pui64Out [O] Destination
2646 HRESULT WINAPI
VarUI8FromUI4(ULONG ulIn
, ULONG64
* pui64Out
)
2648 return _VarUI8FromUI4(ulIn
, pui64Out
);
2651 /************************************************************************
2652 * VarUI8FromDec (OLEAUT32.441)
2654 * Convert a VT_DECIMAL to a VT_UI8.
2658 * pui64Out [O] Destination
2662 * Failure: E_INVALIDARG, if the source value is invalid
2663 * DISP_E_OVERFLOW, if the value will not fit in the destination
2666 * Under native Win32, if the source value has a scale of 0, its sign is
2667 * ignored, i.e. this function takes the absolute value rather than fail
2668 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2669 * (use VarAbs() on pDecIn first if you really want this behaviour).
2671 HRESULT WINAPI
VarUI8FromDec(DECIMAL
*pdecIn
, ULONG64
* pui64Out
)
2673 if (!DEC_SCALE(pdecIn
))
2675 /* This decimal is just a 96 bit integer */
2676 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2677 return E_INVALIDARG
;
2679 if (DEC_HI32(pdecIn
))
2680 return DISP_E_OVERFLOW
;
2682 if (DEC_SIGN(pdecIn
))
2684 WARN("Sign would be ignored under Win32!\n");
2685 return DISP_E_OVERFLOW
;
2688 *pui64Out
= DEC_LO64(pdecIn
);
2693 /* Decimal contains a floating point number */
2697 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2698 if (SUCCEEDED(hRet
))
2699 hRet
= VarUI8FromR8(dbl
, pui64Out
);
2707 /************************************************************************
2708 * VarR4FromUI1 (OLEAUT32.68)
2710 * Convert a VT_UI1 to a VT_R4.
2714 * pFltOut [O] Destination
2719 HRESULT WINAPI
VarR4FromUI1(BYTE bIn
, float *pFltOut
)
2721 return _VarR4FromUI1(bIn
, pFltOut
);
2724 /************************************************************************
2725 * VarR4FromI2 (OLEAUT32.69)
2727 * Convert a VT_I2 to a VT_R4.
2731 * pFltOut [O] Destination
2736 HRESULT WINAPI
VarR4FromI2(SHORT sIn
, float *pFltOut
)
2738 return _VarR4FromI2(sIn
, pFltOut
);
2741 /************************************************************************
2742 * VarR4FromI4 (OLEAUT32.70)
2744 * Convert a VT_I4 to a VT_R4.
2748 * pFltOut [O] Destination
2753 HRESULT WINAPI
VarR4FromI4(LONG lIn
, float *pFltOut
)
2755 return _VarR4FromI4(lIn
, pFltOut
);
2758 /************************************************************************
2759 * VarR4FromR8 (OLEAUT32.71)
2761 * Convert a VT_R8 to a VT_R4.
2765 * pFltOut [O] Destination
2769 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2771 HRESULT WINAPI
VarR4FromR8(double dblIn
, float *pFltOut
)
2773 double d
= dblIn
< 0.0 ? -dblIn
: dblIn
;
2774 if (d
> R4_MAX
) return DISP_E_OVERFLOW
;
2779 /************************************************************************
2780 * VarR4FromCy (OLEAUT32.72)
2782 * Convert a VT_CY to a VT_R4.
2786 * pFltOut [O] Destination
2791 HRESULT WINAPI
VarR4FromCy(CY cyIn
, float *pFltOut
)
2793 *pFltOut
= (double)cyIn
.int64
/ CY_MULTIPLIER_F
;
2797 /************************************************************************
2798 * VarR4FromDate (OLEAUT32.73)
2800 * Convert a VT_DATE to a VT_R4.
2804 * pFltOut [O] Destination
2808 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2810 HRESULT WINAPI
VarR4FromDate(DATE dateIn
, float *pFltOut
)
2812 return VarR4FromR8(dateIn
, pFltOut
);
2815 /************************************************************************
2816 * VarR4FromStr (OLEAUT32.74)
2818 * Convert a VT_BSTR to a VT_R4.
2822 * lcid [I] LCID for the conversion
2823 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2824 * pFltOut [O] Destination
2828 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2829 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2831 HRESULT WINAPI
VarR4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, float *pFltOut
)
2833 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pFltOut
, VT_R4
);
2836 /************************************************************************
2837 * VarR4FromDisp (OLEAUT32.75)
2839 * Convert a VT_DISPATCH to a VT_R4.
2842 * pdispIn [I] Source
2843 * lcid [I] LCID for conversion
2844 * pFltOut [O] Destination
2848 * Failure: E_INVALIDARG, if the source value is invalid
2849 * DISP_E_OVERFLOW, if the value will not fit in the destination
2850 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2852 HRESULT WINAPI
VarR4FromDisp(IDispatch
* pdispIn
, LCID lcid
, float *pFltOut
)
2854 return VARIANT_FromDisp(pdispIn
, lcid
, pFltOut
, VT_R4
, 0);
2857 /************************************************************************
2858 * VarR4FromBool (OLEAUT32.76)
2860 * Convert a VT_BOOL to a VT_R4.
2864 * pFltOut [O] Destination
2869 HRESULT WINAPI
VarR4FromBool(VARIANT_BOOL boolIn
, float *pFltOut
)
2871 return VarR4FromI2(boolIn
, pFltOut
);
2874 /************************************************************************
2875 * VarR4FromI1 (OLEAUT32.213)
2877 * Convert a VT_I1 to a VT_R4.
2881 * pFltOut [O] Destination
2885 * Failure: E_INVALIDARG, if the source value is invalid
2886 * DISP_E_OVERFLOW, if the value will not fit in the destination
2887 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2889 HRESULT WINAPI
VarR4FromI1(signed char cIn
, float *pFltOut
)
2891 return _VarR4FromI1(cIn
, pFltOut
);
2894 /************************************************************************
2895 * VarR4FromUI2 (OLEAUT32.214)
2897 * Convert a VT_UI2 to a VT_R4.
2901 * pFltOut [O] Destination
2905 * Failure: E_INVALIDARG, if the source value is invalid
2906 * DISP_E_OVERFLOW, if the value will not fit in the destination
2907 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2909 HRESULT WINAPI
VarR4FromUI2(USHORT usIn
, float *pFltOut
)
2911 return _VarR4FromUI2(usIn
, pFltOut
);
2914 /************************************************************************
2915 * VarR4FromUI4 (OLEAUT32.215)
2917 * Convert a VT_UI4 to a VT_R4.
2921 * pFltOut [O] Destination
2925 * Failure: E_INVALIDARG, if the source value is invalid
2926 * DISP_E_OVERFLOW, if the value will not fit in the destination
2927 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2929 HRESULT WINAPI
VarR4FromUI4(ULONG ulIn
, float *pFltOut
)
2931 return _VarR4FromUI4(ulIn
, pFltOut
);
2934 /************************************************************************
2935 * VarR4FromDec (OLEAUT32.216)
2937 * Convert a VT_DECIMAL to a VT_R4.
2941 * pFltOut [O] Destination
2945 * Failure: E_INVALIDARG, if the source value is invalid.
2947 HRESULT WINAPI
VarR4FromDec(DECIMAL
* pDecIn
, float *pFltOut
)
2949 BYTE scale
= DEC_SCALE(pDecIn
);
2953 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
2954 return E_INVALIDARG
;
2959 if (DEC_SIGN(pDecIn
))
2962 if (DEC_HI32(pDecIn
))
2964 highPart
= (double)DEC_HI32(pDecIn
) / (double)divisor
;
2965 highPart
*= 4294967296.0F
;
2966 highPart
*= 4294967296.0F
;
2971 *pFltOut
= (double)DEC_LO64(pDecIn
) / (double)divisor
+ highPart
;
2975 /************************************************************************
2976 * VarR4FromI8 (OLEAUT32.360)
2978 * Convert a VT_I8 to a VT_R4.
2982 * pFltOut [O] Destination
2987 HRESULT WINAPI
VarR4FromI8(LONG64 llIn
, float *pFltOut
)
2989 return _VarR4FromI8(llIn
, pFltOut
);
2992 /************************************************************************
2993 * VarR4FromUI8 (OLEAUT32.361)
2995 * Convert a VT_UI8 to a VT_R4.
2999 * pFltOut [O] Destination
3004 HRESULT WINAPI
VarR4FromUI8(ULONG64 ullIn
, float *pFltOut
)
3006 return _VarR4FromUI8(ullIn
, pFltOut
);
3009 /************************************************************************
3010 * VarR4CmpR8 (OLEAUT32.316)
3012 * Compare a VT_R4 to a VT_R8.
3015 * fltLeft [I] Source
3016 * dblRight [I] Value to compare
3019 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3020 * equal to or greater than dblRight respectively.
3022 HRESULT WINAPI
VarR4CmpR8(float fltLeft
, double dblRight
)
3024 if (fltLeft
< dblRight
)
3026 else if (fltLeft
> dblRight
)
3034 /************************************************************************
3035 * VarR8FromUI1 (OLEAUT32.78)
3037 * Convert a VT_UI1 to a VT_R8.
3041 * pDblOut [O] Destination
3046 HRESULT WINAPI
VarR8FromUI1(BYTE bIn
, double *pDblOut
)
3048 return _VarR8FromUI1(bIn
, pDblOut
);
3051 /************************************************************************
3052 * VarR8FromI2 (OLEAUT32.79)
3054 * Convert a VT_I2 to a VT_R8.
3058 * pDblOut [O] Destination
3063 HRESULT WINAPI
VarR8FromI2(SHORT sIn
, double *pDblOut
)
3065 return _VarR8FromI2(sIn
, pDblOut
);
3068 /************************************************************************
3069 * VarR8FromI4 (OLEAUT32.80)
3071 * Convert a VT_I4 to a VT_R8.
3075 * pDblOut [O] Destination
3080 HRESULT WINAPI
VarR8FromI4(LONG lIn
, double *pDblOut
)
3082 return _VarR8FromI4(lIn
, pDblOut
);
3085 /************************************************************************
3086 * VarR8FromR4 (OLEAUT32.81)
3088 * Convert a VT_R4 to a VT_R8.
3092 * pDblOut [O] Destination
3097 HRESULT WINAPI
VarR8FromR4(FLOAT fltIn
, double *pDblOut
)
3099 return _VarR8FromR4(fltIn
, pDblOut
);
3102 /************************************************************************
3103 * VarR8FromCy (OLEAUT32.82)
3105 * Convert a VT_CY to a VT_R8.
3109 * pDblOut [O] Destination
3114 HRESULT WINAPI
VarR8FromCy(CY cyIn
, double *pDblOut
)
3116 return _VarR8FromCy(cyIn
, pDblOut
);
3119 /************************************************************************
3120 * VarR8FromDate (OLEAUT32.83)
3122 * Convert a VT_DATE to a VT_R8.
3126 * pDblOut [O] Destination
3131 HRESULT WINAPI
VarR8FromDate(DATE dateIn
, double *pDblOut
)
3133 return _VarR8FromDate(dateIn
, pDblOut
);
3136 /************************************************************************
3137 * VarR8FromStr (OLEAUT32.84)
3139 * Convert a VT_BSTR to a VT_R8.
3143 * lcid [I] LCID for the conversion
3144 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3145 * pDblOut [O] Destination
3149 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3150 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3152 HRESULT WINAPI
VarR8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, double *pDblOut
)
3154 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDblOut
, VT_R8
);
3157 /************************************************************************
3158 * VarR8FromDisp (OLEAUT32.85)
3160 * Convert a VT_DISPATCH to a VT_R8.
3163 * pdispIn [I] Source
3164 * lcid [I] LCID for conversion
3165 * pDblOut [O] Destination
3169 * Failure: E_INVALIDARG, if the source value is invalid
3170 * DISP_E_OVERFLOW, if the value will not fit in the destination
3171 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3173 HRESULT WINAPI
VarR8FromDisp(IDispatch
* pdispIn
, LCID lcid
, double *pDblOut
)
3175 return VARIANT_FromDisp(pdispIn
, lcid
, pDblOut
, VT_R8
, 0);
3178 /************************************************************************
3179 * VarR8FromBool (OLEAUT32.86)
3181 * Convert a VT_BOOL to a VT_R8.
3185 * pDblOut [O] Destination
3190 HRESULT WINAPI
VarR8FromBool(VARIANT_BOOL boolIn
, double *pDblOut
)
3192 return VarR8FromI2(boolIn
, pDblOut
);
3195 /************************************************************************
3196 * VarR8FromI1 (OLEAUT32.217)
3198 * Convert a VT_I1 to a VT_R8.
3202 * pDblOut [O] Destination
3206 * Failure: E_INVALIDARG, if the source value is invalid
3207 * DISP_E_OVERFLOW, if the value will not fit in the destination
3208 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3210 HRESULT WINAPI
VarR8FromI1(signed char cIn
, double *pDblOut
)
3212 return _VarR8FromI1(cIn
, pDblOut
);
3215 /************************************************************************
3216 * VarR8FromUI2 (OLEAUT32.218)
3218 * Convert a VT_UI2 to a VT_R8.
3222 * pDblOut [O] Destination
3226 * Failure: E_INVALIDARG, if the source value is invalid
3227 * DISP_E_OVERFLOW, if the value will not fit in the destination
3228 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3230 HRESULT WINAPI
VarR8FromUI2(USHORT usIn
, double *pDblOut
)
3232 return _VarR8FromUI2(usIn
, pDblOut
);
3235 /************************************************************************
3236 * VarR8FromUI4 (OLEAUT32.219)
3238 * Convert a VT_UI4 to a VT_R8.
3242 * pDblOut [O] Destination
3246 * Failure: E_INVALIDARG, if the source value is invalid
3247 * DISP_E_OVERFLOW, if the value will not fit in the destination
3248 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3250 HRESULT WINAPI
VarR8FromUI4(ULONG ulIn
, double *pDblOut
)
3252 return _VarR8FromUI4(ulIn
, pDblOut
);
3255 /************************************************************************
3256 * VarR8FromDec (OLEAUT32.220)
3258 * Convert a VT_DECIMAL to a VT_R8.
3262 * pDblOut [O] Destination
3266 * Failure: E_INVALIDARG, if the source value is invalid.
3268 HRESULT WINAPI
VarR8FromDec(const DECIMAL
* pDecIn
, double *pDblOut
)
3270 BYTE scale
= DEC_SCALE(pDecIn
);
3271 double divisor
= 1.0, highPart
;
3273 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
3274 return E_INVALIDARG
;
3279 if (DEC_SIGN(pDecIn
))
3282 if (DEC_HI32(pDecIn
))
3284 highPart
= (double)DEC_HI32(pDecIn
) / divisor
;
3285 highPart
*= 4294967296.0F
;
3286 highPart
*= 4294967296.0F
;
3291 *pDblOut
= (double)DEC_LO64(pDecIn
) / divisor
+ highPart
;
3295 /************************************************************************
3296 * VarR8FromI8 (OLEAUT32.362)
3298 * Convert a VT_I8 to a VT_R8.
3302 * pDblOut [O] Destination
3307 HRESULT WINAPI
VarR8FromI8(LONG64 llIn
, double *pDblOut
)
3309 return _VarR8FromI8(llIn
, pDblOut
);
3312 /************************************************************************
3313 * VarR8FromUI8 (OLEAUT32.363)
3315 * Convert a VT_UI8 to a VT_R8.
3319 * pDblOut [O] Destination
3324 HRESULT WINAPI
VarR8FromUI8(ULONG64 ullIn
, double *pDblOut
)
3326 return _VarR8FromUI8(ullIn
, pDblOut
);
3329 /************************************************************************
3330 * VarR8Pow (OLEAUT32.315)
3332 * Raise a VT_R8 to a power.
3335 * dblLeft [I] Source
3336 * dblPow [I] Power to raise dblLeft by
3337 * pDblOut [O] Destination
3340 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3342 HRESULT WINAPI
VarR8Pow(double dblLeft
, double dblPow
, double *pDblOut
)
3344 *pDblOut
= pow(dblLeft
, dblPow
);
3348 /************************************************************************
3349 * VarR8Round (OLEAUT32.317)
3351 * Round a VT_R8 to a given number of decimal points.
3355 * nDig [I] Number of decimal points to round to
3356 * pDblOut [O] Destination for rounded number
3359 * Success: S_OK. pDblOut is rounded to nDig digits.
3360 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3363 * The native version of this function rounds using the internal
3364 * binary representation of the number. Wine uses the dutch rounding
3365 * convention, so therefore small differences can occur in the value returned.
3366 * MSDN says that you should use your own rounding function if you want
3367 * rounding to be predictable in your application.
3369 HRESULT WINAPI
VarR8Round(double dblIn
, int nDig
, double *pDblOut
)
3371 double scale
, whole
, fract
;
3374 return E_INVALIDARG
;
3376 scale
= pow(10.0, nDig
);
3379 whole
= dblIn
< 0 ? ceil(dblIn
) : floor(dblIn
);
3380 fract
= dblIn
- whole
;
3383 dblIn
= whole
+ 1.0;
3384 else if (fract
== 0.5)
3385 dblIn
= whole
+ fmod(whole
, 2.0);
3386 else if (fract
>= 0.0)
3388 else if (fract
== -0.5)
3389 dblIn
= whole
- fmod(whole
, 2.0);
3390 else if (fract
> -0.5)
3393 dblIn
= whole
- 1.0;
3395 *pDblOut
= dblIn
/ scale
;
3402 /* Powers of 10 from 0..4 D.P. */
3403 static const int CY_Divisors
[5] = { CY_MULTIPLIER
/10000, CY_MULTIPLIER
/1000,
3404 CY_MULTIPLIER
/100, CY_MULTIPLIER
/10, CY_MULTIPLIER
};
3406 /************************************************************************
3407 * VarCyFromUI1 (OLEAUT32.98)
3409 * Convert a VT_UI1 to a VT_CY.
3413 * pCyOut [O] Destination
3417 * Failure: E_INVALIDARG, if the source value is invalid
3418 * DISP_E_OVERFLOW, if the value will not fit in the destination
3419 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3421 HRESULT WINAPI
VarCyFromUI1(BYTE bIn
, CY
* pCyOut
)
3423 pCyOut
->int64
= (ULONG64
)bIn
* CY_MULTIPLIER
;
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 pCyOut
->int64
= (LONG64
)sIn
* CY_MULTIPLIER
;
3448 /************************************************************************
3449 * VarCyFromI4 (OLEAUT32.100)
3451 * Convert a VT_I4 to a VT_CY.
3455 * pCyOut [O] Destination
3459 * Failure: E_INVALIDARG, if the source value is invalid
3460 * DISP_E_OVERFLOW, if the value will not fit in the destination
3461 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3463 HRESULT WINAPI
VarCyFromI4(LONG lIn
, CY
* pCyOut
)
3465 pCyOut
->int64
= (LONG64
)lIn
* CY_MULTIPLIER
;
3469 /************************************************************************
3470 * VarCyFromR4 (OLEAUT32.101)
3472 * Convert a VT_R4 to a VT_CY.
3476 * pCyOut [O] Destination
3480 * Failure: E_INVALIDARG, if the source value is invalid
3481 * DISP_E_OVERFLOW, if the value will not fit in the destination
3482 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3484 HRESULT WINAPI
VarCyFromR4(FLOAT fltIn
, CY
* pCyOut
)
3486 return VarCyFromR8(fltIn
, pCyOut
);
3489 /************************************************************************
3490 * VarCyFromR8 (OLEAUT32.102)
3492 * Convert a VT_R8 to a VT_CY.
3496 * pCyOut [O] Destination
3500 * Failure: E_INVALIDARG, if the source value is invalid
3501 * DISP_E_OVERFLOW, if the value will not fit in the destination
3502 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3504 HRESULT WINAPI
VarCyFromR8(double dblIn
, CY
* pCyOut
)
3506 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3507 /* This code gives identical results to Win32 on Intel.
3508 * Here we use fp exceptions to catch overflows when storing the value.
3510 static const unsigned short r8_fpcontrol
= 0x137f;
3511 static const double r8_multiplier
= CY_MULTIPLIER_F
;
3512 unsigned short old_fpcontrol
, result_fpstatus
;
3514 /* Clear exceptions, save the old fp state and load the new state */
3515 __asm__
__volatile__( "fnclex" );
3516 __asm__
__volatile__( "fstcw %0" : "=m" (old_fpcontrol
) : );
3517 __asm__
__volatile__( "fldcw %0" : : "m" (r8_fpcontrol
) );
3518 /* Perform the conversion. */
3519 __asm__
__volatile__( "fldl %0" : : "m" (dblIn
) );
3520 __asm__
__volatile__( "fmull %0" : : "m" (r8_multiplier
) );
3521 __asm__
__volatile__( "fistpll %0" : : "m" (*pCyOut
) );
3522 /* Save the resulting fp state, load the old state and clear exceptions */
3523 __asm__
__volatile__( "fstsw %0" : "=m" (result_fpstatus
) : );
3524 __asm__
__volatile__( "fnclex" );
3525 __asm__
__volatile__( "fldcw %0" : : "m" (old_fpcontrol
) );
3527 if (result_fpstatus
& 0x9) /* Overflow | Invalid */
3528 return DISP_E_OVERFLOW
;
3530 /* This version produces slightly different results for boundary cases */
3531 if (dblIn
< -922337203685477.5807 || dblIn
>= 922337203685477.5807)
3532 return DISP_E_OVERFLOW
;
3533 dblIn
*= CY_MULTIPLIER_F
;
3534 VARIANT_DutchRound(LONG64
, dblIn
, pCyOut
->int64
);
3539 /************************************************************************
3540 * VarCyFromDate (OLEAUT32.103)
3542 * Convert a VT_DATE to a VT_CY.
3546 * pCyOut [O] Destination
3550 * Failure: E_INVALIDARG, if the source value is invalid
3551 * DISP_E_OVERFLOW, if the value will not fit in the destination
3552 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3554 HRESULT WINAPI
VarCyFromDate(DATE dateIn
, CY
* pCyOut
)
3556 return VarCyFromR8(dateIn
, pCyOut
);
3559 /************************************************************************
3560 * VarCyFromStr (OLEAUT32.104)
3562 * Convert a VT_BSTR to a VT_CY.
3566 * lcid [I] LCID for the conversion
3567 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3568 * pCyOut [O] Destination
3572 * Failure: E_INVALIDARG, if the source value is invalid
3573 * DISP_E_OVERFLOW, if the value will not fit in the destination
3574 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3576 HRESULT WINAPI
VarCyFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, CY
* pCyOut
)
3578 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pCyOut
, VT_CY
);
3581 /************************************************************************
3582 * VarCyFromDisp (OLEAUT32.105)
3584 * Convert a VT_DISPATCH to a VT_CY.
3587 * pdispIn [I] Source
3588 * lcid [I] LCID for conversion
3589 * pCyOut [O] Destination
3593 * Failure: E_INVALIDARG, if the source value is invalid
3594 * DISP_E_OVERFLOW, if the value will not fit in the destination
3595 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3597 HRESULT WINAPI
VarCyFromDisp(IDispatch
* pdispIn
, LCID lcid
, CY
* pCyOut
)
3599 return VARIANT_FromDisp(pdispIn
, lcid
, pCyOut
, VT_CY
, 0);
3602 /************************************************************************
3603 * VarCyFromBool (OLEAUT32.106)
3605 * Convert a VT_BOOL to a VT_CY.
3609 * pCyOut [O] Destination
3613 * Failure: E_INVALIDARG, if the source value is invalid
3614 * DISP_E_OVERFLOW, if the value will not fit in the destination
3615 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3618 * While the sign of the boolean is stored in the currency, the value is
3619 * converted to either 0 or 1.
3621 HRESULT WINAPI
VarCyFromBool(VARIANT_BOOL boolIn
, CY
* pCyOut
)
3623 pCyOut
->int64
= (LONG64
)boolIn
* CY_MULTIPLIER
;
3627 /************************************************************************
3628 * VarCyFromI1 (OLEAUT32.225)
3630 * Convert a VT_I1 to a VT_CY.
3634 * pCyOut [O] Destination
3638 * Failure: E_INVALIDARG, if the source value is invalid
3639 * DISP_E_OVERFLOW, if the value will not fit in the destination
3640 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3642 HRESULT WINAPI
VarCyFromI1(signed char cIn
, CY
* pCyOut
)
3644 pCyOut
->int64
= (LONG64
)cIn
* CY_MULTIPLIER
;
3648 /************************************************************************
3649 * VarCyFromUI2 (OLEAUT32.226)
3651 * Convert a VT_UI2 to a VT_CY.
3655 * pCyOut [O] Destination
3659 * Failure: E_INVALIDARG, if the source value is invalid
3660 * DISP_E_OVERFLOW, if the value will not fit in the destination
3661 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3663 HRESULT WINAPI
VarCyFromUI2(USHORT usIn
, CY
* pCyOut
)
3665 pCyOut
->int64
= (ULONG64
)usIn
* CY_MULTIPLIER
;
3669 /************************************************************************
3670 * VarCyFromUI4 (OLEAUT32.227)
3672 * Convert a VT_UI4 to a VT_CY.
3676 * pCyOut [O] Destination
3680 * Failure: E_INVALIDARG, if the source value is invalid
3681 * DISP_E_OVERFLOW, if the value will not fit in the destination
3682 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3684 HRESULT WINAPI
VarCyFromUI4(ULONG ulIn
, CY
* pCyOut
)
3686 pCyOut
->int64
= (ULONG64
)ulIn
* CY_MULTIPLIER
;
3690 /************************************************************************
3691 * VarCyFromDec (OLEAUT32.228)
3693 * Convert a VT_DECIMAL to a VT_CY.
3697 * pCyOut [O] Destination
3701 * Failure: E_INVALIDARG, if the source value is invalid
3702 * DISP_E_OVERFLOW, if the value will not fit in the destination
3703 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3705 HRESULT WINAPI
VarCyFromDec(DECIMAL
* pdecIn
, CY
* pCyOut
)
3710 hRet
= VarDecRound(pdecIn
, 4, &rounded
);
3712 if (SUCCEEDED(hRet
))
3716 if (DEC_HI32(&rounded
))
3717 return DISP_E_OVERFLOW
;
3719 /* Note: Without the casts this promotes to int64 which loses precision */
3720 d
= (double)DEC_LO64(&rounded
) / (double)CY_Divisors
[DEC_SCALE(&rounded
)];
3721 if (DEC_SIGN(&rounded
))
3723 return VarCyFromR8(d
, pCyOut
);
3728 /************************************************************************
3729 * VarCyFromI8 (OLEAUT32.366)
3731 * Convert a VT_I8 to a VT_CY.
3735 * pCyOut [O] Destination
3739 * Failure: E_INVALIDARG, if the source value is invalid
3740 * DISP_E_OVERFLOW, if the value will not fit in the destination
3741 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3743 HRESULT WINAPI
VarCyFromI8(LONG64 llIn
, CY
* pCyOut
)
3745 if (llIn
<= (I8_MIN
/CY_MULTIPLIER
) || llIn
>= (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3746 pCyOut
->int64
= llIn
* CY_MULTIPLIER
;
3750 /************************************************************************
3751 * VarCyFromUI8 (OLEAUT32.375)
3753 * Convert a VT_UI8 to a VT_CY.
3757 * pCyOut [O] Destination
3761 * Failure: E_INVALIDARG, if the source value is invalid
3762 * DISP_E_OVERFLOW, if the value will not fit in the destination
3763 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3765 HRESULT WINAPI
VarCyFromUI8(ULONG64 ullIn
, CY
* pCyOut
)
3767 if (ullIn
>= (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3768 pCyOut
->int64
= ullIn
* CY_MULTIPLIER
;
3772 /************************************************************************
3773 * VarCyAdd (OLEAUT32.299)
3775 * Add one CY to another.
3779 * cyRight [I] Value to add
3780 * pCyOut [O] Destination
3784 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3786 HRESULT WINAPI
VarCyAdd(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3789 _VarR8FromCy(cyLeft
, &l
);
3790 _VarR8FromCy(cyRight
, &r
);
3792 return VarCyFromR8(l
, pCyOut
);
3795 /************************************************************************
3796 * VarCyMul (OLEAUT32.303)
3798 * Multiply one CY by another.
3802 * cyRight [I] Value to multiply by
3803 * pCyOut [O] Destination
3807 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3809 HRESULT WINAPI
VarCyMul(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3812 _VarR8FromCy(cyLeft
, &l
);
3813 _VarR8FromCy(cyRight
, &r
);
3815 return VarCyFromR8(l
, pCyOut
);
3818 /************************************************************************
3819 * VarCyMulI4 (OLEAUT32.304)
3821 * Multiply one CY by a VT_I4.
3825 * lRight [I] Value to multiply by
3826 * pCyOut [O] Destination
3830 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3832 HRESULT WINAPI
VarCyMulI4(const CY cyLeft
, LONG lRight
, CY
* pCyOut
)
3836 _VarR8FromCy(cyLeft
, &d
);
3838 return VarCyFromR8(d
, pCyOut
);
3841 /************************************************************************
3842 * VarCySub (OLEAUT32.305)
3844 * Subtract one CY from another.
3848 * cyRight [I] Value to subtract
3849 * pCyOut [O] Destination
3853 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3855 HRESULT WINAPI
VarCySub(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3858 _VarR8FromCy(cyLeft
, &l
);
3859 _VarR8FromCy(cyRight
, &r
);
3861 return VarCyFromR8(l
, pCyOut
);
3864 /************************************************************************
3865 * VarCyAbs (OLEAUT32.306)
3867 * Convert a VT_CY into its absolute value.
3871 * pCyOut [O] Destination
3874 * Success: S_OK. pCyOut contains the absolute value.
3875 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3877 HRESULT WINAPI
VarCyAbs(const CY cyIn
, CY
* pCyOut
)
3879 if (cyIn
.s
.Hi
== (int)0x80000000 && !cyIn
.s
.Lo
)
3880 return DISP_E_OVERFLOW
;
3882 pCyOut
->int64
= cyIn
.int64
< 0 ? -cyIn
.int64
: cyIn
.int64
;
3886 /************************************************************************
3887 * VarCyFix (OLEAUT32.307)
3889 * Return the integer part of a VT_CY.
3893 * pCyOut [O] Destination
3897 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3900 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3901 * negative numbers away from 0, while this function rounds them towards zero.
3903 HRESULT WINAPI
VarCyFix(const CY cyIn
, CY
* pCyOut
)
3905 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3906 pCyOut
->int64
*= CY_MULTIPLIER
;
3910 /************************************************************************
3911 * VarCyInt (OLEAUT32.308)
3913 * Return the integer part of a VT_CY.
3917 * pCyOut [O] Destination
3921 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3924 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3925 * negative numbers towards 0, while this function rounds them away from zero.
3927 HRESULT WINAPI
VarCyInt(const CY cyIn
, CY
* pCyOut
)
3929 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3930 pCyOut
->int64
*= CY_MULTIPLIER
;
3932 if (cyIn
.int64
< 0 && cyIn
.int64
% CY_MULTIPLIER
!= 0)
3934 pCyOut
->int64
-= CY_MULTIPLIER
;
3939 /************************************************************************
3940 * VarCyNeg (OLEAUT32.309)
3942 * Change the sign of a VT_CY.
3946 * pCyOut [O] Destination
3950 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3952 HRESULT WINAPI
VarCyNeg(const CY cyIn
, CY
* pCyOut
)
3954 if (cyIn
.s
.Hi
== (int)0x80000000 && !cyIn
.s
.Lo
)
3955 return DISP_E_OVERFLOW
;
3957 pCyOut
->int64
= -cyIn
.int64
;
3961 /************************************************************************
3962 * VarCyRound (OLEAUT32.310)
3964 * Change the precision of a VT_CY.
3968 * cDecimals [I] New number of decimals to keep
3969 * pCyOut [O] Destination
3973 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3975 HRESULT WINAPI
VarCyRound(const CY cyIn
, int cDecimals
, CY
* pCyOut
)
3978 return E_INVALIDARG
;
3982 /* Rounding to more precision than we have */
3988 double d
, div
= CY_Divisors
[cDecimals
];
3990 _VarR8FromCy(cyIn
, &d
);
3992 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
3993 d
= (double)pCyOut
->int64
/ div
* CY_MULTIPLIER_F
;
3994 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
3999 /************************************************************************
4000 * VarCyCmp (OLEAUT32.311)
4002 * Compare two VT_CY values.
4006 * cyRight [I] Value to compare
4009 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4010 * compare is less, equal or greater than source respectively.
4011 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4013 HRESULT WINAPI
VarCyCmp(const CY cyLeft
, const CY cyRight
)
4018 /* Subtract right from left, and compare the result to 0 */
4019 hRet
= VarCySub(cyLeft
, cyRight
, &result
);
4021 if (SUCCEEDED(hRet
))
4023 if (result
.int64
< 0)
4024 hRet
= (HRESULT
)VARCMP_LT
;
4025 else if (result
.int64
> 0)
4026 hRet
= (HRESULT
)VARCMP_GT
;
4028 hRet
= (HRESULT
)VARCMP_EQ
;
4033 /************************************************************************
4034 * VarCyCmpR8 (OLEAUT32.312)
4036 * Compare a VT_CY to a double
4039 * cyLeft [I] Currency Source
4040 * dblRight [I] double to compare to cyLeft
4043 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4044 * less than, equal to or greater than cyLeft respectively.
4045 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4047 HRESULT WINAPI
VarCyCmpR8(const CY cyLeft
, double dblRight
)
4052 hRet
= VarCyFromR8(dblRight
, &cyRight
);
4054 if (SUCCEEDED(hRet
))
4055 hRet
= VarCyCmp(cyLeft
, cyRight
);
4060 /************************************************************************
4061 * VarCyMulI8 (OLEAUT32.329)
4063 * Multiply a VT_CY by a VT_I8.
4067 * llRight [I] Value to multiply by
4068 * pCyOut [O] Destination
4072 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4074 HRESULT WINAPI
VarCyMulI8(const CY cyLeft
, LONG64 llRight
, CY
* pCyOut
)
4078 _VarR8FromCy(cyLeft
, &d
);
4079 d
= d
* (double)llRight
;
4080 return VarCyFromR8(d
, pCyOut
);
4086 /************************************************************************
4087 * VarDecFromUI1 (OLEAUT32.190)
4089 * Convert a VT_UI1 to a DECIMAL.
4093 * pDecOut [O] Destination
4098 HRESULT WINAPI
VarDecFromUI1(BYTE bIn
, DECIMAL
* pDecOut
)
4100 return VarDecFromUI4(bIn
, pDecOut
);
4103 /************************************************************************
4104 * VarDecFromI2 (OLEAUT32.191)
4106 * Convert a VT_I2 to a DECIMAL.
4110 * pDecOut [O] Destination
4115 HRESULT WINAPI
VarDecFromI2(SHORT sIn
, DECIMAL
* pDecOut
)
4117 return VarDecFromI4(sIn
, pDecOut
);
4120 /************************************************************************
4121 * VarDecFromI4 (OLEAUT32.192)
4123 * Convert a VT_I4 to a DECIMAL.
4127 * pDecOut [O] Destination
4132 HRESULT WINAPI
VarDecFromI4(LONG lIn
, DECIMAL
* pDecOut
)
4134 DEC_HI32(pDecOut
) = 0;
4135 DEC_MID32(pDecOut
) = 0;
4139 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4140 DEC_LO32(pDecOut
) = -lIn
;
4144 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4145 DEC_LO32(pDecOut
) = lIn
;
4150 #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT))
4152 /* internal representation of the value stored in a DECIMAL. The bytes are
4153 stored from LSB at index 0 to MSB at index 11
4155 typedef struct DECIMAL_internal
4157 DWORD bitsnum
[3]; /* 96 significant bits, unsigned */
4158 unsigned char scale
; /* number scaled * 10 ^ -(scale) */
4159 unsigned int sign
: 1; /* 0 - positive, 1 - negative */
4162 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
);
4163 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
);
4164 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
);
4165 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
);
4167 /************************************************************************
4168 * VarDecFromR4 (OLEAUT32.193)
4170 * Convert a VT_R4 to a DECIMAL.
4174 * pDecOut [O] Destination
4179 HRESULT WINAPI
VarDecFromR4(FLOAT fltIn
, DECIMAL
* pDecOut
)
4184 hres
= VARIANT_DI_FromR4(fltIn
, &di
);
4185 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4189 /************************************************************************
4190 * VarDecFromR8 (OLEAUT32.194)
4192 * Convert a VT_R8 to a DECIMAL.
4196 * pDecOut [O] Destination
4201 HRESULT WINAPI
VarDecFromR8(double dblIn
, DECIMAL
* pDecOut
)
4206 hres
= VARIANT_DI_FromR8(dblIn
, &di
);
4207 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4211 /************************************************************************
4212 * VarDecFromDate (OLEAUT32.195)
4214 * Convert a VT_DATE to a DECIMAL.
4218 * pDecOut [O] Destination
4223 HRESULT WINAPI
VarDecFromDate(DATE dateIn
, DECIMAL
* pDecOut
)
4225 return VarDecFromR8(dateIn
, pDecOut
);
4228 /************************************************************************
4229 * VarDecFromCy (OLEAUT32.196)
4231 * Convert a VT_CY to a DECIMAL.
4235 * pDecOut [O] Destination
4240 HRESULT WINAPI
VarDecFromCy(CY cyIn
, DECIMAL
* pDecOut
)
4242 DEC_HI32(pDecOut
) = 0;
4244 /* Note: This assumes 2s complement integer representation */
4245 if (cyIn
.s
.Hi
& 0x80000000)
4247 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,4);
4248 DEC_LO64(pDecOut
) = -cyIn
.int64
;
4252 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,4);
4253 DEC_MID32(pDecOut
) = cyIn
.s
.Hi
;
4254 DEC_LO32(pDecOut
) = cyIn
.s
.Lo
;
4259 /************************************************************************
4260 * VarDecFromStr (OLEAUT32.197)
4262 * Convert a VT_BSTR to a DECIMAL.
4266 * lcid [I] LCID for the conversion
4267 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4268 * pDecOut [O] Destination
4272 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4274 HRESULT WINAPI
VarDecFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DECIMAL
* pDecOut
)
4276 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDecOut
, VT_DECIMAL
);
4279 /************************************************************************
4280 * VarDecFromDisp (OLEAUT32.198)
4282 * Convert a VT_DISPATCH to a DECIMAL.
4285 * pdispIn [I] Source
4286 * lcid [I] LCID for conversion
4287 * pDecOut [O] Destination
4291 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4293 HRESULT WINAPI
VarDecFromDisp(IDispatch
* pdispIn
, LCID lcid
, DECIMAL
* pDecOut
)
4295 return VARIANT_FromDisp(pdispIn
, lcid
, pDecOut
, VT_DECIMAL
, 0);
4298 /************************************************************************
4299 * VarDecFromBool (OLEAUT32.199)
4301 * Convert a VT_BOOL to a DECIMAL.
4305 * pDecOut [O] Destination
4311 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4313 HRESULT WINAPI
VarDecFromBool(VARIANT_BOOL bIn
, DECIMAL
* pDecOut
)
4315 DEC_HI32(pDecOut
) = 0;
4316 DEC_MID32(pDecOut
) = 0;
4319 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4320 DEC_LO32(pDecOut
) = 1;
4324 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4325 DEC_LO32(pDecOut
) = 0;
4330 /************************************************************************
4331 * VarDecFromI1 (OLEAUT32.241)
4333 * Convert a VT_I1 to a DECIMAL.
4337 * pDecOut [O] Destination
4342 HRESULT WINAPI
VarDecFromI1(signed char cIn
, DECIMAL
* pDecOut
)
4344 return VarDecFromI4(cIn
, pDecOut
);
4347 /************************************************************************
4348 * VarDecFromUI2 (OLEAUT32.242)
4350 * Convert a VT_UI2 to a DECIMAL.
4354 * pDecOut [O] Destination
4359 HRESULT WINAPI
VarDecFromUI2(USHORT usIn
, DECIMAL
* pDecOut
)
4361 return VarDecFromUI4(usIn
, pDecOut
);
4364 /************************************************************************
4365 * VarDecFromUI4 (OLEAUT32.243)
4367 * Convert a VT_UI4 to a DECIMAL.
4371 * pDecOut [O] Destination
4376 HRESULT WINAPI
VarDecFromUI4(ULONG ulIn
, DECIMAL
* pDecOut
)
4378 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4379 DEC_HI32(pDecOut
) = 0;
4380 DEC_MID32(pDecOut
) = 0;
4381 DEC_LO32(pDecOut
) = ulIn
;
4385 /************************************************************************
4386 * VarDecFromI8 (OLEAUT32.374)
4388 * Convert a VT_I8 to a DECIMAL.
4392 * pDecOut [O] Destination
4397 HRESULT WINAPI
VarDecFromI8(LONG64 llIn
, DECIMAL
* pDecOut
)
4399 PULARGE_INTEGER pLi
= (PULARGE_INTEGER
)&llIn
;
4401 DEC_HI32(pDecOut
) = 0;
4403 /* Note: This assumes 2s complement integer representation */
4404 if (pLi
->u
.HighPart
& 0x80000000)
4406 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4407 DEC_LO64(pDecOut
) = -pLi
->QuadPart
;
4411 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4412 DEC_MID32(pDecOut
) = pLi
->u
.HighPart
;
4413 DEC_LO32(pDecOut
) = pLi
->u
.LowPart
;
4418 /************************************************************************
4419 * VarDecFromUI8 (OLEAUT32.375)
4421 * Convert a VT_UI8 to a DECIMAL.
4425 * pDecOut [O] Destination
4430 HRESULT WINAPI
VarDecFromUI8(ULONG64 ullIn
, DECIMAL
* pDecOut
)
4432 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4433 DEC_HI32(pDecOut
) = 0;
4434 DEC_LO64(pDecOut
) = ullIn
;
4438 /* Make two DECIMALS the same scale; used by math functions below */
4439 static HRESULT
VARIANT_DecScale(const DECIMAL
** ppDecLeft
,
4440 const DECIMAL
** ppDecRight
,
4443 static DECIMAL scaleFactor
;
4446 HRESULT hRet
= S_OK
;
4448 if (DEC_SIGN(*ppDecLeft
) & ~DECIMAL_NEG
|| DEC_SIGN(*ppDecRight
) & ~DECIMAL_NEG
)
4449 return E_INVALIDARG
;
4451 DEC_LO32(&scaleFactor
) = 10;
4453 i
= scaleAmount
= DEC_SCALE(*ppDecLeft
) - DEC_SCALE(*ppDecRight
);
4456 return S_OK
; /* Same scale */
4458 if (scaleAmount
> 0)
4460 decTemp
= *(*ppDecRight
); /* Left is bigger - scale the right hand side */
4461 *ppDecRight
= pDecOut
;
4465 decTemp
= *(*ppDecLeft
); /* Right is bigger - scale the left hand side */
4466 *ppDecLeft
= pDecOut
;
4467 i
= scaleAmount
= -scaleAmount
;
4470 if (DEC_SCALE(&decTemp
) + scaleAmount
> DEC_MAX_SCALE
)
4471 return DISP_E_OVERFLOW
; /* Can't scale up */
4473 /* Multiply up the value to be scaled by the correct amount */
4474 while (SUCCEEDED(hRet
) && i
--)
4476 /* Note we are multiplying by a value with a scale of 0, so we don't recurse */
4477 hRet
= VarDecMul(&decTemp
, &scaleFactor
, pDecOut
);
4480 DEC_SCALE(pDecOut
) += scaleAmount
; /* Set the new scale */
4484 /* Add two unsigned 32 bit values with overflow */
4485 static ULONG
VARIANT_Add(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4487 ULARGE_INTEGER ul64
;
4489 ul64
.QuadPart
= (ULONG64
)ulLeft
+ (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4490 *pulHigh
= ul64
.u
.HighPart
;
4491 return ul64
.u
.LowPart
;
4494 /* Subtract two unsigned 32 bit values with underflow */
4495 static ULONG
VARIANT_Sub(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4498 ULARGE_INTEGER ul64
;
4500 ul64
.QuadPart
= (LONG64
)ulLeft
- (ULONG64
)ulRight
;
4501 if (ulLeft
< ulRight
)
4504 if (ul64
.QuadPart
> (ULONG64
)*pulHigh
)
4505 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4508 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4512 ul64
.u
.HighPart
= -ul64
.u
.HighPart
;
4514 *pulHigh
= ul64
.u
.HighPart
;
4515 return ul64
.u
.LowPart
;
4518 /* Multiply two unsigned 32 bit values with overflow */
4519 static ULONG
VARIANT_Mul(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4521 ULARGE_INTEGER ul64
;
4523 ul64
.QuadPart
= (ULONG64
)ulLeft
* (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4524 *pulHigh
= ul64
.u
.HighPart
;
4525 return ul64
.u
.LowPart
;
4528 /* Compare two decimals that have the same scale */
4529 static inline int VARIANT_DecCmp(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
)
4531 if ( DEC_HI32(pDecLeft
) < DEC_HI32(pDecRight
) ||
4532 (DEC_HI32(pDecLeft
) <= DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) < DEC_LO64(pDecRight
)))
4534 else if (DEC_HI32(pDecLeft
) == DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) == DEC_LO64(pDecRight
))
4539 /************************************************************************
4540 * VarDecAdd (OLEAUT32.177)
4542 * Add one DECIMAL to another.
4545 * pDecLeft [I] Source
4546 * pDecRight [I] Value to add
4547 * pDecOut [O] Destination
4551 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4553 HRESULT WINAPI
VarDecAdd(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
4558 hRet
= VARIANT_DecScale(&pDecLeft
, &pDecRight
, &scaled
);
4560 if (SUCCEEDED(hRet
))
4562 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4564 BYTE sign
= DECIMAL_POS
;
4566 /* Correct for the sign of the result */
4567 if (DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4569 /* -x + -y : Negative */
4571 goto VarDecAdd_AsPositive
;
4573 else if (DEC_SIGN(pDecLeft
) && !DEC_SIGN(pDecRight
))
4575 int cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4577 /* -x + y : Negative if x > y */
4581 VarDecAdd_AsNegative
:
4582 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4583 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4584 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4588 VarDecAdd_AsInvertedNegative
:
4589 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecRight
), DEC_LO32(pDecLeft
), &overflow
);
4590 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecRight
), DEC_MID32(pDecLeft
), &overflow
);
4591 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecRight
), DEC_HI32(pDecLeft
), &overflow
);
4594 else if (!DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4596 int cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4598 /* x + -y : Negative if x <= y */
4602 goto VarDecAdd_AsInvertedNegative
;
4604 goto VarDecAdd_AsNegative
;
4608 /* x + y : Positive */
4609 VarDecAdd_AsPositive
:
4610 DEC_LO32(pDecOut
) = VARIANT_Add(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4611 DEC_MID32(pDecOut
) = VARIANT_Add(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4612 DEC_HI32(pDecOut
) = VARIANT_Add(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4616 return DISP_E_OVERFLOW
; /* overflowed */
4618 DEC_SCALE(pDecOut
) = DEC_SCALE(pDecLeft
);
4619 DEC_SIGN(pDecOut
) = sign
;
4624 /* translate from external DECIMAL format into an internal representation */
4625 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
)
4627 to
->scale
= DEC_SCALE(from
);
4628 to
->sign
= DEC_SIGN(from
) ? 1 : 0;
4630 to
->bitsnum
[0] = DEC_LO32(from
);
4631 to
->bitsnum
[1] = DEC_MID32(from
);
4632 to
->bitsnum
[2] = DEC_HI32(from
);
4635 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
)
4638 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_NEG
, from
->scale
);
4640 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_POS
, from
->scale
);
4643 DEC_LO32(to
) = from
->bitsnum
[0];
4644 DEC_MID32(to
) = from
->bitsnum
[1];
4645 DEC_HI32(to
) = from
->bitsnum
[2];
4648 /* clear an internal representation of a DECIMAL */
4649 static void VARIANT_DI_clear(VARIANT_DI
* i
)
4651 memset(i
, 0, sizeof(VARIANT_DI
));
4654 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4655 size is supported. The value in p is replaced by the quotient of the division, and
4656 the remainder is returned as a result. This routine is most often used with a divisor
4657 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4659 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
)
4664 } else if (divisor
== 1) {
4665 /* dividend remains unchanged */
4668 unsigned char remainder
= 0;
4669 ULONGLONG iTempDividend
;
4672 for (i
= n
- 1; i
>= 0 && !p
[i
]; i
--); /* skip leading zeros */
4673 for (; i
>= 0; i
--) {
4674 iTempDividend
= ((ULONGLONG
)remainder
<< 32) + p
[i
];
4675 remainder
= iTempDividend
% divisor
;
4676 p
[i
] = iTempDividend
/ divisor
;
4683 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4684 static int VARIANT_int_iszero(const DWORD
* p
, unsigned int n
)
4686 for (; n
> 0; n
--) if (*p
++ != 0) return 0;
4690 /* multiply two DECIMALS, without changing either one, and place result in third
4691 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4692 digits when scale > 0 in order to fit an overflowing result. Final overflow
4695 static int VARIANT_DI_mul(const VARIANT_DI
* a
, const VARIANT_DI
* b
, VARIANT_DI
* result
)
4699 signed int mulstart
;
4701 VARIANT_DI_clear(result
);
4702 result
->sign
= (a
->sign
^ b
->sign
) ? 1 : 0;
4704 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4705 of the result is formed by adding the scales of the operands.
4707 result
->scale
= a
->scale
+ b
->scale
;
4708 memset(running
, 0, sizeof(running
));
4710 /* count number of leading zero-bytes in operand A */
4711 for (mulstart
= sizeof(a
->bitsnum
)/sizeof(DWORD
) - 1; mulstart
>= 0 && !a
->bitsnum
[mulstart
]; mulstart
--);
4713 /* result is 0, because operand A is 0 */
4717 unsigned char remainder
= 0;
4720 /* perform actual multiplication */
4721 for (iA
= 0; iA
<= mulstart
; iA
++) {
4725 for (iOverflowMul
= 0, iB
= 0; iB
< sizeof(b
->bitsnum
)/sizeof(DWORD
); iB
++) {
4729 iRV
= VARIANT_Mul(b
->bitsnum
[iB
], a
->bitsnum
[iA
], &iOverflowMul
);
4732 running
[iR
] = VARIANT_Add(running
[iR
], 0, &iRV
);
4738 /* Too bad - native oleaut does not do this, so we should not either */
4740 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4741 This operation should not lose significant digits, and gives an
4742 opportunity to reduce the possibility of overflows in future
4743 operations issued by the application.
4745 while (result
->scale
> 0) {
4746 memcpy(quotient
, running
, sizeof(quotient
));
4747 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4748 if (remainder
> 0) break;
4749 memcpy(running
, quotient
, sizeof(quotient
));
4753 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4754 This operation *will* lose significant digits of the result because
4755 all the factors of 10 were consumed by the previous operation.
4757 while (result
->scale
> 0 && !VARIANT_int_iszero(
4758 running
+ sizeof(result
->bitsnum
) / sizeof(DWORD
),
4759 (sizeof(running
) - sizeof(result
->bitsnum
)) / sizeof(DWORD
))) {
4761 remainder
= VARIANT_int_divbychar(running
, sizeof(running
) / sizeof(DWORD
), 10);
4762 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4766 /* round up the result - native oleaut32 does this */
4767 if (remainder
>= 5) {
4769 for (remainder
= 1, i
= 0; i
< sizeof(running
)/sizeof(DWORD
) && remainder
; i
++) {
4770 ULONGLONG digit
= running
[i
] + 1;
4771 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4772 running
[i
] = digit
& 0xFFFFFFFF;
4776 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4777 and copy result bits into result structure
4779 r_overflow
= !VARIANT_int_iszero(
4780 running
+ sizeof(result
->bitsnum
)/sizeof(DWORD
),
4781 (sizeof(running
) - sizeof(result
->bitsnum
))/sizeof(DWORD
));
4782 memcpy(result
->bitsnum
, running
, sizeof(result
->bitsnum
));
4787 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4788 hardcoded (period for decimal separator, dash as negative sign). Returns 0 for
4789 success, nonzero if insufficient space in output buffer.
4791 static int VARIANT_DI_tostringW(const VARIANT_DI
* a
, WCHAR
* s
, unsigned int n
)
4795 unsigned char remainder
;
4798 /* place negative sign */
4799 if (!VARIANT_int_iszero(a
->bitsnum
, sizeof(a
->bitsnum
) / sizeof(DWORD
)) && a
->sign
) {
4807 /* prepare initial 0 */
4812 } else overflow
= 1;
4816 memcpy(quotient
, a
->bitsnum
, sizeof(a
->bitsnum
));
4817 while (!overflow
&& !VARIANT_int_iszero(quotient
, sizeof(quotient
) / sizeof(DWORD
))) {
4818 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4822 s
[i
++] = '0' + remainder
;
4827 if (!overflow
&& !VARIANT_int_iszero(a
->bitsnum
, sizeof(a
->bitsnum
) / sizeof(DWORD
))) {
4829 /* reverse order of digits */
4830 WCHAR
* x
= s
; WCHAR
* y
= s
+ i
- 1;
4837 /* check for decimal point. "i" now has string length */
4838 if (i
<= a
->scale
) {
4839 unsigned int numzeroes
= a
->scale
+ 1 - i
;
4840 if (i
+ 1 + numzeroes
>= n
) {
4843 memmove(s
+ numzeroes
, s
, (i
+ 1) * sizeof(WCHAR
));
4845 while (numzeroes
> 0) {
4846 s
[--numzeroes
] = '0';
4851 /* place decimal point */
4853 unsigned int periodpos
= i
- a
->scale
;
4857 memmove(s
+ periodpos
+ 1, s
+ periodpos
, (i
+ 1 - periodpos
) * sizeof(WCHAR
));
4858 s
[periodpos
] = '.'; i
++;
4860 /* remove extra zeros at the end, if any */
4861 while (s
[i
- 1] == '0') s
[--i
] = '\0';
4862 if (s
[i
- 1] == '.') s
[--i
] = '\0';
4870 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4871 static void VARIANT_int_shiftleft(DWORD
* p
, unsigned int n
, unsigned int shift
)
4876 /* shift whole DWORDs to the left */
4879 memmove(p
+ 1, p
, (n
- 1) * sizeof(DWORD
));
4880 *p
= 0; shift
-= 32;
4883 /* shift remainder (1..31 bits) */
4885 if (shift
> 0) for (i
= 0; i
< n
; i
++)
4888 b
= p
[i
] >> (32 - shift
);
4889 p
[i
] = (p
[i
] << shift
) | shifted
;
4894 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4895 Value at v is incremented by the value at p. Any size is supported, provided
4896 that v is not shorter than p. Any unapplied carry is returned as a result.
4898 static unsigned char VARIANT_int_add(DWORD
* v
, unsigned int nv
, const DWORD
* p
,
4901 unsigned char carry
= 0;
4907 for (i
= 0; i
< np
; i
++) {
4908 sum
= (ULONGLONG
)v
[i
]
4911 v
[i
] = sum
& 0xffffffff;
4914 for (; i
< nv
&& carry
; i
++) {
4915 sum
= (ULONGLONG
)v
[i
]
4917 v
[i
] = sum
& 0xffffffff;
4924 /* perform integral division with operand p as dividend. Parameter n indicates
4925 number of available DWORDs in divisor p, but available space in p must be
4926 actually at least 2 * n DWORDs, because the remainder of the integral
4927 division is built in the next n DWORDs past the start of the quotient. This
4928 routine replaces the dividend in p with the quotient, and appends n
4929 additional DWORDs for the remainder.
4931 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4932 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4933 source code to the VLI (Very Large Integer) division operator. This algorithm
4934 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4935 variably-scaled integers such as the MS DECIMAL representation.
4937 static void VARIANT_int_div(DWORD
* p
, unsigned int n
, const DWORD
* divisor
,
4942 DWORD
* negdivisor
= tempsub
+ n
;
4944 /* build 2s-complement of divisor */
4945 for (i
= 0; i
< n
; i
++) negdivisor
[i
] = (i
< dn
) ? ~divisor
[i
] : 0xFFFFFFFF;
4947 VARIANT_int_add(negdivisor
, n
, p
+ n
, 1);
4948 memset(p
+ n
, 0, n
* sizeof(DWORD
));
4950 /* skip all leading zero DWORDs in quotient */
4951 for (i
= 0; i
< n
&& !p
[n
- 1]; i
++) VARIANT_int_shiftleft(p
, n
, 32);
4952 /* i is now number of DWORDs left to process */
4953 for (i
<<= 5; i
< (n
<< 5); i
++) {
4954 VARIANT_int_shiftleft(p
, n
<< 1, 1); /* shl quotient+remainder */
4956 /* trial subtraction */
4957 memcpy(tempsub
, p
+ n
, n
* sizeof(DWORD
));
4958 VARIANT_int_add(tempsub
, n
, negdivisor
, n
);
4960 /* check whether result of subtraction was negative */
4961 if ((tempsub
[n
- 1] & 0x80000000) == 0) {
4962 memcpy(p
+ n
, tempsub
, n
* sizeof(DWORD
));
4968 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4969 static unsigned char VARIANT_int_mulbychar(DWORD
* p
, unsigned int n
, unsigned char m
)
4974 for (iOverflowMul
= 0, i
= 0; i
< n
; i
++)
4975 p
[i
] = VARIANT_Mul(p
[i
], m
, &iOverflowMul
);
4976 return (unsigned char)iOverflowMul
;
4979 /* increment value in A by the value indicated in B, with scale adjusting.
4980 Modifies parameters by adjusting scales. Returns 0 if addition was
4981 successful, nonzero if a parameter underflowed before it could be
4982 successfully used in the addition.
4984 static int VARIANT_int_addlossy(
4985 DWORD
* a
, int * ascale
, unsigned int an
,
4986 DWORD
* b
, int * bscale
, unsigned int bn
)
4990 if (VARIANT_int_iszero(a
, an
)) {
4991 /* if A is zero, copy B into A, after removing digits */
4992 while (bn
> an
&& !VARIANT_int_iszero(b
+ an
, bn
- an
)) {
4993 VARIANT_int_divbychar(b
, bn
, 10);
4996 memcpy(a
, b
, an
* sizeof(DWORD
));
4998 } else if (!VARIANT_int_iszero(b
, bn
)) {
4999 unsigned int tn
= an
+ 1;
5002 if (bn
+ 1 > tn
) tn
= bn
+ 1;
5003 if (*ascale
!= *bscale
) {
5004 /* first (optimistic) try - try to scale down the one with the bigger
5005 scale, while this number is divisible by 10 */
5006 DWORD
* digitchosen
;
5007 unsigned int nchosen
;
5011 if (*ascale
< *bscale
) {
5012 targetscale
= *ascale
;
5013 scalechosen
= bscale
;
5017 targetscale
= *bscale
;
5018 scalechosen
= ascale
;
5022 memset(t
, 0, tn
* sizeof(DWORD
));
5023 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5025 /* divide by 10 until target scale is reached */
5026 while (*scalechosen
> targetscale
) {
5027 unsigned char remainder
= VARIANT_int_divbychar(t
, tn
, 10);
5030 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5035 if (*ascale
!= *bscale
) {
5036 DWORD
* digitchosen
;
5037 unsigned int nchosen
;
5041 /* try to scale up the one with the smaller scale */
5042 if (*ascale
> *bscale
) {
5043 targetscale
= *ascale
;
5044 scalechosen
= bscale
;
5048 targetscale
= *bscale
;
5049 scalechosen
= ascale
;
5053 memset(t
, 0, tn
* sizeof(DWORD
));
5054 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5056 /* multiply by 10 until target scale is reached, or
5057 significant bytes overflow the number
5059 while (*scalechosen
< targetscale
&& t
[nchosen
] == 0) {
5060 VARIANT_int_mulbychar(t
, tn
, 10);
5061 if (t
[nchosen
] == 0) {
5062 /* still does not overflow */
5064 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5069 if (*ascale
!= *bscale
) {
5070 /* still different? try to scale down the one with the bigger scale
5071 (this *will* lose significant digits) */
5072 DWORD
* digitchosen
;
5073 unsigned int nchosen
;
5077 if (*ascale
< *bscale
) {
5078 targetscale
= *ascale
;
5079 scalechosen
= bscale
;
5083 targetscale
= *bscale
;
5084 scalechosen
= ascale
;
5088 memset(t
, 0, tn
* sizeof(DWORD
));
5089 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5091 /* divide by 10 until target scale is reached */
5092 while (*scalechosen
> targetscale
) {
5093 VARIANT_int_divbychar(t
, tn
, 10);
5095 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5099 /* check whether any of the operands still has significant digits
5102 if (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
)) {
5105 /* at this step, both numbers have the same scale and can be added
5106 as integers. However, the result might not fit in A, so further
5107 scaling down might be necessary.
5109 while (!underflow
) {
5110 memset(t
, 0, tn
* sizeof(DWORD
));
5111 memcpy(t
, a
, an
* sizeof(DWORD
));
5113 VARIANT_int_add(t
, tn
, b
, bn
);
5114 if (VARIANT_int_iszero(t
+ an
, tn
- an
)) {
5115 /* addition was successful */
5116 memcpy(a
, t
, an
* sizeof(DWORD
));
5119 /* addition overflowed - remove significant digits
5120 from both operands and try again */
5121 VARIANT_int_divbychar(a
, an
, 10); (*ascale
)--;
5122 VARIANT_int_divbychar(b
, bn
, 10); (*bscale
)--;
5123 /* check whether any operand keeps significant digits after
5124 scaledown (underflow case 2)
5126 underflow
= (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
));
5134 /* perform complete DECIMAL division in the internal representation. Returns
5135 0 if the division was completed (even if quotient is set to 0), or nonzero
5136 in case of quotient overflow.
5138 static HRESULT
VARIANT_DI_div(const VARIANT_DI
* dividend
, const VARIANT_DI
* divisor
,
5139 VARIANT_DI
* quotient
)
5141 HRESULT r_overflow
= S_OK
;
5143 if (VARIANT_int_iszero(divisor
->bitsnum
, sizeof(divisor
->bitsnum
)/sizeof(DWORD
))) {
5145 r_overflow
= DISP_E_DIVBYZERO
;
5146 } else if (VARIANT_int_iszero(dividend
->bitsnum
, sizeof(dividend
->bitsnum
)/sizeof(DWORD
))) {
5147 VARIANT_DI_clear(quotient
);
5149 int quotientscale
, remainderscale
, tempquotientscale
;
5150 DWORD remainderplusquotient
[8];
5153 quotientscale
= remainderscale
= (int)dividend
->scale
- (int)divisor
->scale
;
5154 tempquotientscale
= quotientscale
;
5155 VARIANT_DI_clear(quotient
);
5156 quotient
->sign
= (dividend
->sign
^ divisor
->sign
) ? 1 : 0;
5158 /* The following strategy is used for division
5159 1) if there was a nonzero remainder from previous iteration, use it as
5160 dividend for this iteration, else (for first iteration) use intended
5162 2) perform integer division in temporary buffer, develop quotient in
5163 low-order part, remainder in high-order part
5164 3) add quotient from step 2 to final result, with possible loss of
5166 4) multiply integer part of remainder by 10, while incrementing the
5167 scale of the remainder. This operation preserves the intended value
5169 5) loop to step 1 until one of the following is true:
5170 a) remainder is zero (exact division achieved)
5171 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5173 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5174 memcpy(remainderplusquotient
, dividend
->bitsnum
, sizeof(dividend
->bitsnum
));
5177 remainderplusquotient
, 4,
5178 divisor
->bitsnum
, sizeof(divisor
->bitsnum
)/sizeof(DWORD
));
5179 underflow
= VARIANT_int_addlossy(
5180 quotient
->bitsnum
, "ientscale
, sizeof(quotient
->bitsnum
) / sizeof(DWORD
),
5181 remainderplusquotient
, &tempquotientscale
, 4);
5182 VARIANT_int_mulbychar(remainderplusquotient
+ 4, 4, 10);
5183 memcpy(remainderplusquotient
, remainderplusquotient
+ 4, 4 * sizeof(DWORD
));
5184 tempquotientscale
= ++remainderscale
;
5185 } while (!underflow
&& !VARIANT_int_iszero(remainderplusquotient
+ 4, 4));
5187 /* quotient scale might now be negative (extremely big number). If, so, try
5188 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5189 until scale is 0. If this cannot be done, it is a real overflow.
5191 while (r_overflow
== S_OK
&& quotientscale
< 0) {
5192 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5193 memcpy(remainderplusquotient
, quotient
->bitsnum
, sizeof(quotient
->bitsnum
));
5194 VARIANT_int_mulbychar(remainderplusquotient
, sizeof(remainderplusquotient
)/sizeof(DWORD
), 10);
5195 if (VARIANT_int_iszero(remainderplusquotient
+ sizeof(quotient
->bitsnum
)/sizeof(DWORD
),
5196 (sizeof(remainderplusquotient
) - sizeof(quotient
->bitsnum
))/sizeof(DWORD
))) {
5198 memcpy(quotient
->bitsnum
, remainderplusquotient
, sizeof(quotient
->bitsnum
));
5199 } else r_overflow
= DISP_E_OVERFLOW
;
5201 if (r_overflow
== S_OK
) {
5202 if (quotientscale
<= 255) quotient
->scale
= quotientscale
;
5203 else VARIANT_DI_clear(quotient
);
5209 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5210 with an undefined scale, which will be assigned to (if possible). It also
5211 receives an exponent of 2. This procedure will then manipulate the mantissa
5212 and calculate a corresponding scale, so that the exponent2 value is assimilated
5213 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5214 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5216 static HRESULT
VARIANT_DI_normalize(VARIANT_DI
* val
, int exponent2
, int isDouble
)
5218 HRESULT hres
= S_OK
;
5219 int exponent5
, exponent10
;
5221 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5222 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5223 exponent10 might be used to set the VARIANT_DI scale directly. However,
5224 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5225 exponent5
= -exponent2
;
5226 exponent10
= exponent2
;
5228 /* Handle exponent5 > 0 */
5229 while (exponent5
> 0) {
5233 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5234 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5235 somehow the mantissa should be divided by 2. */
5236 if ((val
->bitsnum
[0] & 1) == 0) {
5237 /* The mantissa is divisible by 2. Therefore the division can be done
5238 without losing significant digits. */
5239 exponent10
++; exponent5
--;
5242 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5243 val
->bitsnum
[2] >>= 1;
5244 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5245 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5246 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5248 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5249 be multiplied by 5, unless the multiplication overflows. */
5250 DWORD temp_bitsnum
[3];
5254 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5255 if (0 == VARIANT_int_mulbychar(temp_bitsnum
, 3, 5)) {
5256 /* Multiplication succeeded without overflow, so copy result back
5258 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5260 /* Mask out 3 extraneous bits introduced by the multiply */
5262 /* Multiplication by 5 overflows. The mantissa should be divided
5263 by 2, and therefore will lose significant digits. */
5267 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5268 val
->bitsnum
[2] >>= 1;
5269 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5270 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5271 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5276 /* Handle exponent5 < 0 */
5277 while (exponent5
< 0) {
5278 /* In order to divide the value represented by the VARIANT_DI by 5, it
5279 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5280 and the mantissa should be multiplied by 2 */
5281 if ((val
->bitsnum
[2] & 0x80000000) == 0) {
5282 /* The mantissa can withstand a shift-left without overflowing */
5283 exponent10
--; exponent5
++;
5284 VARIANT_int_shiftleft(val
->bitsnum
, 3, 1);
5286 /* The mantissa would overflow if shifted. Therefore it should be
5287 directly divided by 5. This will lose significant digits, unless
5288 by chance the mantissa happens to be divisible by 5 */
5290 VARIANT_int_divbychar(val
->bitsnum
, 3, 5);
5294 /* At this point, the mantissa has assimilated the exponent5, but the
5295 exponent10 might not be suitable for assignment. The exponent10 must be
5296 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5297 down appropriately. */
5298 while (hres
== S_OK
&& exponent10
> 0) {
5299 /* In order to bring exponent10 down to 0, the mantissa should be
5300 multiplied by 10 to compensate. If the exponent10 is too big, this
5301 will cause the mantissa to overflow. */
5302 if (0 == VARIANT_int_mulbychar(val
->bitsnum
, 3, 10)) {
5305 hres
= DISP_E_OVERFLOW
;
5308 while (exponent10
< -DEC_MAX_SCALE
) {
5310 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5311 be divided by 10 to compensate. If the exponent10 is too small, this
5312 will cause the mantissa to underflow and become 0 */
5313 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5315 if (VARIANT_int_iszero(val
->bitsnum
, 3)) {
5316 /* Underflow, unable to keep dividing */
5318 } else if (rem10
>= 5) {
5320 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5323 /* This step is required in order to remove excess bits of precision from the
5324 end of the bit representation, down to the precision guaranteed by the
5325 floating point number. */
5327 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || (val
->bitsnum
[2] == 0 && (val
->bitsnum
[1] & 0xFFE00000) != 0))) {
5330 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5334 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5338 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || val
->bitsnum
[1] != 0 ||
5339 (val
->bitsnum
[2] == 0 && val
->bitsnum
[1] == 0 && (val
->bitsnum
[0] & 0xFF000000) != 0))) {
5342 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5346 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5350 /* Remove multiples of 10 from the representation */
5351 while (exponent10
< 0) {
5352 DWORD temp_bitsnum
[3];
5354 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5355 if (0 == VARIANT_int_divbychar(temp_bitsnum
, 3, 10)) {
5357 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5361 /* Scale assignment */
5362 if (hres
== S_OK
) val
->scale
= -exponent10
;
5371 unsigned long m
: 23;
5372 unsigned int exp_bias
: 8;
5373 unsigned int sign
: 1;
5378 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5379 intermediate string step. */
5380 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
)
5382 HRESULT hres
= S_OK
;
5387 /* Detect special cases */
5388 if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0) {
5389 /* Floating-point zero */
5390 VARIANT_DI_clear(dest
);
5391 } else if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0xFF) {
5392 /* Floating-point infinity */
5393 hres
= DISP_E_OVERFLOW
;
5394 } else if (fx
.i
.exp_bias
== 0xFF) {
5395 /* Floating-point NaN */
5396 hres
= DISP_E_BADVARTYPE
;
5399 VARIANT_DI_clear(dest
);
5401 exponent2
= fx
.i
.exp_bias
- 127; /* Get unbiased exponent */
5402 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5404 /* Copy significant bits to VARIANT_DI mantissa */
5405 dest
->bitsnum
[0] = fx
.i
.m
;
5406 dest
->bitsnum
[0] &= 0x007FFFFF;
5407 if (fx
.i
.exp_bias
== 0) {
5408 /* Denormalized number - correct exponent */
5411 /* Add hidden bit to mantissa */
5412 dest
->bitsnum
[0] |= 0x00800000;
5415 /* The act of copying a FP mantissa as integer bits is equivalent to
5416 shifting left the mantissa 23 bits. The exponent2 is reduced to
5420 hres
= VARIANT_DI_normalize(dest
, exponent2
, 0);
5430 unsigned long m_lo
: 32; /* 52 bits of precision */
5431 unsigned int m_hi
: 20;
5432 unsigned int exp_bias
: 11; /* bias == 1023 */
5433 unsigned int sign
: 1;
5438 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5439 intermediate string step. */
5440 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
)
5442 HRESULT hres
= S_OK
;
5447 /* Detect special cases */
5448 if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0) {
5449 /* Floating-point zero */
5450 VARIANT_DI_clear(dest
);
5451 } else if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0x7FF) {
5452 /* Floating-point infinity */
5453 hres
= DISP_E_OVERFLOW
;
5454 } else if (fx
.i
.exp_bias
== 0x7FF) {
5455 /* Floating-point NaN */
5456 hres
= DISP_E_BADVARTYPE
;
5459 VARIANT_DI_clear(dest
);
5461 exponent2
= fx
.i
.exp_bias
- 1023; /* Get unbiased exponent */
5462 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5464 /* Copy significant bits to VARIANT_DI mantissa */
5465 dest
->bitsnum
[0] = fx
.i
.m_lo
;
5466 dest
->bitsnum
[1] = fx
.i
.m_hi
;
5467 dest
->bitsnum
[1] &= 0x000FFFFF;
5468 if (fx
.i
.exp_bias
== 0) {
5469 /* Denormalized number - correct exponent */
5472 /* Add hidden bit to mantissa */
5473 dest
->bitsnum
[1] |= 0x00100000;
5476 /* The act of copying a FP mantissa as integer bits is equivalent to
5477 shifting left the mantissa 52 bits. The exponent2 is reduced to
5481 hres
= VARIANT_DI_normalize(dest
, exponent2
, 1);
5487 /************************************************************************
5488 * VarDecDiv (OLEAUT32.178)
5490 * Divide one DECIMAL by another.
5493 * pDecLeft [I] Source
5494 * pDecRight [I] Value to divide by
5495 * pDecOut [O] Destination
5499 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5501 HRESULT WINAPI
VarDecDiv(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5503 HRESULT hRet
= S_OK
;
5504 VARIANT_DI di_left
, di_right
, di_result
;
5507 if (!pDecLeft
|| !pDecRight
|| !pDecOut
) return E_INVALIDARG
;
5509 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5510 VARIANT_DIFromDec(pDecRight
, &di_right
);
5511 divresult
= VARIANT_DI_div(&di_left
, &di_right
, &di_result
);
5512 if (divresult
!= S_OK
)
5514 /* division actually overflowed */
5521 if (di_result
.scale
> DEC_MAX_SCALE
)
5523 unsigned char remainder
= 0;
5525 /* division underflowed. In order to comply with the MSDN
5526 specifications for DECIMAL ranges, some significant digits
5529 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5531 while (di_result
.scale
> DEC_MAX_SCALE
&&
5532 !VARIANT_int_iszero(di_result
.bitsnum
, sizeof(di_result
.bitsnum
) / sizeof(DWORD
)))
5534 remainder
= VARIANT_int_divbychar(di_result
.bitsnum
, sizeof(di_result
.bitsnum
) / sizeof(DWORD
), 10);
5537 if (di_result
.scale
> DEC_MAX_SCALE
)
5539 WARN("result underflowed, setting to 0\n");
5540 di_result
.scale
= 0;
5543 else if (remainder
>= 5) /* round up result - native oleaut32 does this */
5546 for (remainder
= 1, i
= 0; i
< sizeof(di_result
.bitsnum
) / sizeof(DWORD
) && remainder
; i
++) {
5547 ULONGLONG digit
= di_result
.bitsnum
[i
] + 1;
5548 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5549 di_result
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
5553 VARIANT_DecFromDI(&di_result
, pDecOut
);
5558 /************************************************************************
5559 * VarDecMul (OLEAUT32.179)
5561 * Multiply one DECIMAL by another.
5564 * pDecLeft [I] Source
5565 * pDecRight [I] Value to multiply by
5566 * pDecOut [O] Destination
5570 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5572 HRESULT WINAPI
VarDecMul(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5574 HRESULT hRet
= S_OK
;
5575 VARIANT_DI di_left
, di_right
, di_result
;
5578 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5579 VARIANT_DIFromDec(pDecRight
, &di_right
);
5580 mulresult
= VARIANT_DI_mul(&di_left
, &di_right
, &di_result
);
5583 /* multiplication actually overflowed */
5584 hRet
= DISP_E_OVERFLOW
;
5588 if (di_result
.scale
> DEC_MAX_SCALE
)
5590 /* multiplication underflowed. In order to comply with the MSDN
5591 specifications for DECIMAL ranges, some significant digits
5594 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5596 while (di_result
.scale
> DEC_MAX_SCALE
&&
5597 !VARIANT_int_iszero(di_result
.bitsnum
, sizeof(di_result
.bitsnum
)/sizeof(DWORD
)))
5599 VARIANT_int_divbychar(di_result
.bitsnum
, sizeof(di_result
.bitsnum
)/sizeof(DWORD
), 10);
5602 if (di_result
.scale
> DEC_MAX_SCALE
)
5604 WARN("result underflowed, setting to 0\n");
5605 di_result
.scale
= 0;
5609 VARIANT_DecFromDI(&di_result
, pDecOut
);
5614 /************************************************************************
5615 * VarDecSub (OLEAUT32.181)
5617 * Subtract one DECIMAL from another.
5620 * pDecLeft [I] Source
5621 * pDecRight [I] DECIMAL to subtract from pDecLeft
5622 * pDecOut [O] Destination
5625 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5627 HRESULT WINAPI
VarDecSub(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5631 /* Implement as addition of the negative */
5632 VarDecNeg(pDecRight
, &decRight
);
5633 return VarDecAdd(pDecLeft
, &decRight
, pDecOut
);
5636 /************************************************************************
5637 * VarDecAbs (OLEAUT32.182)
5639 * Convert a DECIMAL into its absolute value.
5643 * pDecOut [O] Destination
5646 * S_OK. This function does not fail.
5648 HRESULT WINAPI
VarDecAbs(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5651 DEC_SIGN(pDecOut
) &= ~DECIMAL_NEG
;
5655 /************************************************************************
5656 * VarDecFix (OLEAUT32.187)
5658 * Return the integer portion of a DECIMAL.
5662 * pDecOut [O] Destination
5666 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5669 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5670 * negative numbers away from 0, while this function rounds them towards zero.
5672 HRESULT WINAPI
VarDecFix(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5677 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5678 return E_INVALIDARG
;
5680 if (!DEC_SCALE(pDecIn
))
5682 *pDecOut
= *pDecIn
; /* Already an integer */
5686 hr
= VarR8FromDec(pDecIn
, &dbl
);
5687 if (SUCCEEDED(hr
)) {
5688 LONGLONG rounded
= dbl
;
5690 hr
= VarDecFromI8(rounded
, pDecOut
);
5695 /************************************************************************
5696 * VarDecInt (OLEAUT32.188)
5698 * Return the integer portion of a DECIMAL.
5702 * pDecOut [O] Destination
5706 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5709 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5710 * negative numbers towards 0, while this function rounds them away from zero.
5712 HRESULT WINAPI
VarDecInt(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5717 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5718 return E_INVALIDARG
;
5720 if (!(DEC_SIGN(pDecIn
) & DECIMAL_NEG
) || !DEC_SCALE(pDecIn
))
5721 return VarDecFix(pDecIn
, pDecOut
); /* The same, if +ve or no fractionals */
5723 hr
= VarR8FromDec(pDecIn
, &dbl
);
5724 if (SUCCEEDED(hr
)) {
5725 LONGLONG rounded
= dbl
>= 0.0 ? dbl
+ 0.5 : dbl
- 0.5;
5727 hr
= VarDecFromI8(rounded
, pDecOut
);
5732 /************************************************************************
5733 * VarDecNeg (OLEAUT32.189)
5735 * Change the sign of a DECIMAL.
5739 * pDecOut [O] Destination
5742 * S_OK. This function does not fail.
5744 HRESULT WINAPI
VarDecNeg(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5747 DEC_SIGN(pDecOut
) ^= DECIMAL_NEG
;
5751 /************************************************************************
5752 * VarDecRound (OLEAUT32.203)
5754 * Change the precision of a DECIMAL.
5758 * cDecimals [I] New number of decimals to keep
5759 * pDecOut [O] Destination
5762 * Success: S_OK. pDecOut contains the rounded value.
5763 * Failure: E_INVALIDARG if any argument is invalid.
5765 HRESULT WINAPI
VarDecRound(const DECIMAL
* pDecIn
, int cDecimals
, DECIMAL
* pDecOut
)
5767 if (cDecimals
< 0 || (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
) || DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
)
5768 return E_INVALIDARG
;
5770 if (cDecimals
>= DEC_SCALE(pDecIn
))
5772 *pDecOut
= *pDecIn
; /* More precision than we have */
5776 FIXME("semi-stub!\n");
5778 return DISP_E_OVERFLOW
;
5781 /************************************************************************
5782 * VarDecCmp (OLEAUT32.204)
5784 * Compare two DECIMAL values.
5787 * pDecLeft [I] Source
5788 * pDecRight [I] Value to compare
5791 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5792 * is less than, equal to or greater than pDecRight respectively.
5793 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5795 HRESULT WINAPI
VarDecCmp(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
)
5800 if (!pDecLeft
|| !pDecRight
)
5803 if ((!(DEC_SIGN(pDecLeft
) & DECIMAL_NEG
)) && (DEC_SIGN(pDecRight
) & DECIMAL_NEG
) &&
5804 (DEC_HI32(pDecLeft
) | DEC_MID32(pDecLeft
) | DEC_LO32(pDecLeft
)))
5806 else if ((DEC_SIGN(pDecLeft
) & DECIMAL_NEG
) && (!(DEC_SIGN(pDecRight
) & DECIMAL_NEG
)) &&
5807 (DEC_HI32(pDecLeft
) | DEC_MID32(pDecLeft
) | DEC_LO32(pDecLeft
)))
5810 /* Subtract right from left, and compare the result to 0 */
5811 hRet
= VarDecSub(pDecLeft
, pDecRight
, &result
);
5813 if (SUCCEEDED(hRet
))
5815 int non_zero
= DEC_HI32(&result
) | DEC_MID32(&result
) | DEC_LO32(&result
);
5817 if ((DEC_SIGN(&result
) & DECIMAL_NEG
) && non_zero
)
5818 hRet
= (HRESULT
)VARCMP_LT
;
5820 hRet
= (HRESULT
)VARCMP_GT
;
5822 hRet
= (HRESULT
)VARCMP_EQ
;
5827 /************************************************************************
5828 * VarDecCmpR8 (OLEAUT32.298)
5830 * Compare a DECIMAL to a double
5833 * pDecLeft [I] DECIMAL Source
5834 * dblRight [I] double to compare to pDecLeft
5837 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5838 * is less than, equal to or greater than pDecLeft respectively.
5839 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5841 HRESULT WINAPI
VarDecCmpR8(const DECIMAL
* pDecLeft
, double dblRight
)
5846 hRet
= VarDecFromR8(dblRight
, &decRight
);
5848 if (SUCCEEDED(hRet
))
5849 hRet
= VarDecCmp(pDecLeft
, &decRight
);
5857 /************************************************************************
5858 * VarBoolFromUI1 (OLEAUT32.118)
5860 * Convert a VT_UI1 to a VT_BOOL.
5864 * pBoolOut [O] Destination
5869 HRESULT WINAPI
VarBoolFromUI1(BYTE bIn
, VARIANT_BOOL
*pBoolOut
)
5871 *pBoolOut
= bIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5875 /************************************************************************
5876 * VarBoolFromI2 (OLEAUT32.119)
5878 * Convert a VT_I2 to a VT_BOOL.
5882 * pBoolOut [O] Destination
5887 HRESULT WINAPI
VarBoolFromI2(SHORT sIn
, VARIANT_BOOL
*pBoolOut
)
5889 *pBoolOut
= sIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5893 /************************************************************************
5894 * VarBoolFromI4 (OLEAUT32.120)
5896 * Convert a VT_I4 to a VT_BOOL.
5900 * pBoolOut [O] Destination
5905 HRESULT WINAPI
VarBoolFromI4(LONG lIn
, VARIANT_BOOL
*pBoolOut
)
5907 *pBoolOut
= lIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5911 /************************************************************************
5912 * VarBoolFromR4 (OLEAUT32.121)
5914 * Convert a VT_R4 to a VT_BOOL.
5918 * pBoolOut [O] Destination
5923 HRESULT WINAPI
VarBoolFromR4(FLOAT fltIn
, VARIANT_BOOL
*pBoolOut
)
5925 *pBoolOut
= fltIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5929 /************************************************************************
5930 * VarBoolFromR8 (OLEAUT32.122)
5932 * Convert a VT_R8 to a VT_BOOL.
5936 * pBoolOut [O] Destination
5941 HRESULT WINAPI
VarBoolFromR8(double dblIn
, VARIANT_BOOL
*pBoolOut
)
5943 *pBoolOut
= dblIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5947 /************************************************************************
5948 * VarBoolFromDate (OLEAUT32.123)
5950 * Convert a VT_DATE to a VT_BOOL.
5954 * pBoolOut [O] Destination
5959 HRESULT WINAPI
VarBoolFromDate(DATE dateIn
, VARIANT_BOOL
*pBoolOut
)
5961 *pBoolOut
= dateIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5965 /************************************************************************
5966 * VarBoolFromCy (OLEAUT32.124)
5968 * Convert a VT_CY to a VT_BOOL.
5972 * pBoolOut [O] Destination
5977 HRESULT WINAPI
VarBoolFromCy(CY cyIn
, VARIANT_BOOL
*pBoolOut
)
5979 *pBoolOut
= cyIn
.int64
? VARIANT_TRUE
: VARIANT_FALSE
;
5983 /************************************************************************
5984 * VARIANT_GetLocalisedText [internal]
5986 * Get a localized string from the resources
5989 BOOL
VARIANT_GetLocalisedText(LANGID langId
, DWORD dwId
, WCHAR
*lpszDest
)
5993 hrsrc
= FindResourceExW( hProxyDll
, (LPWSTR
)RT_STRING
,
5994 MAKEINTRESOURCEW((dwId
>> 4) + 1), langId
);
5997 HGLOBAL hmem
= LoadResource( hProxyDll
, hrsrc
);
6004 p
= LockResource( hmem
);
6005 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
6007 memcpy( lpszDest
, p
+ 1, *p
* sizeof(WCHAR
) );
6008 lpszDest
[*p
] = '\0';
6009 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest
), langId
);
6016 /************************************************************************
6017 * VarBoolFromStr (OLEAUT32.125)
6019 * Convert a VT_BSTR to a VT_BOOL.
6023 * lcid [I] LCID for the conversion
6024 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6025 * pBoolOut [O] Destination
6029 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6030 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6033 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6034 * it may contain (in any case mapping) the text "true" or "false".
6035 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6036 * localised text of "True" or "False" in the language specified by lcid.
6037 * - If none of these matches occur, the string is treated as a numeric string
6038 * and the boolean pBoolOut will be set according to whether the number is zero
6039 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6040 * - If the text is not numeric and does not match any of the above, then
6041 * DISP_E_TYPEMISMATCH is returned.
6043 HRESULT WINAPI
VarBoolFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, VARIANT_BOOL
*pBoolOut
)
6045 /* Any VB/VBA programmers out there should recognise these strings... */
6046 static const WCHAR szFalse
[] = { '#','F','A','L','S','E','#','\0' };
6047 static const WCHAR szTrue
[] = { '#','T','R','U','E','#','\0' };
6049 LANGID langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6050 HRESULT hRes
= S_OK
;
6052 if (!strIn
|| !pBoolOut
)
6053 return DISP_E_TYPEMISMATCH
;
6055 /* Check if we should be comparing against localised text */
6056 if (dwFlags
& VAR_LOCALBOOL
)
6058 /* Convert our LCID into a usable value */
6059 lcid
= ConvertDefaultLocale(lcid
);
6061 langId
= LANGIDFROMLCID(lcid
);
6063 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6064 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6066 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6067 * I don't think this is needed unless any of the localised text strings
6068 * contain characters that can be so mapped. In the event that this is
6069 * true for a given language (possibly some Asian languages), then strIn
6070 * should be mapped here _only_ if langId is an Id for which this can occur.
6074 /* Note that if we are not comparing against localised strings, langId
6075 * will have its default value of LANG_ENGLISH. This allows us to mimic
6076 * the native behaviour of always checking against English strings even
6077 * after we've checked for localised ones.
6079 VarBoolFromStr_CheckLocalised
:
6080 if (VARIANT_GetLocalisedText(langId
, IDS_TRUE
, szBuff
))
6082 /* Compare against localised strings, ignoring case */
6083 if (!strcmpiW(strIn
, szBuff
))
6085 *pBoolOut
= VARIANT_TRUE
; /* Matched localised 'true' text */
6088 VARIANT_GetLocalisedText(langId
, IDS_FALSE
, szBuff
);
6089 if (!strcmpiW(strIn
, szBuff
))
6091 *pBoolOut
= VARIANT_FALSE
; /* Matched localised 'false' text */
6096 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6098 /* We have checked the localised text, now check English */
6099 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6100 goto VarBoolFromStr_CheckLocalised
;
6103 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6104 if (!strcmpW(strIn
, szFalse
))
6105 *pBoolOut
= VARIANT_FALSE
;
6106 else if (!strcmpW(strIn
, szTrue
))
6107 *pBoolOut
= VARIANT_TRUE
;
6112 /* If this string is a number, convert it as one */
6113 hRes
= VarR8FromStr(strIn
, lcid
, dwFlags
, &d
);
6114 if (SUCCEEDED(hRes
)) *pBoolOut
= d
? VARIANT_TRUE
: VARIANT_FALSE
;
6119 /************************************************************************
6120 * VarBoolFromDisp (OLEAUT32.126)
6122 * Convert a VT_DISPATCH to a VT_BOOL.
6125 * pdispIn [I] Source
6126 * lcid [I] LCID for conversion
6127 * pBoolOut [O] Destination
6131 * Failure: E_INVALIDARG, if the source value is invalid
6132 * DISP_E_OVERFLOW, if the value will not fit in the destination
6133 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6135 HRESULT WINAPI
VarBoolFromDisp(IDispatch
* pdispIn
, LCID lcid
, VARIANT_BOOL
*pBoolOut
)
6137 return VARIANT_FromDisp(pdispIn
, lcid
, pBoolOut
, VT_BOOL
, 0);
6140 /************************************************************************
6141 * VarBoolFromI1 (OLEAUT32.233)
6143 * Convert a VT_I1 to a VT_BOOL.
6147 * pBoolOut [O] Destination
6152 HRESULT WINAPI
VarBoolFromI1(signed char cIn
, VARIANT_BOOL
*pBoolOut
)
6154 *pBoolOut
= cIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6158 /************************************************************************
6159 * VarBoolFromUI2 (OLEAUT32.234)
6161 * Convert a VT_UI2 to a VT_BOOL.
6165 * pBoolOut [O] Destination
6170 HRESULT WINAPI
VarBoolFromUI2(USHORT usIn
, VARIANT_BOOL
*pBoolOut
)
6172 *pBoolOut
= usIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6176 /************************************************************************
6177 * VarBoolFromUI4 (OLEAUT32.235)
6179 * Convert a VT_UI4 to a VT_BOOL.
6183 * pBoolOut [O] Destination
6188 HRESULT WINAPI
VarBoolFromUI4(ULONG ulIn
, VARIANT_BOOL
*pBoolOut
)
6190 *pBoolOut
= ulIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6194 /************************************************************************
6195 * VarBoolFromDec (OLEAUT32.236)
6197 * Convert a VT_DECIMAL to a VT_BOOL.
6201 * pBoolOut [O] Destination
6205 * Failure: E_INVALIDARG, if pDecIn is invalid.
6207 HRESULT WINAPI
VarBoolFromDec(DECIMAL
* pDecIn
, VARIANT_BOOL
*pBoolOut
)
6209 if (DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
|| (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
))
6210 return E_INVALIDARG
;
6212 if (DEC_HI32(pDecIn
) || DEC_MID32(pDecIn
) || DEC_LO32(pDecIn
))
6213 *pBoolOut
= VARIANT_TRUE
;
6215 *pBoolOut
= VARIANT_FALSE
;
6219 /************************************************************************
6220 * VarBoolFromI8 (OLEAUT32.370)
6222 * Convert a VT_I8 to a VT_BOOL.
6226 * pBoolOut [O] Destination
6231 HRESULT WINAPI
VarBoolFromI8(LONG64 llIn
, VARIANT_BOOL
*pBoolOut
)
6233 *pBoolOut
= llIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6237 /************************************************************************
6238 * VarBoolFromUI8 (OLEAUT32.371)
6240 * Convert a VT_UI8 to a VT_BOOL.
6244 * pBoolOut [O] Destination
6249 HRESULT WINAPI
VarBoolFromUI8(ULONG64 ullIn
, VARIANT_BOOL
*pBoolOut
)
6251 *pBoolOut
= ullIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6258 /* Write a number from a UI8 and sign */
6259 static WCHAR
*VARIANT_WriteNumber(ULONG64 ulVal
, WCHAR
* szOut
)
6263 WCHAR ulNextDigit
= ulVal
% 10;
6265 *szOut
-- = '0' + ulNextDigit
;
6266 ulVal
= (ulVal
- ulNextDigit
) / 10;
6273 /* Create a (possibly localised) BSTR from a UI8 and sign */
6274 static BSTR
VARIANT_MakeBstr(LCID lcid
, DWORD dwFlags
, WCHAR
*szOut
)
6276 WCHAR szConverted
[256];
6278 if (dwFlags
& VAR_NEGATIVE
)
6281 if (dwFlags
& LOCALE_USE_NLS
)
6283 /* Format the number for the locale */
6284 szConverted
[0] = '\0';
6285 GetNumberFormatW(lcid
,
6286 dwFlags
& LOCALE_NOUSEROVERRIDE
,
6287 szOut
, NULL
, szConverted
, sizeof(szConverted
)/sizeof(WCHAR
));
6288 szOut
= szConverted
;
6290 return SysAllocStringByteLen((LPCSTR
)szOut
, strlenW(szOut
) * sizeof(WCHAR
));
6293 /* Create a (possibly localised) BSTR from a UI8 and sign */
6294 static HRESULT
VARIANT_BstrFromUInt(ULONG64 ulVal
, LCID lcid
, DWORD dwFlags
, BSTR
*pbstrOut
)
6296 WCHAR szBuff
[64], *szOut
= szBuff
+ sizeof(szBuff
)/sizeof(WCHAR
) - 1;
6299 return E_INVALIDARG
;
6301 /* Create the basic number string */
6303 szOut
= VARIANT_WriteNumber(ulVal
, szOut
);
6305 *pbstrOut
= VARIANT_MakeBstr(lcid
, dwFlags
, szOut
);
6306 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6307 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6310 /******************************************************************************
6311 * VarBstrFromUI1 (OLEAUT32.108)
6313 * Convert a VT_UI1 to a VT_BSTR.
6317 * lcid [I] LCID for the conversion
6318 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6319 * pbstrOut [O] Destination
6323 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6324 * E_OUTOFMEMORY, if memory allocation fails.
6326 HRESULT WINAPI
VarBstrFromUI1(BYTE bIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6328 return VARIANT_BstrFromUInt(bIn
, lcid
, dwFlags
, pbstrOut
);
6331 /******************************************************************************
6332 * VarBstrFromI2 (OLEAUT32.109)
6334 * Convert a VT_I2 to a VT_BSTR.
6338 * lcid [I] LCID for the conversion
6339 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6340 * pbstrOut [O] Destination
6344 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6345 * E_OUTOFMEMORY, if memory allocation fails.
6347 HRESULT WINAPI
VarBstrFromI2(short sIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6354 dwFlags
|= VAR_NEGATIVE
;
6356 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6359 /******************************************************************************
6360 * VarBstrFromI4 (OLEAUT32.110)
6362 * Convert a VT_I4 to a VT_BSTR.
6366 * lcid [I] LCID for the conversion
6367 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6368 * pbstrOut [O] Destination
6372 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6373 * E_OUTOFMEMORY, if memory allocation fails.
6375 HRESULT WINAPI
VarBstrFromI4(LONG lIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6382 dwFlags
|= VAR_NEGATIVE
;
6384 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6387 static BSTR
VARIANT_BstrReplaceDecimal(const WCHAR
* buff
, LCID lcid
, ULONG dwFlags
)
6390 WCHAR lpDecimalSep
[16];
6392 /* Native oleaut32 uses the locale-specific decimal separator even in the
6393 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6394 American locales will see "one thousand and one tenth" as "1000,1"
6395 instead of "1000.1" (notice the comma). The following code checks for
6396 the need to replace the decimal separator, and if so, will prepare an
6397 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6399 GetLocaleInfoW(lcid
, LOCALE_SDECIMAL
| (dwFlags
& LOCALE_NOUSEROVERRIDE
),
6400 lpDecimalSep
, sizeof(lpDecimalSep
) / sizeof(WCHAR
));
6401 if (lpDecimalSep
[0] == '.' && lpDecimalSep
[1] == '\0')
6403 /* locale is compatible with English - return original string */
6404 bstrOut
= SysAllocString(buff
);
6410 WCHAR empty
[1] = {'\0'};
6411 NUMBERFMTW minFormat
;
6413 minFormat
.NumDigits
= 0;
6414 minFormat
.LeadingZero
= 0;
6415 minFormat
.Grouping
= 0;
6416 minFormat
.lpDecimalSep
= lpDecimalSep
;
6417 minFormat
.lpThousandSep
= empty
;
6418 minFormat
.NegativeOrder
= 1; /* NLS_NEG_LEFT */
6420 /* count number of decimal digits in string */
6421 p
= strchrW( buff
, '.' );
6422 if (p
) minFormat
.NumDigits
= strlenW(p
+ 1);
6425 if (!GetNumberFormatW(lcid
, 0, buff
, &minFormat
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
)))
6427 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6428 bstrOut
= SysAllocString(buff
);
6432 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff
));
6433 bstrOut
= SysAllocString(numbuff
);
6439 static HRESULT
VARIANT_BstrFromReal(DOUBLE dblIn
, LCID lcid
, ULONG dwFlags
,
6440 BSTR
* pbstrOut
, LPCWSTR lpszFormat
)
6445 return E_INVALIDARG
;
6447 sprintfW( buff
, lpszFormat
, dblIn
);
6449 /* Negative zeroes are disallowed (some applications depend on this).
6450 If buff starts with a minus, and then nothing follows but zeroes
6451 and/or a period, it is a negative zero and is replaced with a
6452 canonical zero. This duplicates native oleaut32 behavior.
6456 const WCHAR szAccept
[] = {'0', '.', '\0'};
6457 if (strlenW(buff
+ 1) == strspnW(buff
+ 1, szAccept
))
6458 { buff
[0] = '0'; buff
[1] = '\0'; }
6461 TRACE("created string %s\n", debugstr_w(buff
));
6462 if (dwFlags
& LOCALE_USE_NLS
)
6466 /* Format the number for the locale */
6468 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6469 buff
, NULL
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
));
6470 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
6471 *pbstrOut
= SysAllocString(numbuff
);
6475 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
6477 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6480 /******************************************************************************
6481 * VarBstrFromR4 (OLEAUT32.111)
6483 * Convert a VT_R4 to a VT_BSTR.
6487 * lcid [I] LCID for the conversion
6488 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6489 * pbstrOut [O] Destination
6493 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6494 * E_OUTOFMEMORY, if memory allocation fails.
6496 HRESULT WINAPI
VarBstrFromR4(FLOAT fltIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6498 return VARIANT_BstrFromReal(fltIn
, lcid
, dwFlags
, pbstrOut
, szFloatFormatW
);
6501 /******************************************************************************
6502 * VarBstrFromR8 (OLEAUT32.112)
6504 * Convert a VT_R8 to a VT_BSTR.
6508 * lcid [I] LCID for the conversion
6509 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6510 * pbstrOut [O] Destination
6514 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6515 * E_OUTOFMEMORY, if memory allocation fails.
6517 HRESULT WINAPI
VarBstrFromR8(double dblIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6519 return VARIANT_BstrFromReal(dblIn
, lcid
, dwFlags
, pbstrOut
, szDoubleFormatW
);
6522 /******************************************************************************
6523 * VarBstrFromCy [OLEAUT32.113]
6525 * Convert a VT_CY to a VT_BSTR.
6529 * lcid [I] LCID for the conversion
6530 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6531 * pbstrOut [O] Destination
6535 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6536 * E_OUTOFMEMORY, if memory allocation fails.
6538 HRESULT WINAPI
VarBstrFromCy(CY cyIn
, LCID lcid
, ULONG dwFlags
, BSTR
*pbstrOut
)
6544 return E_INVALIDARG
;
6548 decVal
.bitsnum
[0] = cyIn
.s
.Lo
;
6549 decVal
.bitsnum
[1] = cyIn
.s
.Hi
;
6550 if (cyIn
.s
.Hi
& 0x80000000UL
) {
6553 /* Negative number! */
6555 decVal
.bitsnum
[0] = ~decVal
.bitsnum
[0];
6556 decVal
.bitsnum
[1] = ~decVal
.bitsnum
[1];
6557 VARIANT_int_add(decVal
.bitsnum
, 3, &one
, 1);
6559 decVal
.bitsnum
[2] = 0;
6560 VARIANT_DI_tostringW(&decVal
, buff
, sizeof(buff
)/sizeof(buff
[0]));
6562 if (dwFlags
& LOCALE_USE_NLS
)
6566 /* Format the currency for the locale */
6568 GetCurrencyFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6569 buff
, NULL
, cybuff
, sizeof(cybuff
) / sizeof(WCHAR
));
6570 *pbstrOut
= SysAllocString(cybuff
);
6573 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
,lcid
,dwFlags
);
6575 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6578 /******************************************************************************
6579 * VarBstrFromDate [OLEAUT32.114]
6581 * Convert a VT_DATE to a VT_BSTR.
6585 * lcid [I] LCID for the conversion
6586 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6587 * pbstrOut [O] Destination
6591 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6592 * E_OUTOFMEMORY, if memory allocation fails.
6594 HRESULT WINAPI
VarBstrFromDate(DATE dateIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6597 DWORD dwFormatFlags
= dwFlags
& LOCALE_NOUSEROVERRIDE
;
6598 WCHAR date
[128], *time
;
6600 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn
, lcid
, dwFlags
, pbstrOut
);
6602 if (!pbstrOut
|| !VariantTimeToSystemTime(dateIn
, &st
))
6603 return E_INVALIDARG
;
6607 if (dwFlags
& VAR_CALENDAR_THAI
)
6608 st
.wYear
+= 553; /* Use the Thai buddhist calendar year */
6609 else if (dwFlags
& (VAR_CALENDAR_HIJRI
|VAR_CALENDAR_GREGORIAN
))
6610 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6612 if (dwFlags
& LOCALE_USE_NLS
)
6613 dwFlags
&= ~(VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
);
6616 double whole
= dateIn
< 0 ? ceil(dateIn
) : floor(dateIn
);
6617 double partial
= dateIn
- whole
;
6620 dwFlags
|= VAR_TIMEVALUEONLY
;
6621 else if (partial
< 1e-12)
6622 dwFlags
|= VAR_DATEVALUEONLY
;
6625 if (dwFlags
& VAR_TIMEVALUEONLY
)
6628 if (!GetDateFormatW(lcid
, dwFormatFlags
|DATE_SHORTDATE
, &st
, NULL
, date
,
6629 sizeof(date
)/sizeof(WCHAR
)))
6630 return E_INVALIDARG
;
6632 if (!(dwFlags
& VAR_DATEVALUEONLY
))
6634 time
= date
+ strlenW(date
);
6637 if (!GetTimeFormatW(lcid
, dwFormatFlags
, &st
, NULL
, time
,
6638 sizeof(date
)/sizeof(WCHAR
)-(time
-date
)))
6639 return E_INVALIDARG
;
6642 *pbstrOut
= SysAllocString(date
);
6644 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6645 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6648 /******************************************************************************
6649 * VarBstrFromBool (OLEAUT32.116)
6651 * Convert a VT_BOOL to a VT_BSTR.
6655 * lcid [I] LCID for the conversion
6656 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6657 * pbstrOut [O] Destination
6661 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6662 * E_OUTOFMEMORY, if memory allocation fails.
6665 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6666 * localised text of "True" or "False". To convert a bool into a
6667 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6669 HRESULT WINAPI
VarBstrFromBool(VARIANT_BOOL boolIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6672 DWORD dwResId
= IDS_TRUE
;
6675 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn
, lcid
, dwFlags
, pbstrOut
);
6678 return E_INVALIDARG
;
6680 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6681 * for variant formatting */
6682 switch (dwFlags
& (VAR_LOCALBOOL
|VAR_BOOLONOFF
|VAR_BOOLYESNO
))
6693 lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
),SORT_DEFAULT
);
6696 lcid
= ConvertDefaultLocale(lcid
);
6697 langId
= LANGIDFROMLCID(lcid
);
6698 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6699 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6701 if (boolIn
== VARIANT_FALSE
)
6702 dwResId
++; /* Use negative form */
6704 VarBstrFromBool_GetLocalised
:
6705 if (VARIANT_GetLocalisedText(langId
, dwResId
, szBuff
))
6707 *pbstrOut
= SysAllocString(szBuff
);
6708 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6711 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6713 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6714 goto VarBstrFromBool_GetLocalised
;
6717 /* Should never get here */
6718 WARN("Failed to load bool text!\n");
6719 return E_OUTOFMEMORY
;
6722 /******************************************************************************
6723 * VarBstrFromI1 (OLEAUT32.229)
6725 * Convert a VT_I1 to a VT_BSTR.
6729 * lcid [I] LCID for the conversion
6730 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6731 * pbstrOut [O] Destination
6735 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6736 * E_OUTOFMEMORY, if memory allocation fails.
6738 HRESULT WINAPI
VarBstrFromI1(signed char cIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6745 dwFlags
|= VAR_NEGATIVE
;
6747 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6750 /******************************************************************************
6751 * VarBstrFromUI2 (OLEAUT32.230)
6753 * Convert a VT_UI2 to a VT_BSTR.
6757 * lcid [I] LCID for the conversion
6758 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6759 * pbstrOut [O] Destination
6763 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6764 * E_OUTOFMEMORY, if memory allocation fails.
6766 HRESULT WINAPI
VarBstrFromUI2(USHORT usIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6768 return VARIANT_BstrFromUInt(usIn
, lcid
, dwFlags
, pbstrOut
);
6771 /******************************************************************************
6772 * VarBstrFromUI4 (OLEAUT32.231)
6774 * Convert a VT_UI4 to a VT_BSTR.
6778 * lcid [I] LCID for the conversion
6779 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6780 * pbstrOut [O] Destination
6784 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6785 * E_OUTOFMEMORY, if memory allocation fails.
6787 HRESULT WINAPI
VarBstrFromUI4(ULONG ulIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6789 return VARIANT_BstrFromUInt(ulIn
, lcid
, dwFlags
, pbstrOut
);
6792 /******************************************************************************
6793 * VarBstrFromDec (OLEAUT32.232)
6795 * Convert a VT_DECIMAL to a VT_BSTR.
6799 * lcid [I] LCID for the conversion
6800 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6801 * pbstrOut [O] Destination
6805 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6806 * E_OUTOFMEMORY, if memory allocation fails.
6808 HRESULT WINAPI
VarBstrFromDec(DECIMAL
* pDecIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6814 return E_INVALIDARG
;
6816 VARIANT_DIFromDec(pDecIn
, &temp
);
6817 VARIANT_DI_tostringW(&temp
, buff
, 256);
6819 if (dwFlags
& LOCALE_USE_NLS
)
6823 /* Format the number for the locale */
6825 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6826 buff
, NULL
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
));
6827 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
6828 *pbstrOut
= SysAllocString(numbuff
);
6832 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
6835 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6836 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6839 /************************************************************************
6840 * VarBstrFromI8 (OLEAUT32.370)
6842 * Convert a VT_I8 to a VT_BSTR.
6846 * lcid [I] LCID for the conversion
6847 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6848 * pbstrOut [O] Destination
6852 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6853 * E_OUTOFMEMORY, if memory allocation fails.
6855 HRESULT WINAPI
VarBstrFromI8(LONG64 llIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6857 ULONG64 ul64
= llIn
;
6862 dwFlags
|= VAR_NEGATIVE
;
6864 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6867 /************************************************************************
6868 * VarBstrFromUI8 (OLEAUT32.371)
6870 * Convert a VT_UI8 to a VT_BSTR.
6874 * lcid [I] LCID for the conversion
6875 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6876 * pbstrOut [O] Destination
6880 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6881 * E_OUTOFMEMORY, if memory allocation fails.
6883 HRESULT WINAPI
VarBstrFromUI8(ULONG64 ullIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6885 return VARIANT_BstrFromUInt(ullIn
, lcid
, dwFlags
, pbstrOut
);
6888 /************************************************************************
6889 * VarBstrFromDisp (OLEAUT32.115)
6891 * Convert a VT_DISPATCH to a BSTR.
6894 * pdispIn [I] Source
6895 * lcid [I] LCID for conversion
6896 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6897 * pbstrOut [O] Destination
6901 * Failure: E_INVALIDARG, if the source value is invalid
6902 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6904 HRESULT WINAPI
VarBstrFromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6906 return VARIANT_FromDisp(pdispIn
, lcid
, pbstrOut
, VT_BSTR
, dwFlags
);
6909 /**********************************************************************
6910 * VarBstrCat (OLEAUT32.313)
6912 * Concatenate two BSTR values.
6915 * pbstrLeft [I] Source
6916 * pbstrRight [I] Value to concatenate
6917 * pbstrOut [O] Destination
6921 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6922 * E_OUTOFMEMORY, if memory allocation fails.
6924 HRESULT WINAPI
VarBstrCat(BSTR pbstrLeft
, BSTR pbstrRight
, BSTR
*pbstrOut
)
6926 unsigned int lenLeft
, lenRight
;
6929 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
6930 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), pbstrOut
);
6933 return E_INVALIDARG
;
6935 lenLeft
= pbstrLeft
? SysStringLen(pbstrLeft
) : 0;
6936 lenRight
= pbstrRight
? SysStringLen(pbstrRight
) : 0;
6938 *pbstrOut
= SysAllocStringLen(NULL
, lenLeft
+ lenRight
);
6940 return E_OUTOFMEMORY
;
6942 (*pbstrOut
)[0] = '\0';
6945 memcpy(*pbstrOut
, pbstrLeft
, lenLeft
* sizeof(WCHAR
));
6948 memcpy(*pbstrOut
+ lenLeft
, pbstrRight
, lenRight
* sizeof(WCHAR
));
6950 TRACE("%s\n", debugstr_wn(*pbstrOut
, SysStringLen(*pbstrOut
)));
6954 /**********************************************************************
6955 * VarBstrCmp (OLEAUT32.314)
6957 * Compare two BSTR values.
6960 * pbstrLeft [I] Source
6961 * pbstrRight [I] Value to compare
6962 * lcid [I] LCID for the comparison
6963 * dwFlags [I] Flags to pass directly to CompareStringW().
6966 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
6967 * than, equal to or greater than pbstrRight respectively.
6970 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
6971 * states. A NULL BSTR pointer is equivalent to an empty string.
6972 * If LCID is equal to 0, a byte by byte comparison is performed.
6974 HRESULT WINAPI
VarBstrCmp(BSTR pbstrLeft
, BSTR pbstrRight
, LCID lcid
, DWORD dwFlags
)
6979 TRACE("%s,%s,%d,%08x\n",
6980 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
6981 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), lcid
, dwFlags
);
6983 if (!pbstrLeft
|| !*pbstrLeft
)
6985 if (pbstrRight
&& *pbstrRight
)
6988 else if (!pbstrRight
|| !*pbstrRight
)
6993 unsigned int lenLeft
= SysStringByteLen(pbstrLeft
);
6994 unsigned int lenRight
= SysStringByteLen(pbstrRight
);
6995 ret
= memcmp(pbstrLeft
, pbstrRight
, min(lenLeft
, lenRight
));
7000 if (lenLeft
< lenRight
)
7002 if (lenLeft
> lenRight
)
7008 unsigned int lenLeft
= SysStringLen(pbstrLeft
);
7009 unsigned int lenRight
= SysStringLen(pbstrRight
);
7011 if (lenLeft
== 0 || lenRight
== 0)
7013 if (lenLeft
== 0 && lenRight
== 0) return VARCMP_EQ
;
7014 return lenLeft
< lenRight
? VARCMP_LT
: VARCMP_GT
;
7017 hres
= CompareStringW(lcid
, dwFlags
, pbstrLeft
, lenLeft
,
7018 pbstrRight
, lenRight
) - 1;
7019 TRACE("%d\n", hres
);
7028 /******************************************************************************
7029 * VarDateFromUI1 (OLEAUT32.88)
7031 * Convert a VT_UI1 to a VT_DATE.
7035 * pdateOut [O] Destination
7040 HRESULT WINAPI
VarDateFromUI1(BYTE bIn
, DATE
* pdateOut
)
7042 return VarR8FromUI1(bIn
, pdateOut
);
7045 /******************************************************************************
7046 * VarDateFromI2 (OLEAUT32.89)
7048 * Convert a VT_I2 to a VT_DATE.
7052 * pdateOut [O] Destination
7057 HRESULT WINAPI
VarDateFromI2(short sIn
, DATE
* pdateOut
)
7059 return VarR8FromI2(sIn
, pdateOut
);
7062 /******************************************************************************
7063 * VarDateFromI4 (OLEAUT32.90)
7065 * Convert a VT_I4 to a VT_DATE.
7069 * pdateOut [O] Destination
7074 HRESULT WINAPI
VarDateFromI4(LONG lIn
, DATE
* pdateOut
)
7076 return VarDateFromR8(lIn
, pdateOut
);
7079 /******************************************************************************
7080 * VarDateFromR4 (OLEAUT32.91)
7082 * Convert a VT_R4 to a VT_DATE.
7086 * pdateOut [O] Destination
7091 HRESULT WINAPI
VarDateFromR4(FLOAT fltIn
, DATE
* pdateOut
)
7093 return VarR8FromR4(fltIn
, pdateOut
);
7096 /******************************************************************************
7097 * VarDateFromR8 (OLEAUT32.92)
7099 * Convert a VT_R8 to a VT_DATE.
7103 * pdateOut [O] Destination
7108 HRESULT WINAPI
VarDateFromR8(double dblIn
, DATE
* pdateOut
)
7110 if (dblIn
<= (DATE_MIN
- 1.0) || dblIn
>= (DATE_MAX
+ 1.0)) return DISP_E_OVERFLOW
;
7111 *pdateOut
= (DATE
)dblIn
;
7115 /**********************************************************************
7116 * VarDateFromDisp (OLEAUT32.95)
7118 * Convert a VT_DISPATCH to a VT_DATE.
7121 * pdispIn [I] Source
7122 * lcid [I] LCID for conversion
7123 * pdateOut [O] Destination
7127 * Failure: E_INVALIDARG, if the source value is invalid
7128 * DISP_E_OVERFLOW, if the value will not fit in the destination
7129 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7131 HRESULT WINAPI
VarDateFromDisp(IDispatch
* pdispIn
, LCID lcid
, DATE
* pdateOut
)
7133 return VARIANT_FromDisp(pdispIn
, lcid
, pdateOut
, VT_DATE
, 0);
7136 /******************************************************************************
7137 * VarDateFromBool (OLEAUT32.96)
7139 * Convert a VT_BOOL to a VT_DATE.
7143 * pdateOut [O] Destination
7148 HRESULT WINAPI
VarDateFromBool(VARIANT_BOOL boolIn
, DATE
* pdateOut
)
7150 return VarR8FromBool(boolIn
, pdateOut
);
7153 /**********************************************************************
7154 * VarDateFromCy (OLEAUT32.93)
7156 * Convert a VT_CY to a VT_DATE.
7160 * pdateOut [O] Destination
7165 HRESULT WINAPI
VarDateFromCy(CY cyIn
, DATE
* pdateOut
)
7167 return VarR8FromCy(cyIn
, pdateOut
);
7170 /* Date string parsing */
7171 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7172 #define DP_DATESEP 0x02 /* Date separator */
7173 #define DP_MONTH 0x04 /* Month name */
7174 #define DP_AM 0x08 /* AM */
7175 #define DP_PM 0x10 /* PM */
7177 typedef struct tagDATEPARSE
7179 DWORD dwCount
; /* Number of fields found so far (maximum 6) */
7180 DWORD dwParseFlags
; /* Global parse flags (DP_ Flags above) */
7181 DWORD dwFlags
[6]; /* Flags for each field */
7182 DWORD dwValues
[6]; /* Value of each field */
7185 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7187 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7189 /* Determine if a day is valid in a given month of a given year */
7190 static BOOL
VARIANT_IsValidMonthDay(DWORD day
, DWORD month
, DWORD year
)
7192 static const BYTE days
[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7194 if (day
&& month
&& month
< 13)
7196 if (day
<= days
[month
] || (month
== 2 && day
== 29 && IsLeapYear(year
)))
7202 /* Possible orders for 3 numbers making up a date */
7203 #define ORDER_MDY 0x01
7204 #define ORDER_YMD 0x02
7205 #define ORDER_YDM 0x04
7206 #define ORDER_DMY 0x08
7207 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7209 /* Determine a date for a particular locale, from 3 numbers */
7210 static inline HRESULT
VARIANT_MakeDate(DATEPARSE
*dp
, DWORD iDate
,
7211 DWORD offset
, SYSTEMTIME
*st
)
7213 DWORD dwAllOrders
, dwTry
, dwCount
= 0, v1
, v2
, v3
;
7217 v1
= 30; /* Default to (Variant) 0 date part */
7220 goto VARIANT_MakeDate_OK
;
7223 v1
= dp
->dwValues
[offset
+ 0];
7224 v2
= dp
->dwValues
[offset
+ 1];
7225 if (dp
->dwCount
== 2)
7228 GetSystemTime(¤t
);
7232 v3
= dp
->dwValues
[offset
+ 2];
7234 TRACE("(%d,%d,%d,%d,%d)\n", v1
, v2
, v3
, iDate
, offset
);
7236 /* If one number must be a month (Because a month name was given), then only
7237 * consider orders with the month in that position.
7238 * If we took the current year as 'v3', then only allow a year in that position.
7240 if (dp
->dwFlags
[offset
+ 0] & DP_MONTH
)
7242 dwAllOrders
= ORDER_MDY
;
7244 else if (dp
->dwFlags
[offset
+ 1] & DP_MONTH
)
7246 dwAllOrders
= ORDER_DMY
;
7247 if (dp
->dwCount
> 2)
7248 dwAllOrders
|= ORDER_YMD
;
7250 else if (dp
->dwCount
> 2 && dp
->dwFlags
[offset
+ 2] & DP_MONTH
)
7252 dwAllOrders
= ORDER_YDM
;
7256 dwAllOrders
= ORDER_MDY
|ORDER_DMY
;
7257 if (dp
->dwCount
> 2)
7258 dwAllOrders
|= (ORDER_YMD
|ORDER_YDM
);
7261 VARIANT_MakeDate_Start
:
7262 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders
);
7270 /* First: Try the order given by iDate */
7273 case 0: dwTry
= dwAllOrders
& ORDER_MDY
; break;
7274 case 1: dwTry
= dwAllOrders
& ORDER_DMY
; break;
7275 default: dwTry
= dwAllOrders
& ORDER_YMD
; break;
7278 else if (dwCount
== 1)
7280 /* Second: Try all the orders compatible with iDate */
7283 case 0: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7284 case 1: dwTry
= dwAllOrders
& ~(ORDER_MDY
|ORDER_YMD
|ORDER_MYD
); break;
7285 default: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7290 /* Finally: Try any remaining orders */
7291 dwTry
= dwAllOrders
;
7294 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount
, dwTry
);
7300 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7302 if (dwTry
& ORDER_MDY
)
7304 if (VARIANT_IsValidMonthDay(v2
,v1
,v3
))
7307 goto VARIANT_MakeDate_OK
;
7309 dwAllOrders
&= ~ORDER_MDY
;
7311 if (dwTry
& ORDER_YMD
)
7313 if (VARIANT_IsValidMonthDay(v3
,v2
,v1
))
7316 goto VARIANT_MakeDate_OK
;
7318 dwAllOrders
&= ~ORDER_YMD
;
7320 if (dwTry
& ORDER_YDM
)
7322 if (VARIANT_IsValidMonthDay(v2
,v3
,v1
))
7326 goto VARIANT_MakeDate_OK
;
7328 dwAllOrders
&= ~ORDER_YDM
;
7330 if (dwTry
& ORDER_DMY
)
7332 if (VARIANT_IsValidMonthDay(v1
,v2
,v3
))
7333 goto VARIANT_MakeDate_OK
;
7334 dwAllOrders
&= ~ORDER_DMY
;
7336 if (dwTry
& ORDER_MYD
)
7338 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7339 if (VARIANT_IsValidMonthDay(v3
,v1
,v2
))
7343 goto VARIANT_MakeDate_OK
;
7345 dwAllOrders
&= ~ORDER_MYD
;
7349 if (dp
->dwCount
== 2)
7351 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7352 v3
= 1; /* 1st of the month */
7353 dwAllOrders
= ORDER_YMD
|ORDER_MYD
;
7354 dp
->dwCount
= 0; /* Don't return to this code path again */
7356 goto VARIANT_MakeDate_Start
;
7359 /* No valid dates were able to be constructed */
7360 return DISP_E_TYPEMISMATCH
;
7362 VARIANT_MakeDate_OK
:
7364 /* Check that the time part is ok */
7365 if (st
->wHour
> 23 || st
->wMinute
> 59 || st
->wSecond
> 59)
7366 return DISP_E_TYPEMISMATCH
;
7368 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7369 if (st
->wHour
< 12 && (dp
->dwParseFlags
& DP_PM
))
7371 else if (st
->wHour
== 12 && (dp
->dwParseFlags
& DP_AM
))
7373 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7377 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7378 * be retrieved from:
7379 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7380 * But Wine doesn't have/use that key as at the time of writing.
7382 st
->wYear
= v3
< 30 ? 2000 + v3
: v3
< 100 ? 1900 + v3
: v3
;
7383 TRACE("Returning date %d/%d/%d\n", v1
, v2
, st
->wYear
);
7387 /******************************************************************************
7388 * VarDateFromStr [OLEAUT32.94]
7390 * Convert a VT_BSTR to at VT_DATE.
7393 * strIn [I] String to convert
7394 * lcid [I] Locale identifier for the conversion
7395 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7396 * pdateOut [O] Destination for the converted value
7399 * Success: S_OK. pdateOut contains the converted value.
7400 * FAILURE: An HRESULT error code indicating the problem.
7403 * Any date format that can be created using the date formats from lcid
7404 * (Either from kernel Nls functions, variant conversion or formatting) is a
7405 * valid input to this function. In addition, a few more esoteric formats are
7406 * also supported for compatibility with the native version. The date is
7407 * interpreted according to the date settings in the control panel, unless
7408 * the date is invalid in that format, in which the most compatible format
7409 * that produces a valid date will be used.
7411 HRESULT WINAPI
VarDateFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DATE
* pdateOut
)
7413 static const USHORT ParseDateTokens
[] =
7415 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
7416 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
7417 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
,
7418 LOCALE_SMONTHNAME13
,
7419 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
7420 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
7421 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
7422 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
,
7423 LOCALE_SABBREVMONTHNAME13
,
7424 LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
, LOCALE_SDAYNAME4
,
7425 LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
, LOCALE_SDAYNAME7
,
7426 LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
, LOCALE_SABBREVDAYNAME3
,
7427 LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
, LOCALE_SABBREVDAYNAME6
,
7428 LOCALE_SABBREVDAYNAME7
,
7429 LOCALE_S1159
, LOCALE_S2359
7431 static const BYTE ParseDateMonths
[] =
7433 1,2,3,4,5,6,7,8,9,10,11,12,13,
7434 1,2,3,4,5,6,7,8,9,10,11,12,13
7437 BSTR tokens
[sizeof(ParseDateTokens
)/sizeof(ParseDateTokens
[0])];
7439 DWORD dwDateSeps
= 0, iDate
= 0;
7440 HRESULT hRet
= S_OK
;
7442 if ((dwFlags
& (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
)) ==
7443 (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
))
7444 return E_INVALIDARG
;
7447 return DISP_E_TYPEMISMATCH
;
7451 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn
), lcid
, dwFlags
, pdateOut
);
7453 memset(&dp
, 0, sizeof(dp
));
7455 GetLocaleInfoW(lcid
, LOCALE_IDATE
|LOCALE_RETURN_NUMBER
|(dwFlags
& LOCALE_NOUSEROVERRIDE
),
7456 (LPWSTR
)&iDate
, sizeof(iDate
)/sizeof(WCHAR
));
7457 TRACE("iDate is %d\n", iDate
);
7459 /* Get the month/day/am/pm tokens for this locale */
7460 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7463 LCTYPE lctype
= ParseDateTokens
[i
] | (dwFlags
& LOCALE_NOUSEROVERRIDE
);
7465 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7466 * GetAltMonthNames(). We should really cache these strings too.
7469 GetLocaleInfoW(lcid
, lctype
, buff
, sizeof(buff
)/sizeof(WCHAR
));
7470 tokens
[i
] = SysAllocString(buff
);
7471 TRACE("token %d is %s\n", i
, debugstr_w(tokens
[i
]));
7474 /* Parse the string into our structure */
7477 if (dp
.dwCount
>= 6)
7480 if (isdigitW(*strIn
))
7482 dp
.dwValues
[dp
.dwCount
] = strtoulW(strIn
, &strIn
, 10);
7486 else if (isalpha(*strIn
))
7488 BOOL bFound
= FALSE
;
7490 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7492 DWORD dwLen
= strlenW(tokens
[i
]);
7493 if (dwLen
&& !strncmpiW(strIn
, tokens
[i
], dwLen
))
7497 dp
.dwValues
[dp
.dwCount
] = ParseDateMonths
[i
];
7498 dp
.dwFlags
[dp
.dwCount
] |= (DP_MONTH
|DP_DATESEP
);
7503 if (!dp
.dwCount
|| dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7504 hRet
= DISP_E_TYPEMISMATCH
;
7507 dp
.dwFlags
[dp
.dwCount
- 1] |= (i
== 40 ? DP_AM
: DP_PM
);
7508 dp
.dwParseFlags
|= (i
== 40 ? DP_AM
: DP_PM
);
7511 strIn
+= (dwLen
- 1);
7519 if ((*strIn
== 'a' || *strIn
== 'A' || *strIn
== 'p' || *strIn
== 'P') &&
7520 (dp
.dwCount
&& !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7522 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7523 if (*strIn
== 'a' || *strIn
== 'A')
7525 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_AM
;
7526 dp
.dwParseFlags
|= DP_AM
;
7530 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_PM
;
7531 dp
.dwParseFlags
|= DP_PM
;
7537 TRACE("No matching token for %s\n", debugstr_w(strIn
));
7538 hRet
= DISP_E_TYPEMISMATCH
;
7543 else if (*strIn
== ':' || *strIn
== '.')
7545 if (!dp
.dwCount
|| !strIn
[1])
7546 hRet
= DISP_E_TYPEMISMATCH
;
7548 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_TIMESEP
;
7550 else if (*strIn
== '-' || *strIn
== '/')
7553 if (dwDateSeps
> 2 || !dp
.dwCount
|| !strIn
[1])
7554 hRet
= DISP_E_TYPEMISMATCH
;
7556 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7558 else if (*strIn
== ',' || isspaceW(*strIn
))
7560 if (*strIn
== ',' && !strIn
[1])
7561 hRet
= DISP_E_TYPEMISMATCH
;
7565 hRet
= DISP_E_TYPEMISMATCH
;
7570 if (!dp
.dwCount
|| dp
.dwCount
> 6 ||
7571 (dp
.dwCount
== 1 && !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7572 hRet
= DISP_E_TYPEMISMATCH
;
7574 if (SUCCEEDED(hRet
))
7577 DWORD dwOffset
= 0; /* Start of date fields in dp.dwValues */
7579 st
.wDayOfWeek
= st
.wHour
= st
.wMinute
= st
.wSecond
= st
.wMilliseconds
= 0;
7581 /* Figure out which numbers correspond to which fields.
7583 * This switch statement works based on the fact that native interprets any
7584 * fields that are not joined with a time separator ('.' or ':') as date
7585 * fields. Thus we construct a value from 0-32 where each set bit indicates
7586 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7587 * For valid permutations, we set dwOffset to point to the first date field
7588 * and shorten dp.dwCount by the number of time fields found. The real
7589 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7590 * each date number must represent in the context of iDate.
7592 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7594 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7596 case 0x1: /* TT TTDD TTDDD */
7597 if (dp
.dwCount
> 3 &&
7598 ((dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) ||
7599 (dp
.dwFlags
[4] & (DP_AM
|DP_PM
))))
7600 hRet
= DISP_E_TYPEMISMATCH
;
7601 else if (dp
.dwCount
!= 2 && dp
.dwCount
!= 4 && dp
.dwCount
!= 5)
7602 hRet
= DISP_E_TYPEMISMATCH
;
7603 st
.wHour
= dp
.dwValues
[0];
7604 st
.wMinute
= dp
.dwValues
[1];
7609 case 0x3: /* TTT TTTDD TTTDDD */
7610 if (iDate
&& dp
.dwCount
== 3)
7613 if ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) ||
7614 (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))
7615 hRet
= DISP_E_TYPEMISMATCH
;
7618 if (dp
.dwCount
> 4 &&
7619 ((dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[4] & (DP_AM
|DP_PM
)) ||
7620 (dp
.dwFlags
[5] & (DP_AM
|DP_PM
))))
7621 hRet
= DISP_E_TYPEMISMATCH
;
7622 else if (dp
.dwCount
!= 3 && dp
.dwCount
!= 5 && dp
.dwCount
!= 6)
7623 hRet
= DISP_E_TYPEMISMATCH
;
7624 st
.wHour
= dp
.dwValues
[0];
7625 st
.wMinute
= dp
.dwValues
[1];
7626 st
.wSecond
= dp
.dwValues
[2];
7631 case 0x4: /* DDTT */
7632 if (dp
.dwCount
!= 4 ||
7633 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7634 hRet
= DISP_E_TYPEMISMATCH
;
7636 st
.wHour
= dp
.dwValues
[2];
7637 st
.wMinute
= dp
.dwValues
[3];
7641 case 0x0: /* T DD DDD TDDD TDDD */
7642 if (dp
.dwCount
== 1 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7644 st
.wHour
= dp
.dwValues
[0]; /* T */
7648 else if (dp
.dwCount
> 4 || (dp
.dwCount
< 3 && dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7650 hRet
= DISP_E_TYPEMISMATCH
;
7652 else if (dp
.dwCount
== 3)
7654 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDD */
7657 st
.wHour
= dp
.dwValues
[0];
7661 if (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) /* DDT */
7664 st
.wHour
= dp
.dwValues
[2];
7667 else if (dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7668 hRet
= DISP_E_TYPEMISMATCH
;
7670 else if (dp
.dwCount
== 4)
7673 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDDD */
7675 st
.wHour
= dp
.dwValues
[0];
7678 else if (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) /* DDDT */
7680 st
.wHour
= dp
.dwValues
[3];
7683 hRet
= DISP_E_TYPEMISMATCH
;
7686 /* .. fall through .. */
7688 case 0x8: /* DDDTT */
7689 if ((dp
.dwCount
== 2 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
))) ||
7690 (dp
.dwCount
== 5 && ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) ||
7691 (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))) ||
7692 dp
.dwCount
== 4 || dp
.dwCount
== 6)
7693 hRet
= DISP_E_TYPEMISMATCH
;
7694 st
.wHour
= dp
.dwValues
[3];
7695 st
.wMinute
= dp
.dwValues
[4];
7696 if (dp
.dwCount
== 5)
7700 case 0xC: /* DDTTT */
7701 if (dp
.dwCount
!= 5 ||
7702 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7703 hRet
= DISP_E_TYPEMISMATCH
;
7704 st
.wHour
= dp
.dwValues
[2];
7705 st
.wMinute
= dp
.dwValues
[3];
7706 st
.wSecond
= dp
.dwValues
[4];
7710 case 0x1B: /* localized DDDTTT */
7713 hRet
= DISP_E_TYPEMISMATCH
;
7716 /* .. fall through .. */
7717 case 0x18: /* DDDTTT */
7718 if ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) ||
7719 (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))
7720 hRet
= DISP_E_TYPEMISMATCH
;
7721 st
.wHour
= dp
.dwValues
[3];
7722 st
.wMinute
= dp
.dwValues
[4];
7723 st
.wSecond
= dp
.dwValues
[5];
7728 hRet
= DISP_E_TYPEMISMATCH
;
7732 if (SUCCEEDED(hRet
))
7734 hRet
= VARIANT_MakeDate(&dp
, iDate
, dwOffset
, &st
);
7736 if (dwFlags
& VAR_TIMEVALUEONLY
)
7742 else if (dwFlags
& VAR_DATEVALUEONLY
)
7743 st
.wHour
= st
.wMinute
= st
.wSecond
= 0;
7745 /* Finally, convert the value to a VT_DATE */
7746 if (SUCCEEDED(hRet
))
7747 hRet
= SystemTimeToVariantTime(&st
, pdateOut
) ? S_OK
: DISP_E_TYPEMISMATCH
;
7751 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7752 SysFreeString(tokens
[i
]);
7756 /******************************************************************************
7757 * VarDateFromI1 (OLEAUT32.221)
7759 * Convert a VT_I1 to a VT_DATE.
7763 * pdateOut [O] Destination
7768 HRESULT WINAPI
VarDateFromI1(signed char cIn
, DATE
* pdateOut
)
7770 return VarR8FromI1(cIn
, pdateOut
);
7773 /******************************************************************************
7774 * VarDateFromUI2 (OLEAUT32.222)
7776 * Convert a VT_UI2 to a VT_DATE.
7780 * pdateOut [O] Destination
7785 HRESULT WINAPI
VarDateFromUI2(USHORT uiIn
, DATE
* pdateOut
)
7787 return VarR8FromUI2(uiIn
, pdateOut
);
7790 /******************************************************************************
7791 * VarDateFromUI4 (OLEAUT32.223)
7793 * Convert a VT_UI4 to a VT_DATE.
7797 * pdateOut [O] Destination
7802 HRESULT WINAPI
VarDateFromUI4(ULONG ulIn
, DATE
* pdateOut
)
7804 return VarDateFromR8(ulIn
, pdateOut
);
7807 /**********************************************************************
7808 * VarDateFromDec (OLEAUT32.224)
7810 * Convert a VT_DECIMAL to a VT_DATE.
7814 * pdateOut [O] Destination
7819 HRESULT WINAPI
VarDateFromDec(DECIMAL
*pdecIn
, DATE
* pdateOut
)
7821 return VarR8FromDec(pdecIn
, pdateOut
);
7824 /******************************************************************************
7825 * VarDateFromI8 (OLEAUT32.364)
7827 * Convert a VT_I8 to a VT_DATE.
7831 * pdateOut [O] Destination
7835 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7837 HRESULT WINAPI
VarDateFromI8(LONG64 llIn
, DATE
* pdateOut
)
7839 if (llIn
< DATE_MIN
|| llIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
7840 *pdateOut
= (DATE
)llIn
;
7844 /******************************************************************************
7845 * VarDateFromUI8 (OLEAUT32.365)
7847 * Convert a VT_UI8 to a VT_DATE.
7851 * pdateOut [O] Destination
7855 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7857 HRESULT WINAPI
VarDateFromUI8(ULONG64 ullIn
, DATE
* pdateOut
)
7859 if (ullIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
7860 *pdateOut
= (DATE
)ullIn
;