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"
34 WINE_DEFAULT_DEBUG_CHANNEL(variant
);
36 extern HMODULE hProxyDll DECLSPEC_HIDDEN
;
38 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
39 #define CY_MULTIPLIER_F 10000.0
40 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
41 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
43 /* Copy data from one variant to another. */
44 static inline void VARIANT_CopyData(const VARIANT
*srcVar
, VARTYPE vt
, void *pOut
)
49 case VT_UI1
: memcpy(pOut
, &V_UI1(srcVar
), sizeof(BYTE
)); break;
52 case VT_UI2
: memcpy(pOut
, &V_UI2(srcVar
), sizeof(SHORT
)); break;
57 case VT_UI4
: memcpy(pOut
, &V_UI4(srcVar
), sizeof (LONG
)); break;
62 case VT_UI8
: memcpy(pOut
, &V_UI8(srcVar
), sizeof (LONG64
)); break;
63 case VT_INT_PTR
: memcpy(pOut
, &V_INT_PTR(srcVar
), sizeof (INT_PTR
)); break;
64 case VT_DECIMAL
: memcpy(pOut
, &V_DECIMAL(srcVar
), sizeof (DECIMAL
)); break;
65 case VT_BSTR
: memcpy(pOut
, &V_BSTR(srcVar
), sizeof(BSTR
)); break;
67 FIXME("VT_ type %d unhandled, please report!\n", vt
);
71 /* Macro to inline conversion from a float or double to any integer type,
72 * rounding according to the 'dutch' convention.
74 #define VARIANT_DutchRound(typ, value, res) do { \
75 double whole = value < 0 ? ceil(value) : floor(value); \
76 double fract = value - whole; \
77 if (fract > 0.5) res = (typ)whole + (typ)1; \
78 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
79 else if (fract >= 0.0) res = (typ)whole; \
80 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
81 else if (fract > -0.5) res = (typ)whole; \
82 else res = (typ)whole - (typ)1; \
86 /* Coerce VT_BSTR to a numeric type */
87 static HRESULT
VARIANT_NumberFromBstr(OLECHAR
* pStrIn
, LCID lcid
, ULONG ulFlags
,
88 void* pOut
, VARTYPE vt
)
95 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
96 np
.cDig
= ARRAY_SIZE(rgb
);
97 np
.dwInFlags
= NUMPRS_STD
;
99 hRet
= VarParseNumFromStr(pStrIn
, lcid
, ulFlags
, &np
, rgb
);
103 /* 1 << vt gives us the VTBIT constant for the destination number type */
104 hRet
= VarNumFromParseNum(&np
, rgb
, 1 << vt
, &dstVar
);
106 VARIANT_CopyData(&dstVar
, vt
, pOut
);
111 /* Coerce VT_DISPATCH to another type */
112 static HRESULT
VARIANT_FromDisp(IDispatch
* pdispIn
, LCID lcid
, void* pOut
,
113 VARTYPE vt
, DWORD dwFlags
)
115 static DISPPARAMS emptyParams
= { NULL
, NULL
, 0, 0 };
116 VARIANTARG srcVar
, dstVar
;
120 return DISP_E_BADVARTYPE
;
122 /* Get the default 'value' property from the IDispatch */
123 VariantInit(&srcVar
);
124 hRet
= IDispatch_Invoke(pdispIn
, DISPID_VALUE
, &IID_NULL
, lcid
, DISPATCH_PROPERTYGET
,
125 &emptyParams
, &srcVar
, NULL
, NULL
);
129 /* Convert the property to the requested type */
130 VariantInit(&dstVar
);
131 hRet
= VariantChangeTypeEx(&dstVar
, &srcVar
, lcid
, dwFlags
, vt
);
132 VariantClear(&srcVar
);
135 VARIANT_CopyData(&dstVar
, vt
, pOut
);
138 hRet
= DISP_E_TYPEMISMATCH
;
142 /* Inline return type */
143 #define RETTYP static inline HRESULT
146 /* Simple compiler cast from one type to another */
147 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
148 *out = in; return S_OK; }
150 /* Compiler cast where input cannot be negative */
151 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
152 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
154 /* Compiler cast where input cannot be > some number */
155 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
156 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
158 /* Compiler cast where input cannot be < some number or >= some other number */
159 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
160 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
163 POSTST(signed char, BYTE
, VarI1FromUI1
, I1_MAX
)
164 BOTHTST(signed char, SHORT
, VarI1FromI2
, I1_MIN
, I1_MAX
)
165 BOTHTST(signed char, LONG
, VarI1FromI4
, I1_MIN
, I1_MAX
)
166 SIMPLE(signed char, VARIANT_BOOL
, VarI1FromBool
)
167 POSTST(signed char, USHORT
, VarI1FromUI2
, I1_MAX
)
168 POSTST(signed char, ULONG
, VarI1FromUI4
, I1_MAX
)
169 BOTHTST(signed char, LONG64
, VarI1FromI8
, I1_MIN
, I1_MAX
)
170 POSTST(signed char, ULONG64
, VarI1FromUI8
, I1_MAX
)
173 BOTHTST(BYTE
, SHORT
, VarUI1FromI2
, UI1_MIN
, UI1_MAX
)
174 SIMPLE(BYTE
, VARIANT_BOOL
, VarUI1FromBool
)
175 NEGTST(BYTE
, signed char, VarUI1FromI1
)
176 POSTST(BYTE
, USHORT
, VarUI1FromUI2
, UI1_MAX
)
177 BOTHTST(BYTE
, LONG
, VarUI1FromI4
, UI1_MIN
, UI1_MAX
)
178 POSTST(BYTE
, ULONG
, VarUI1FromUI4
, UI1_MAX
)
179 BOTHTST(BYTE
, LONG64
, VarUI1FromI8
, UI1_MIN
, UI1_MAX
)
180 POSTST(BYTE
, ULONG64
, VarUI1FromUI8
, UI1_MAX
)
183 SIMPLE(SHORT
, BYTE
, VarI2FromUI1
)
184 BOTHTST(SHORT
, LONG
, VarI2FromI4
, I2_MIN
, I2_MAX
)
185 SIMPLE(SHORT
, VARIANT_BOOL
, VarI2FromBool
)
186 SIMPLE(SHORT
, signed char, VarI2FromI1
)
187 POSTST(SHORT
, USHORT
, VarI2FromUI2
, I2_MAX
)
188 POSTST(SHORT
, ULONG
, VarI2FromUI4
, I2_MAX
)
189 BOTHTST(SHORT
, LONG64
, VarI2FromI8
, I2_MIN
, I2_MAX
)
190 POSTST(SHORT
, ULONG64
, VarI2FromUI8
, I2_MAX
)
193 SIMPLE(USHORT
, BYTE
, VarUI2FromUI1
)
194 NEGTST(USHORT
, SHORT
, VarUI2FromI2
)
195 BOTHTST(USHORT
, LONG
, VarUI2FromI4
, UI2_MIN
, UI2_MAX
)
196 SIMPLE(USHORT
, VARIANT_BOOL
, VarUI2FromBool
)
197 NEGTST(USHORT
, signed char, VarUI2FromI1
)
198 POSTST(USHORT
, ULONG
, VarUI2FromUI4
, UI2_MAX
)
199 BOTHTST(USHORT
, LONG64
, VarUI2FromI8
, UI2_MIN
, UI2_MAX
)
200 POSTST(USHORT
, ULONG64
, VarUI2FromUI8
, UI2_MAX
)
203 SIMPLE(LONG
, BYTE
, VarI4FromUI1
)
204 SIMPLE(LONG
, SHORT
, VarI4FromI2
)
205 SIMPLE(LONG
, VARIANT_BOOL
, VarI4FromBool
)
206 SIMPLE(LONG
, signed char, VarI4FromI1
)
207 SIMPLE(LONG
, USHORT
, VarI4FromUI2
)
208 POSTST(LONG
, ULONG
, VarI4FromUI4
, I4_MAX
)
209 BOTHTST(LONG
, LONG64
, VarI4FromI8
, I4_MIN
, I4_MAX
)
210 POSTST(LONG
, ULONG64
, VarI4FromUI8
, I4_MAX
)
213 SIMPLE(ULONG
, BYTE
, VarUI4FromUI1
)
214 NEGTST(ULONG
, SHORT
, VarUI4FromI2
)
215 NEGTST(ULONG
, LONG
, VarUI4FromI4
)
216 SIMPLE(ULONG
, VARIANT_BOOL
, VarUI4FromBool
)
217 NEGTST(ULONG
, signed char, VarUI4FromI1
)
218 SIMPLE(ULONG
, USHORT
, VarUI4FromUI2
)
219 BOTHTST(ULONG
, LONG64
, VarUI4FromI8
, UI4_MIN
, UI4_MAX
)
220 POSTST(ULONG
, ULONG64
, VarUI4FromUI8
, UI4_MAX
)
223 SIMPLE(LONG64
, BYTE
, VarI8FromUI1
)
224 SIMPLE(LONG64
, SHORT
, VarI8FromI2
)
225 SIMPLE(LONG64
, signed char, VarI8FromI1
)
226 SIMPLE(LONG64
, USHORT
, VarI8FromUI2
)
227 SIMPLE(LONG64
, ULONG
, VarI8FromUI4
)
228 POSTST(LONG64
, ULONG64
, VarI8FromUI8
, I8_MAX
)
231 SIMPLE(ULONG64
, BYTE
, VarUI8FromUI1
)
232 NEGTST(ULONG64
, SHORT
, VarUI8FromI2
)
233 NEGTST(ULONG64
, signed char, VarUI8FromI1
)
234 SIMPLE(ULONG64
, USHORT
, VarUI8FromUI2
)
235 SIMPLE(ULONG64
, ULONG
, VarUI8FromUI4
)
236 NEGTST(ULONG64
, LONG64
, VarUI8FromI8
)
239 SIMPLE(float, BYTE
, VarR4FromUI1
)
240 SIMPLE(float, SHORT
, VarR4FromI2
)
241 SIMPLE(float, signed char, VarR4FromI1
)
242 SIMPLE(float, USHORT
, VarR4FromUI2
)
243 SIMPLE(float, LONG
, VarR4FromI4
)
244 SIMPLE(float, ULONG
, VarR4FromUI4
)
245 SIMPLE(float, LONG64
, VarR4FromI8
)
246 SIMPLE(float, ULONG64
, VarR4FromUI8
)
249 SIMPLE(double, BYTE
, VarR8FromUI1
)
250 SIMPLE(double, SHORT
, VarR8FromI2
)
251 SIMPLE(double, float, VarR8FromR4
)
252 RETTYP
_VarR8FromCy(CY i
, double* o
) { *o
= (double)i
.int64
/ CY_MULTIPLIER_F
; return S_OK
; }
253 SIMPLE(double, DATE
, VarR8FromDate
)
254 SIMPLE(double, signed char, VarR8FromI1
)
255 SIMPLE(double, USHORT
, VarR8FromUI2
)
256 SIMPLE(double, LONG
, VarR8FromI4
)
257 SIMPLE(double, ULONG
, VarR8FromUI4
)
258 SIMPLE(double, LONG64
, VarR8FromI8
)
259 SIMPLE(double, ULONG64
, VarR8FromUI8
)
265 /************************************************************************
266 * VarI1FromUI1 (OLEAUT32.244)
268 * Convert a VT_UI1 to a VT_I1.
272 * pcOut [O] Destination
276 * Failure: E_INVALIDARG, if the source value is invalid
277 * DISP_E_OVERFLOW, if the value will not fit in the destination
279 HRESULT WINAPI
VarI1FromUI1(BYTE bIn
, signed char* pcOut
)
281 return _VarI1FromUI1(bIn
, pcOut
);
284 /************************************************************************
285 * VarI1FromI2 (OLEAUT32.245)
287 * Convert a VT_I2 to a VT_I1.
291 * pcOut [O] Destination
295 * Failure: E_INVALIDARG, if the source value is invalid
296 * DISP_E_OVERFLOW, if the value will not fit in the destination
298 HRESULT WINAPI
VarI1FromI2(SHORT sIn
, signed char* pcOut
)
300 return _VarI1FromI2(sIn
, pcOut
);
303 /************************************************************************
304 * VarI1FromI4 (OLEAUT32.246)
306 * Convert a VT_I4 to a VT_I1.
310 * pcOut [O] Destination
314 * Failure: E_INVALIDARG, if the source value is invalid
315 * DISP_E_OVERFLOW, if the value will not fit in the destination
317 HRESULT WINAPI
VarI1FromI4(LONG iIn
, signed char* pcOut
)
319 return _VarI1FromI4(iIn
, pcOut
);
322 /************************************************************************
323 * VarI1FromR4 (OLEAUT32.247)
325 * Convert a VT_R4 to a VT_I1.
329 * pcOut [O] Destination
333 * Failure: E_INVALIDARG, if the source value is invalid
334 * DISP_E_OVERFLOW, if the value will not fit in the destination
336 HRESULT WINAPI
VarI1FromR4(FLOAT fltIn
, signed char* pcOut
)
338 return VarI1FromR8(fltIn
, pcOut
);
341 /************************************************************************
342 * VarI1FromR8 (OLEAUT32.248)
344 * Convert a VT_R8 to a VT_I1.
348 * pcOut [O] Destination
352 * Failure: E_INVALIDARG, if the source value is invalid
353 * DISP_E_OVERFLOW, if the value will not fit in the destination
356 * See VarI8FromR8() for details concerning rounding.
358 HRESULT WINAPI
VarI1FromR8(double dblIn
, signed char* pcOut
)
360 if (dblIn
< I1_MIN
- 0.5 || dblIn
>= I1_MAX
+ 0.5)
361 return DISP_E_OVERFLOW
;
362 VARIANT_DutchRound(CHAR
, dblIn
, *pcOut
);
366 /************************************************************************
367 * VarI1FromDate (OLEAUT32.249)
369 * Convert a VT_DATE to a VT_I1.
373 * pcOut [O] Destination
377 * Failure: E_INVALIDARG, if the source value is invalid
378 * DISP_E_OVERFLOW, if the value will not fit in the destination
380 HRESULT WINAPI
VarI1FromDate(DATE dateIn
, signed char* pcOut
)
382 return VarI1FromR8(dateIn
, pcOut
);
385 /************************************************************************
386 * VarI1FromCy (OLEAUT32.250)
388 * Convert a VT_CY to a VT_I1.
392 * pcOut [O] Destination
396 * Failure: E_INVALIDARG, if the source value is invalid
397 * DISP_E_OVERFLOW, if the value will not fit in the destination
399 HRESULT WINAPI
VarI1FromCy(CY cyIn
, signed char* pcOut
)
403 VarI4FromCy(cyIn
, &i
);
404 return _VarI1FromI4(i
, pcOut
);
407 /************************************************************************
408 * VarI1FromStr (OLEAUT32.251)
410 * Convert a VT_BSTR to a VT_I1.
414 * lcid [I] LCID for the conversion
415 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
416 * pcOut [O] Destination
420 * Failure: E_INVALIDARG, if the source value is invalid
421 * DISP_E_OVERFLOW, if the value will not fit in the destination
422 * DISP_E_TYPEMISMATCH, if the type cannot be converted
424 HRESULT WINAPI
VarI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, signed char* pcOut
)
426 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pcOut
, VT_I1
);
429 /************************************************************************
430 * VarI1FromDisp (OLEAUT32.252)
432 * Convert a VT_DISPATCH to a VT_I1.
436 * lcid [I] LCID for conversion
437 * pcOut [O] Destination
441 * Failure: E_INVALIDARG, if the source value is invalid
442 * DISP_E_OVERFLOW, if the value will not fit in the destination
443 * DISP_E_TYPEMISMATCH, if the type cannot be converted
445 HRESULT WINAPI
VarI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, signed char* pcOut
)
447 return VARIANT_FromDisp(pdispIn
, lcid
, pcOut
, VT_I1
, 0);
450 /************************************************************************
451 * VarI1FromBool (OLEAUT32.253)
453 * Convert a VT_BOOL to a VT_I1.
457 * pcOut [O] Destination
462 HRESULT WINAPI
VarI1FromBool(VARIANT_BOOL boolIn
, signed char* pcOut
)
464 return _VarI1FromBool(boolIn
, pcOut
);
467 /************************************************************************
468 * VarI1FromUI2 (OLEAUT32.254)
470 * Convert a VT_UI2 to a VT_I1.
474 * pcOut [O] Destination
478 * Failure: E_INVALIDARG, if the source value is invalid
479 * DISP_E_OVERFLOW, if the value will not fit in the destination
481 HRESULT WINAPI
VarI1FromUI2(USHORT usIn
, signed char* pcOut
)
483 return _VarI1FromUI2(usIn
, pcOut
);
486 /************************************************************************
487 * VarI1FromUI4 (OLEAUT32.255)
489 * Convert a VT_UI4 to a VT_I1.
493 * pcOut [O] Destination
497 * Failure: E_INVALIDARG, if the source value is invalid
498 * DISP_E_OVERFLOW, if the value will not fit in the destination
499 * DISP_E_TYPEMISMATCH, if the type cannot be converted
501 HRESULT WINAPI
VarI1FromUI4(ULONG ulIn
, signed char* pcOut
)
503 return _VarI1FromUI4(ulIn
, pcOut
);
506 /************************************************************************
507 * VarI1FromDec (OLEAUT32.256)
509 * Convert a VT_DECIMAL to a VT_I1.
513 * pcOut [O] Destination
517 * Failure: E_INVALIDARG, if the source value is invalid
518 * DISP_E_OVERFLOW, if the value will not fit in the destination
520 HRESULT WINAPI
VarI1FromDec(DECIMAL
*pdecIn
, signed char* pcOut
)
525 hRet
= VarI8FromDec(pdecIn
, &i64
);
528 hRet
= _VarI1FromI8(i64
, pcOut
);
532 /************************************************************************
533 * VarI1FromI8 (OLEAUT32.376)
535 * Convert a VT_I8 to a VT_I1.
539 * pcOut [O] Destination
543 * Failure: E_INVALIDARG, if the source value is invalid
544 * DISP_E_OVERFLOW, if the value will not fit in the destination
546 HRESULT WINAPI
VarI1FromI8(LONG64 llIn
, signed char* pcOut
)
548 return _VarI1FromI8(llIn
, pcOut
);
551 /************************************************************************
552 * VarI1FromUI8 (OLEAUT32.377)
554 * Convert a VT_UI8 to a VT_I1.
558 * pcOut [O] Destination
562 * Failure: E_INVALIDARG, if the source value is invalid
563 * DISP_E_OVERFLOW, if the value will not fit in the destination
565 HRESULT WINAPI
VarI1FromUI8(ULONG64 ullIn
, signed char* pcOut
)
567 return _VarI1FromUI8(ullIn
, pcOut
);
573 /************************************************************************
574 * VarUI1FromI2 (OLEAUT32.130)
576 * Convert a VT_I2 to a VT_UI1.
580 * pbOut [O] Destination
584 * Failure: E_INVALIDARG, if the source value is invalid
585 * DISP_E_OVERFLOW, if the value will not fit in the destination
587 HRESULT WINAPI
VarUI1FromI2(SHORT sIn
, BYTE
* pbOut
)
589 return _VarUI1FromI2(sIn
, pbOut
);
592 /************************************************************************
593 * VarUI1FromI4 (OLEAUT32.131)
595 * Convert a VT_I4 to a VT_UI1.
599 * pbOut [O] Destination
603 * Failure: E_INVALIDARG, if the source value is invalid
604 * DISP_E_OVERFLOW, if the value will not fit in the destination
606 HRESULT WINAPI
VarUI1FromI4(LONG iIn
, BYTE
* pbOut
)
608 return _VarUI1FromI4(iIn
, pbOut
);
611 /************************************************************************
612 * VarUI1FromR4 (OLEAUT32.132)
614 * Convert a VT_R4 to a VT_UI1.
618 * pbOut [O] Destination
622 * Failure: E_INVALIDARG, if the source value is invalid
623 * DISP_E_OVERFLOW, if the value will not fit in the destination
624 * DISP_E_TYPEMISMATCH, if the type cannot be converted
626 HRESULT WINAPI
VarUI1FromR4(FLOAT fltIn
, BYTE
* pbOut
)
628 return VarUI1FromR8(fltIn
, pbOut
);
631 /************************************************************************
632 * VarUI1FromR8 (OLEAUT32.133)
634 * Convert a VT_R8 to a VT_UI1.
638 * pbOut [O] Destination
642 * Failure: E_INVALIDARG, if the source value is invalid
643 * DISP_E_OVERFLOW, if the value will not fit in the destination
646 * See VarI8FromR8() for details concerning rounding.
648 HRESULT WINAPI
VarUI1FromR8(double dblIn
, BYTE
* pbOut
)
650 if (dblIn
< -0.5 || dblIn
>= UI1_MAX
+ 0.5)
651 return DISP_E_OVERFLOW
;
652 VARIANT_DutchRound(BYTE
, dblIn
, *pbOut
);
656 /************************************************************************
657 * VarUI1FromCy (OLEAUT32.134)
659 * Convert a VT_CY to a VT_UI1.
663 * pbOut [O] Destination
667 * Failure: E_INVALIDARG, if the source value is invalid
668 * DISP_E_OVERFLOW, if the value will not fit in the destination
671 * Negative values >= -5000 will be converted to 0.
673 HRESULT WINAPI
VarUI1FromCy(CY cyIn
, BYTE
* pbOut
)
675 ULONG i
= UI1_MAX
+ 1;
677 VarUI4FromCy(cyIn
, &i
);
678 return _VarUI1FromUI4(i
, pbOut
);
681 /************************************************************************
682 * VarUI1FromDate (OLEAUT32.135)
684 * Convert a VT_DATE to a VT_UI1.
688 * pbOut [O] Destination
692 * Failure: E_INVALIDARG, if the source value is invalid
693 * DISP_E_OVERFLOW, if the value will not fit in the destination
695 HRESULT WINAPI
VarUI1FromDate(DATE dateIn
, BYTE
* pbOut
)
697 return VarUI1FromR8(dateIn
, pbOut
);
700 /************************************************************************
701 * VarUI1FromStr (OLEAUT32.136)
703 * Convert a VT_BSTR to a VT_UI1.
707 * lcid [I] LCID for the conversion
708 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
709 * pbOut [O] Destination
713 * Failure: E_INVALIDARG, if the source value is invalid
714 * DISP_E_OVERFLOW, if the value will not fit in the destination
715 * DISP_E_TYPEMISMATCH, if the type cannot be converted
717 HRESULT WINAPI
VarUI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, BYTE
* pbOut
)
719 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pbOut
, VT_UI1
);
722 /************************************************************************
723 * VarUI1FromDisp (OLEAUT32.137)
725 * Convert a VT_DISPATCH to a VT_UI1.
729 * lcid [I] LCID for conversion
730 * pbOut [O] Destination
734 * Failure: E_INVALIDARG, if the source value is invalid
735 * DISP_E_OVERFLOW, if the value will not fit in the destination
736 * DISP_E_TYPEMISMATCH, if the type cannot be converted
738 HRESULT WINAPI
VarUI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, BYTE
* pbOut
)
740 return VARIANT_FromDisp(pdispIn
, lcid
, pbOut
, VT_UI1
, 0);
743 /************************************************************************
744 * VarUI1FromBool (OLEAUT32.138)
746 * Convert a VT_BOOL to a VT_UI1.
750 * pbOut [O] Destination
755 HRESULT WINAPI
VarUI1FromBool(VARIANT_BOOL boolIn
, BYTE
* pbOut
)
757 return _VarUI1FromBool(boolIn
, pbOut
);
760 /************************************************************************
761 * VarUI1FromI1 (OLEAUT32.237)
763 * Convert a VT_I1 to a VT_UI1.
767 * pbOut [O] Destination
771 * Failure: E_INVALIDARG, if the source value is invalid
772 * DISP_E_OVERFLOW, if the value will not fit in the destination
774 HRESULT WINAPI
VarUI1FromI1(signed char cIn
, BYTE
* pbOut
)
776 return _VarUI1FromI1(cIn
, pbOut
);
779 /************************************************************************
780 * VarUI1FromUI2 (OLEAUT32.238)
782 * Convert a VT_UI2 to a VT_UI1.
786 * pbOut [O] Destination
790 * Failure: E_INVALIDARG, if the source value is invalid
791 * DISP_E_OVERFLOW, if the value will not fit in the destination
793 HRESULT WINAPI
VarUI1FromUI2(USHORT usIn
, BYTE
* pbOut
)
795 return _VarUI1FromUI2(usIn
, pbOut
);
798 /************************************************************************
799 * VarUI1FromUI4 (OLEAUT32.239)
801 * Convert a VT_UI4 to a VT_UI1.
805 * pbOut [O] Destination
809 * Failure: E_INVALIDARG, if the source value is invalid
810 * DISP_E_OVERFLOW, if the value will not fit in the destination
812 HRESULT WINAPI
VarUI1FromUI4(ULONG ulIn
, BYTE
* pbOut
)
814 return _VarUI1FromUI4(ulIn
, pbOut
);
817 /************************************************************************
818 * VarUI1FromDec (OLEAUT32.240)
820 * Convert a VT_DECIMAL to a VT_UI1.
824 * pbOut [O] Destination
828 * Failure: E_INVALIDARG, if the source value is invalid
829 * DISP_E_OVERFLOW, if the value will not fit in the destination
831 HRESULT WINAPI
VarUI1FromDec(DECIMAL
*pdecIn
, BYTE
* pbOut
)
836 hRet
= VarI8FromDec(pdecIn
, &i64
);
839 hRet
= _VarUI1FromI8(i64
, pbOut
);
843 /************************************************************************
844 * VarUI1FromI8 (OLEAUT32.372)
846 * Convert a VT_I8 to a VT_UI1.
850 * pbOut [O] Destination
854 * Failure: E_INVALIDARG, if the source value is invalid
855 * DISP_E_OVERFLOW, if the value will not fit in the destination
857 HRESULT WINAPI
VarUI1FromI8(LONG64 llIn
, BYTE
* pbOut
)
859 return _VarUI1FromI8(llIn
, pbOut
);
862 /************************************************************************
863 * VarUI1FromUI8 (OLEAUT32.373)
865 * Convert a VT_UI8 to a VT_UI1.
869 * pbOut [O] Destination
873 * Failure: E_INVALIDARG, if the source value is invalid
874 * DISP_E_OVERFLOW, if the value will not fit in the destination
876 HRESULT WINAPI
VarUI1FromUI8(ULONG64 ullIn
, BYTE
* pbOut
)
878 return _VarUI1FromUI8(ullIn
, pbOut
);
885 /************************************************************************
886 * VarI2FromUI1 (OLEAUT32.48)
888 * Convert a VT_UI2 to a VT_I2.
892 * psOut [O] Destination
897 HRESULT WINAPI
VarI2FromUI1(BYTE bIn
, SHORT
* psOut
)
899 return _VarI2FromUI1(bIn
, psOut
);
902 /************************************************************************
903 * VarI2FromI4 (OLEAUT32.49)
905 * Convert a VT_I4 to a VT_I2.
909 * psOut [O] Destination
913 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
915 HRESULT WINAPI
VarI2FromI4(LONG iIn
, SHORT
* psOut
)
917 return _VarI2FromI4(iIn
, psOut
);
920 /************************************************************************
921 * VarI2FromR4 (OLEAUT32.50)
923 * Convert a VT_R4 to a VT_I2.
927 * psOut [O] Destination
931 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
933 HRESULT WINAPI
VarI2FromR4(FLOAT fltIn
, SHORT
* psOut
)
935 return VarI2FromR8(fltIn
, psOut
);
938 /************************************************************************
939 * VarI2FromR8 (OLEAUT32.51)
941 * Convert a VT_R8 to a VT_I2.
945 * psOut [O] Destination
949 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
952 * See VarI8FromR8() for details concerning rounding.
954 HRESULT WINAPI
VarI2FromR8(double dblIn
, SHORT
* psOut
)
956 if (dblIn
< I2_MIN
- 0.5 || dblIn
>= I2_MAX
+ 0.5)
957 return DISP_E_OVERFLOW
;
958 VARIANT_DutchRound(SHORT
, dblIn
, *psOut
);
962 /************************************************************************
963 * VarI2FromCy (OLEAUT32.52)
965 * Convert a VT_CY to a VT_I2.
969 * psOut [O] Destination
973 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
975 HRESULT WINAPI
VarI2FromCy(CY cyIn
, SHORT
* psOut
)
979 VarI4FromCy(cyIn
, &i
);
980 return _VarI2FromI4(i
, psOut
);
983 /************************************************************************
984 * VarI2FromDate (OLEAUT32.53)
986 * Convert a VT_DATE to a VT_I2.
990 * psOut [O] Destination
994 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
996 HRESULT WINAPI
VarI2FromDate(DATE dateIn
, SHORT
* psOut
)
998 return VarI2FromR8(dateIn
, psOut
);
1001 /************************************************************************
1002 * VarI2FromStr (OLEAUT32.54)
1004 * Convert a VT_BSTR to a VT_I2.
1008 * lcid [I] LCID for the conversion
1009 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1010 * psOut [O] Destination
1014 * Failure: E_INVALIDARG, if any parameter is invalid
1015 * DISP_E_OVERFLOW, if the value will not fit in the destination
1016 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1018 HRESULT WINAPI
VarI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, SHORT
* psOut
)
1020 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, psOut
, VT_I2
);
1023 /************************************************************************
1024 * VarI2FromDisp (OLEAUT32.55)
1026 * Convert a VT_DISPATCH to a VT_I2.
1029 * pdispIn [I] Source
1030 * lcid [I] LCID for conversion
1031 * psOut [O] Destination
1035 * Failure: E_INVALIDARG, if pdispIn is invalid,
1036 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1037 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1039 HRESULT WINAPI
VarI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, SHORT
* psOut
)
1041 return VARIANT_FromDisp(pdispIn
, lcid
, psOut
, VT_I2
, 0);
1044 /************************************************************************
1045 * VarI2FromBool (OLEAUT32.56)
1047 * Convert a VT_BOOL to a VT_I2.
1051 * psOut [O] Destination
1056 HRESULT WINAPI
VarI2FromBool(VARIANT_BOOL boolIn
, SHORT
* psOut
)
1058 return _VarI2FromBool(boolIn
, psOut
);
1061 /************************************************************************
1062 * VarI2FromI1 (OLEAUT32.205)
1064 * Convert a VT_I1 to a VT_I2.
1068 * psOut [O] Destination
1073 HRESULT WINAPI
VarI2FromI1(signed char cIn
, SHORT
* psOut
)
1075 return _VarI2FromI1(cIn
, psOut
);
1078 /************************************************************************
1079 * VarI2FromUI2 (OLEAUT32.206)
1081 * Convert a VT_UI2 to a VT_I2.
1085 * psOut [O] Destination
1089 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1091 HRESULT WINAPI
VarI2FromUI2(USHORT usIn
, SHORT
* psOut
)
1093 return _VarI2FromUI2(usIn
, psOut
);
1096 /************************************************************************
1097 * VarI2FromUI4 (OLEAUT32.207)
1099 * Convert a VT_UI4 to a VT_I2.
1103 * psOut [O] Destination
1107 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1109 HRESULT WINAPI
VarI2FromUI4(ULONG ulIn
, SHORT
* psOut
)
1111 return _VarI2FromUI4(ulIn
, psOut
);
1114 /************************************************************************
1115 * VarI2FromDec (OLEAUT32.208)
1117 * Convert a VT_DECIMAL to a VT_I2.
1121 * psOut [O] Destination
1125 * Failure: E_INVALIDARG, if the source value is invalid
1126 * DISP_E_OVERFLOW, if the value will not fit in the destination
1128 HRESULT WINAPI
VarI2FromDec(DECIMAL
*pdecIn
, SHORT
* psOut
)
1133 hRet
= VarI8FromDec(pdecIn
, &i64
);
1135 if (SUCCEEDED(hRet
))
1136 hRet
= _VarI2FromI8(i64
, psOut
);
1140 /************************************************************************
1141 * VarI2FromI8 (OLEAUT32.346)
1143 * Convert a VT_I8 to a VT_I2.
1147 * psOut [O] Destination
1151 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1153 HRESULT WINAPI
VarI2FromI8(LONG64 llIn
, SHORT
* psOut
)
1155 return _VarI2FromI8(llIn
, psOut
);
1158 /************************************************************************
1159 * VarI2FromUI8 (OLEAUT32.347)
1161 * Convert a VT_UI8 to a VT_I2.
1165 * psOut [O] Destination
1169 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1171 HRESULT WINAPI
VarI2FromUI8(ULONG64 ullIn
, SHORT
* psOut
)
1173 return _VarI2FromUI8(ullIn
, psOut
);
1179 /************************************************************************
1180 * VarUI2FromUI1 (OLEAUT32.257)
1182 * Convert a VT_UI1 to a VT_UI2.
1186 * pusOut [O] Destination
1191 HRESULT WINAPI
VarUI2FromUI1(BYTE bIn
, USHORT
* pusOut
)
1193 return _VarUI2FromUI1(bIn
, pusOut
);
1196 /************************************************************************
1197 * VarUI2FromI2 (OLEAUT32.258)
1199 * Convert a VT_I2 to a VT_UI2.
1203 * pusOut [O] Destination
1207 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1209 HRESULT WINAPI
VarUI2FromI2(SHORT sIn
, USHORT
* pusOut
)
1211 return _VarUI2FromI2(sIn
, pusOut
);
1214 /************************************************************************
1215 * VarUI2FromI4 (OLEAUT32.259)
1217 * Convert a VT_I4 to a VT_UI2.
1221 * pusOut [O] Destination
1225 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1227 HRESULT WINAPI
VarUI2FromI4(LONG iIn
, USHORT
* pusOut
)
1229 return _VarUI2FromI4(iIn
, pusOut
);
1232 /************************************************************************
1233 * VarUI2FromR4 (OLEAUT32.260)
1235 * Convert a VT_R4 to a VT_UI2.
1239 * pusOut [O] Destination
1243 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1245 HRESULT WINAPI
VarUI2FromR4(FLOAT fltIn
, USHORT
* pusOut
)
1247 return VarUI2FromR8(fltIn
, pusOut
);
1250 /************************************************************************
1251 * VarUI2FromR8 (OLEAUT32.261)
1253 * Convert a VT_R8 to a VT_UI2.
1257 * pusOut [O] Destination
1261 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1264 * See VarI8FromR8() for details concerning rounding.
1266 HRESULT WINAPI
VarUI2FromR8(double dblIn
, USHORT
* pusOut
)
1268 if (dblIn
< -0.5 || dblIn
>= UI2_MAX
+ 0.5)
1269 return DISP_E_OVERFLOW
;
1270 VARIANT_DutchRound(USHORT
, dblIn
, *pusOut
);
1274 /************************************************************************
1275 * VarUI2FromDate (OLEAUT32.262)
1277 * Convert a VT_DATE to a VT_UI2.
1281 * pusOut [O] Destination
1285 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1287 HRESULT WINAPI
VarUI2FromDate(DATE dateIn
, USHORT
* pusOut
)
1289 return VarUI2FromR8(dateIn
, pusOut
);
1292 /************************************************************************
1293 * VarUI2FromCy (OLEAUT32.263)
1295 * Convert a VT_CY to a VT_UI2.
1299 * pusOut [O] Destination
1303 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1306 * Negative values >= -5000 will be converted to 0.
1308 HRESULT WINAPI
VarUI2FromCy(CY cyIn
, USHORT
* pusOut
)
1310 ULONG i
= UI2_MAX
+ 1;
1312 VarUI4FromCy(cyIn
, &i
);
1313 return _VarUI2FromUI4(i
, pusOut
);
1316 /************************************************************************
1317 * VarUI2FromStr (OLEAUT32.264)
1319 * Convert a VT_BSTR to a VT_UI2.
1323 * lcid [I] LCID for the conversion
1324 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1325 * pusOut [O] Destination
1329 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1330 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1332 HRESULT WINAPI
VarUI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, USHORT
* pusOut
)
1334 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pusOut
, VT_UI2
);
1337 /************************************************************************
1338 * VarUI2FromDisp (OLEAUT32.265)
1340 * Convert a VT_DISPATCH to a VT_UI2.
1343 * pdispIn [I] Source
1344 * lcid [I] LCID for conversion
1345 * pusOut [O] Destination
1349 * Failure: E_INVALIDARG, if the source value is invalid
1350 * DISP_E_OVERFLOW, if the value will not fit in the destination
1351 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1353 HRESULT WINAPI
VarUI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, USHORT
* pusOut
)
1355 return VARIANT_FromDisp(pdispIn
, lcid
, pusOut
, VT_UI2
, 0);
1358 /************************************************************************
1359 * VarUI2FromBool (OLEAUT32.266)
1361 * Convert a VT_BOOL to a VT_UI2.
1365 * pusOut [O] Destination
1370 HRESULT WINAPI
VarUI2FromBool(VARIANT_BOOL boolIn
, USHORT
* pusOut
)
1372 return _VarUI2FromBool(boolIn
, pusOut
);
1375 /************************************************************************
1376 * VarUI2FromI1 (OLEAUT32.267)
1378 * Convert a VT_I1 to a VT_UI2.
1382 * pusOut [O] Destination
1386 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1388 HRESULT WINAPI
VarUI2FromI1(signed char cIn
, USHORT
* pusOut
)
1390 return _VarUI2FromI1(cIn
, pusOut
);
1393 /************************************************************************
1394 * VarUI2FromUI4 (OLEAUT32.268)
1396 * Convert a VT_UI4 to a VT_UI2.
1400 * pusOut [O] Destination
1404 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1406 HRESULT WINAPI
VarUI2FromUI4(ULONG ulIn
, USHORT
* pusOut
)
1408 return _VarUI2FromUI4(ulIn
, pusOut
);
1411 /************************************************************************
1412 * VarUI2FromDec (OLEAUT32.269)
1414 * Convert a VT_DECIMAL to a VT_UI2.
1418 * pusOut [O] Destination
1422 * Failure: E_INVALIDARG, if the source value is invalid
1423 * DISP_E_OVERFLOW, if the value will not fit in the destination
1425 HRESULT WINAPI
VarUI2FromDec(DECIMAL
*pdecIn
, USHORT
* pusOut
)
1430 hRet
= VarI8FromDec(pdecIn
, &i64
);
1432 if (SUCCEEDED(hRet
))
1433 hRet
= _VarUI2FromI8(i64
, pusOut
);
1437 /************************************************************************
1438 * VarUI2FromI8 (OLEAUT32.378)
1440 * Convert a VT_I8 to a VT_UI2.
1444 * pusOut [O] Destination
1448 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1450 HRESULT WINAPI
VarUI2FromI8(LONG64 llIn
, USHORT
* pusOut
)
1452 return _VarUI2FromI8(llIn
, pusOut
);
1455 /************************************************************************
1456 * VarUI2FromUI8 (OLEAUT32.379)
1458 * Convert a VT_UI8 to a VT_UI2.
1462 * pusOut [O] Destination
1466 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1468 HRESULT WINAPI
VarUI2FromUI8(ULONG64 ullIn
, USHORT
* pusOut
)
1470 return _VarUI2FromUI8(ullIn
, pusOut
);
1476 /************************************************************************
1477 * VarI4FromUI1 (OLEAUT32.58)
1479 * Convert a VT_UI1 to a VT_I4.
1483 * piOut [O] Destination
1488 HRESULT WINAPI
VarI4FromUI1(BYTE bIn
, LONG
*piOut
)
1490 return _VarI4FromUI1(bIn
, piOut
);
1493 /************************************************************************
1494 * VarI4FromI2 (OLEAUT32.59)
1496 * Convert a VT_I2 to a VT_I4.
1500 * piOut [O] Destination
1504 * Failure: E_INVALIDARG, if the source value is invalid
1505 * DISP_E_OVERFLOW, if the value will not fit in the destination
1507 HRESULT WINAPI
VarI4FromI2(SHORT sIn
, LONG
*piOut
)
1509 return _VarI4FromI2(sIn
, piOut
);
1512 /************************************************************************
1513 * VarI4FromR4 (OLEAUT32.60)
1515 * Convert a VT_R4 to a VT_I4.
1519 * piOut [O] Destination
1523 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1525 HRESULT WINAPI
VarI4FromR4(FLOAT fltIn
, LONG
*piOut
)
1527 return VarI4FromR8(fltIn
, piOut
);
1530 /************************************************************************
1531 * VarI4FromR8 (OLEAUT32.61)
1533 * Convert a VT_R8 to a VT_I4.
1537 * piOut [O] Destination
1541 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1544 * See VarI8FromR8() for details concerning rounding.
1546 HRESULT WINAPI
VarI4FromR8(double dblIn
, LONG
*piOut
)
1548 if (dblIn
< I4_MIN
- 0.5 || dblIn
>= I4_MAX
+ 0.5)
1549 return DISP_E_OVERFLOW
;
1550 VARIANT_DutchRound(LONG
, dblIn
, *piOut
);
1554 /************************************************************************
1555 * VarI4FromCy (OLEAUT32.62)
1557 * Convert a VT_CY to a VT_I4.
1561 * piOut [O] Destination
1565 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1567 HRESULT WINAPI
VarI4FromCy(CY cyIn
, LONG
*piOut
)
1569 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1570 return VarI4FromR8(d
, piOut
);
1573 /************************************************************************
1574 * VarI4FromDate (OLEAUT32.63)
1576 * Convert a VT_DATE to a VT_I4.
1580 * piOut [O] Destination
1584 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1586 HRESULT WINAPI
VarI4FromDate(DATE dateIn
, LONG
*piOut
)
1588 return VarI4FromR8(dateIn
, piOut
);
1591 /************************************************************************
1592 * VarI4FromStr (OLEAUT32.64)
1594 * Convert a VT_BSTR to a VT_I4.
1598 * lcid [I] LCID for the conversion
1599 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1600 * piOut [O] Destination
1604 * Failure: E_INVALIDARG, if any parameter is invalid
1605 * DISP_E_OVERFLOW, if the value will not fit in the destination
1606 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1608 HRESULT WINAPI
VarI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG
*piOut
)
1610 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, piOut
, VT_I4
);
1613 /************************************************************************
1614 * VarI4FromDisp (OLEAUT32.65)
1616 * Convert a VT_DISPATCH to a VT_I4.
1619 * pdispIn [I] Source
1620 * lcid [I] LCID for conversion
1621 * piOut [O] Destination
1625 * Failure: E_INVALIDARG, if the source value is invalid
1626 * DISP_E_OVERFLOW, if the value will not fit in the destination
1627 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1629 HRESULT WINAPI
VarI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG
*piOut
)
1631 return VARIANT_FromDisp(pdispIn
, lcid
, piOut
, VT_I4
, 0);
1634 /************************************************************************
1635 * VarI4FromBool (OLEAUT32.66)
1637 * Convert a VT_BOOL to a VT_I4.
1641 * piOut [O] Destination
1646 HRESULT WINAPI
VarI4FromBool(VARIANT_BOOL boolIn
, LONG
*piOut
)
1648 return _VarI4FromBool(boolIn
, piOut
);
1651 /************************************************************************
1652 * VarI4FromI1 (OLEAUT32.209)
1654 * Convert a VT_I1 to a VT_I4.
1658 * piOut [O] Destination
1663 HRESULT WINAPI
VarI4FromI1(signed char cIn
, LONG
*piOut
)
1665 return _VarI4FromI1(cIn
, piOut
);
1668 /************************************************************************
1669 * VarI4FromUI2 (OLEAUT32.210)
1671 * Convert a VT_UI2 to a VT_I4.
1675 * piOut [O] Destination
1680 HRESULT WINAPI
VarI4FromUI2(USHORT usIn
, LONG
*piOut
)
1682 return _VarI4FromUI2(usIn
, piOut
);
1685 /************************************************************************
1686 * VarI4FromUI4 (OLEAUT32.211)
1688 * Convert a VT_UI4 to a VT_I4.
1692 * piOut [O] Destination
1696 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1698 HRESULT WINAPI
VarI4FromUI4(ULONG ulIn
, LONG
*piOut
)
1700 return _VarI4FromUI4(ulIn
, piOut
);
1703 /************************************************************************
1704 * VarI4FromDec (OLEAUT32.212)
1706 * Convert a VT_DECIMAL to a VT_I4.
1710 * piOut [O] Destination
1714 * Failure: E_INVALIDARG, if pdecIn is invalid
1715 * DISP_E_OVERFLOW, if the value will not fit in the destination
1717 HRESULT WINAPI
VarI4FromDec(DECIMAL
*pdecIn
, LONG
*piOut
)
1722 hRet
= VarI8FromDec(pdecIn
, &i64
);
1724 if (SUCCEEDED(hRet
))
1725 hRet
= _VarI4FromI8(i64
, piOut
);
1729 /************************************************************************
1730 * VarI4FromI8 (OLEAUT32.348)
1732 * Convert a VT_I8 to a VT_I4.
1736 * piOut [O] Destination
1740 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1742 HRESULT WINAPI
VarI4FromI8(LONG64 llIn
, LONG
*piOut
)
1744 return _VarI4FromI8(llIn
, piOut
);
1747 /************************************************************************
1748 * VarI4FromUI8 (OLEAUT32.349)
1750 * Convert a VT_UI8 to a VT_I4.
1754 * piOut [O] Destination
1758 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1760 HRESULT WINAPI
VarI4FromUI8(ULONG64 ullIn
, LONG
*piOut
)
1762 return _VarI4FromUI8(ullIn
, piOut
);
1768 /************************************************************************
1769 * VarUI4FromUI1 (OLEAUT32.270)
1771 * Convert a VT_UI1 to a VT_UI4.
1775 * pulOut [O] Destination
1780 HRESULT WINAPI
VarUI4FromUI1(BYTE bIn
, ULONG
*pulOut
)
1782 return _VarUI4FromUI1(bIn
, pulOut
);
1785 /************************************************************************
1786 * VarUI4FromI2 (OLEAUT32.271)
1788 * Convert a VT_I2 to a VT_UI4.
1792 * pulOut [O] Destination
1796 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1798 HRESULT WINAPI
VarUI4FromI2(SHORT sIn
, ULONG
*pulOut
)
1800 return _VarUI4FromI2(sIn
, pulOut
);
1803 /************************************************************************
1804 * VarUI4FromI4 (OLEAUT32.272)
1806 * Convert a VT_I4 to a VT_UI4.
1810 * pulOut [O] Destination
1814 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1816 HRESULT WINAPI
VarUI4FromI4(LONG iIn
, ULONG
*pulOut
)
1818 return _VarUI4FromI4(iIn
, pulOut
);
1821 /************************************************************************
1822 * VarUI4FromR4 (OLEAUT32.273)
1824 * Convert a VT_R4 to a VT_UI4.
1828 * pulOut [O] Destination
1832 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1834 HRESULT WINAPI
VarUI4FromR4(FLOAT fltIn
, ULONG
*pulOut
)
1836 return VarUI4FromR8(fltIn
, pulOut
);
1839 /************************************************************************
1840 * VarUI4FromR8 (OLEAUT32.274)
1842 * Convert a VT_R8 to a VT_UI4.
1846 * pulOut [O] Destination
1850 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1853 * See VarI8FromR8() for details concerning rounding.
1855 HRESULT WINAPI
VarUI4FromR8(double dblIn
, ULONG
*pulOut
)
1857 if (dblIn
< -0.5 || dblIn
>= UI4_MAX
+ 0.5)
1858 return DISP_E_OVERFLOW
;
1859 VARIANT_DutchRound(ULONG
, dblIn
, *pulOut
);
1863 /************************************************************************
1864 * VarUI4FromDate (OLEAUT32.275)
1866 * Convert a VT_DATE to a VT_UI4.
1870 * pulOut [O] Destination
1874 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1876 HRESULT WINAPI
VarUI4FromDate(DATE dateIn
, ULONG
*pulOut
)
1878 return VarUI4FromR8(dateIn
, pulOut
);
1881 /************************************************************************
1882 * VarUI4FromCy (OLEAUT32.276)
1884 * Convert a VT_CY to a VT_UI4.
1888 * pulOut [O] Destination
1892 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1894 HRESULT WINAPI
VarUI4FromCy(CY cyIn
, ULONG
*pulOut
)
1896 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1897 return VarUI4FromR8(d
, pulOut
);
1900 /************************************************************************
1901 * VarUI4FromStr (OLEAUT32.277)
1903 * Convert a VT_BSTR to a VT_UI4.
1907 * lcid [I] LCID for the conversion
1908 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1909 * pulOut [O] Destination
1913 * Failure: E_INVALIDARG, if any parameter is invalid
1914 * DISP_E_OVERFLOW, if the value will not fit in the destination
1915 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1917 HRESULT WINAPI
VarUI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG
*pulOut
)
1919 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pulOut
, VT_UI4
);
1922 /************************************************************************
1923 * VarUI4FromDisp (OLEAUT32.278)
1925 * Convert a VT_DISPATCH to a VT_UI4.
1928 * pdispIn [I] Source
1929 * lcid [I] LCID for conversion
1930 * pulOut [O] Destination
1934 * Failure: E_INVALIDARG, if the source value is invalid
1935 * DISP_E_OVERFLOW, if the value will not fit in the destination
1936 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1938 HRESULT WINAPI
VarUI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG
*pulOut
)
1940 return VARIANT_FromDisp(pdispIn
, lcid
, pulOut
, VT_UI4
, 0);
1943 /************************************************************************
1944 * VarUI4FromBool (OLEAUT32.279)
1946 * Convert a VT_BOOL to a VT_UI4.
1950 * pulOut [O] Destination
1955 HRESULT WINAPI
VarUI4FromBool(VARIANT_BOOL boolIn
, ULONG
*pulOut
)
1957 return _VarUI4FromBool(boolIn
, pulOut
);
1960 /************************************************************************
1961 * VarUI4FromI1 (OLEAUT32.280)
1963 * Convert a VT_I1 to a VT_UI4.
1967 * pulOut [O] Destination
1971 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1973 HRESULT WINAPI
VarUI4FromI1(signed char cIn
, ULONG
*pulOut
)
1975 return _VarUI4FromI1(cIn
, pulOut
);
1978 /************************************************************************
1979 * VarUI4FromUI2 (OLEAUT32.281)
1981 * Convert a VT_UI2 to a VT_UI4.
1985 * pulOut [O] Destination
1990 HRESULT WINAPI
VarUI4FromUI2(USHORT usIn
, ULONG
*pulOut
)
1992 return _VarUI4FromUI2(usIn
, pulOut
);
1995 /************************************************************************
1996 * VarUI4FromDec (OLEAUT32.282)
1998 * Convert a VT_DECIMAL to a VT_UI4.
2002 * pulOut [O] Destination
2006 * Failure: E_INVALIDARG, if pdecIn is invalid
2007 * DISP_E_OVERFLOW, if the value will not fit in the destination
2009 HRESULT WINAPI
VarUI4FromDec(DECIMAL
*pdecIn
, ULONG
*pulOut
)
2014 hRet
= VarI8FromDec(pdecIn
, &i64
);
2016 if (SUCCEEDED(hRet
))
2017 hRet
= _VarUI4FromI8(i64
, pulOut
);
2021 /************************************************************************
2022 * VarUI4FromI8 (OLEAUT32.425)
2024 * Convert a VT_I8 to a VT_UI4.
2028 * pulOut [O] Destination
2032 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2034 HRESULT WINAPI
VarUI4FromI8(LONG64 llIn
, ULONG
*pulOut
)
2036 return _VarUI4FromI8(llIn
, pulOut
);
2039 /************************************************************************
2040 * VarUI4FromUI8 (OLEAUT32.426)
2042 * Convert a VT_UI8 to a VT_UI4.
2046 * pulOut [O] Destination
2050 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2052 HRESULT WINAPI
VarUI4FromUI8(ULONG64 ullIn
, ULONG
*pulOut
)
2054 return _VarUI4FromUI8(ullIn
, pulOut
);
2060 /************************************************************************
2061 * VarI8FromUI1 (OLEAUT32.333)
2063 * Convert a VT_UI1 to a VT_I8.
2067 * pi64Out [O] Destination
2072 HRESULT WINAPI
VarI8FromUI1(BYTE bIn
, LONG64
* pi64Out
)
2074 return _VarI8FromUI1(bIn
, pi64Out
);
2078 /************************************************************************
2079 * VarI8FromI2 (OLEAUT32.334)
2081 * Convert a VT_I2 to a VT_I8.
2085 * pi64Out [O] Destination
2090 HRESULT WINAPI
VarI8FromI2(SHORT sIn
, LONG64
* pi64Out
)
2092 return _VarI8FromI2(sIn
, pi64Out
);
2095 /************************************************************************
2096 * VarI8FromR4 (OLEAUT32.335)
2098 * Convert a VT_R4 to a VT_I8.
2102 * pi64Out [O] Destination
2106 * Failure: E_INVALIDARG, if the source value is invalid
2107 * DISP_E_OVERFLOW, if the value will not fit in the destination
2109 HRESULT WINAPI
VarI8FromR4(FLOAT fltIn
, LONG64
* pi64Out
)
2111 return VarI8FromR8(fltIn
, pi64Out
);
2114 /************************************************************************
2115 * VarI8FromR8 (OLEAUT32.336)
2117 * Convert a VT_R8 to a VT_I8.
2121 * pi64Out [O] Destination
2125 * Failure: E_INVALIDARG, if the source value is invalid
2126 * DISP_E_OVERFLOW, if the value will not fit in the destination
2129 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2130 * very high or low values will not be accurately converted.
2132 * Numbers are rounded using Dutch rounding, as follows:
2134 *| Fractional Part Sign Direction Example
2135 *| --------------- ---- --------- -------
2136 *| < 0.5 + Down 0.4 -> 0.0
2137 *| < 0.5 - Up -0.4 -> 0.0
2138 *| > 0.5 + Up 0.6 -> 1.0
2139 *| < 0.5 - Up -0.6 -> -1.0
2140 *| = 0.5 + Up/Down Down if even, Up if odd
2141 *| = 0.5 - Up/Down Up if even, Down if odd
2143 * This system is often used in supermarkets.
2145 HRESULT WINAPI
VarI8FromR8(double dblIn
, LONG64
* pi64Out
)
2147 if ( dblIn
< -4611686018427387904.0 || dblIn
>= 4611686018427387904.0)
2148 return DISP_E_OVERFLOW
;
2149 VARIANT_DutchRound(LONG64
, dblIn
, *pi64Out
);
2153 /************************************************************************
2154 * VarI8FromCy (OLEAUT32.337)
2156 * Convert a VT_CY to a VT_I8.
2160 * pi64Out [O] Destination
2166 * All negative numbers are rounded down by 1, including those that are
2167 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2168 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2171 HRESULT WINAPI
VarI8FromCy(CY cyIn
, LONG64
* pi64Out
)
2173 *pi64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2176 (*pi64Out
)--; /* Mimic Win32 bug */
2179 cyIn
.int64
-= *pi64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2181 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pi64Out
& 0x1)))
2187 /************************************************************************
2188 * VarI8FromDate (OLEAUT32.338)
2190 * Convert a VT_DATE to a VT_I8.
2194 * pi64Out [O] Destination
2198 * Failure: E_INVALIDARG, if the source value is invalid
2199 * DISP_E_OVERFLOW, if the value will not fit in the destination
2200 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2202 HRESULT WINAPI
VarI8FromDate(DATE dateIn
, LONG64
* pi64Out
)
2204 return VarI8FromR8(dateIn
, pi64Out
);
2207 /************************************************************************
2208 * VarI8FromStr (OLEAUT32.339)
2210 * Convert a VT_BSTR to a VT_I8.
2214 * lcid [I] LCID for the conversion
2215 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2216 * pi64Out [O] Destination
2220 * Failure: E_INVALIDARG, if the source value is invalid
2221 * DISP_E_OVERFLOW, if the value will not fit in the destination
2222 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2224 HRESULT WINAPI
VarI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG64
* pi64Out
)
2226 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pi64Out
, VT_I8
);
2229 /************************************************************************
2230 * VarI8FromDisp (OLEAUT32.340)
2232 * Convert a VT_DISPATCH to a VT_I8.
2235 * pdispIn [I] Source
2236 * lcid [I] LCID for conversion
2237 * pi64Out [O] Destination
2241 * Failure: E_INVALIDARG, if the source value is invalid
2242 * DISP_E_OVERFLOW, if the value will not fit in the destination
2243 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2245 HRESULT WINAPI
VarI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG64
* pi64Out
)
2247 return VARIANT_FromDisp(pdispIn
, lcid
, pi64Out
, VT_I8
, 0);
2250 /************************************************************************
2251 * VarI8FromBool (OLEAUT32.341)
2253 * Convert a VT_BOOL to a VT_I8.
2257 * pi64Out [O] Destination
2262 HRESULT WINAPI
VarI8FromBool(VARIANT_BOOL boolIn
, LONG64
* pi64Out
)
2264 return VarI8FromI2(boolIn
, pi64Out
);
2267 /************************************************************************
2268 * VarI8FromI1 (OLEAUT32.342)
2270 * Convert a VT_I1 to a VT_I8.
2274 * pi64Out [O] Destination
2279 HRESULT WINAPI
VarI8FromI1(signed char cIn
, LONG64
* pi64Out
)
2281 return _VarI8FromI1(cIn
, pi64Out
);
2284 /************************************************************************
2285 * VarI8FromUI2 (OLEAUT32.343)
2287 * Convert a VT_UI2 to a VT_I8.
2291 * pi64Out [O] Destination
2296 HRESULT WINAPI
VarI8FromUI2(USHORT usIn
, LONG64
* pi64Out
)
2298 return _VarI8FromUI2(usIn
, pi64Out
);
2301 /************************************************************************
2302 * VarI8FromUI4 (OLEAUT32.344)
2304 * Convert a VT_UI4 to a VT_I8.
2308 * pi64Out [O] Destination
2313 HRESULT WINAPI
VarI8FromUI4(ULONG ulIn
, LONG64
* pi64Out
)
2315 return _VarI8FromUI4(ulIn
, pi64Out
);
2318 /************************************************************************
2319 * VarI8FromDec (OLEAUT32.345)
2321 * Convert a VT_DECIMAL to a VT_I8.
2325 * pi64Out [O] Destination
2329 * Failure: E_INVALIDARG, if the source value is invalid
2330 * DISP_E_OVERFLOW, if the value will not fit in the destination
2332 HRESULT WINAPI
VarI8FromDec(DECIMAL
*pdecIn
, LONG64
* pi64Out
)
2334 if (!DEC_SCALE(pdecIn
))
2336 /* This decimal is just a 96 bit integer */
2337 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2338 return E_INVALIDARG
;
2340 if (DEC_HI32(pdecIn
) || DEC_MID32(pdecIn
) & 0x80000000)
2341 return DISP_E_OVERFLOW
;
2343 if (DEC_SIGN(pdecIn
))
2344 *pi64Out
= -DEC_LO64(pdecIn
);
2346 *pi64Out
= DEC_LO64(pdecIn
);
2351 /* Decimal contains a floating point number */
2355 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2356 if (SUCCEEDED(hRet
))
2357 hRet
= VarI8FromR8(dbl
, pi64Out
);
2362 /************************************************************************
2363 * VarI8FromUI8 (OLEAUT32.427)
2365 * Convert a VT_UI8 to a VT_I8.
2369 * pi64Out [O] Destination
2373 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2375 HRESULT WINAPI
VarI8FromUI8(ULONG64 ullIn
, LONG64
* pi64Out
)
2377 return _VarI8FromUI8(ullIn
, pi64Out
);
2383 /************************************************************************
2384 * VarUI8FromI8 (OLEAUT32.428)
2386 * Convert a VT_I8 to a VT_UI8.
2390 * pui64Out [O] Destination
2394 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2396 HRESULT WINAPI
VarUI8FromI8(LONG64 llIn
, ULONG64
* pui64Out
)
2398 return _VarUI8FromI8(llIn
, pui64Out
);
2401 /************************************************************************
2402 * VarUI8FromUI1 (OLEAUT32.429)
2404 * Convert a VT_UI1 to a VT_UI8.
2408 * pui64Out [O] Destination
2413 HRESULT WINAPI
VarUI8FromUI1(BYTE bIn
, ULONG64
* pui64Out
)
2415 return _VarUI8FromUI1(bIn
, pui64Out
);
2418 /************************************************************************
2419 * VarUI8FromI2 (OLEAUT32.430)
2421 * Convert a VT_I2 to a VT_UI8.
2425 * pui64Out [O] Destination
2430 HRESULT WINAPI
VarUI8FromI2(SHORT sIn
, ULONG64
* pui64Out
)
2432 return _VarUI8FromI2(sIn
, pui64Out
);
2435 /************************************************************************
2436 * VarUI8FromR4 (OLEAUT32.431)
2438 * Convert a VT_R4 to a VT_UI8.
2442 * pui64Out [O] Destination
2446 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2448 HRESULT WINAPI
VarUI8FromR4(FLOAT fltIn
, ULONG64
* pui64Out
)
2450 return VarUI8FromR8(fltIn
, pui64Out
);
2453 /************************************************************************
2454 * VarUI8FromR8 (OLEAUT32.432)
2456 * Convert a VT_R8 to a VT_UI8.
2460 * pui64Out [O] Destination
2464 * Failure: E_INVALIDARG, if the source value is invalid
2465 * DISP_E_OVERFLOW, if the value will not fit in the destination
2468 * See VarI8FromR8() for details concerning rounding.
2470 HRESULT WINAPI
VarUI8FromR8(double dblIn
, ULONG64
* pui64Out
)
2472 if (dblIn
< -0.5 || dblIn
> 1.844674407370955e19
)
2473 return DISP_E_OVERFLOW
;
2474 VARIANT_DutchRound(ULONG64
, dblIn
, *pui64Out
);
2478 /************************************************************************
2479 * VarUI8FromCy (OLEAUT32.433)
2481 * Convert a VT_CY to a VT_UI8.
2485 * pui64Out [O] Destination
2489 * Failure: E_INVALIDARG, if the source value is invalid
2490 * DISP_E_OVERFLOW, if the value will not fit in the destination
2493 * Negative values >= -5000 will be converted to 0.
2495 HRESULT WINAPI
VarUI8FromCy(CY cyIn
, ULONG64
* pui64Out
)
2499 if (cyIn
.int64
< -CY_HALF
)
2500 return DISP_E_OVERFLOW
;
2505 *pui64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2507 cyIn
.int64
-= *pui64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2509 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pui64Out
& 0x1)))
2515 /************************************************************************
2516 * VarUI8FromDate (OLEAUT32.434)
2518 * Convert a VT_DATE to a VT_UI8.
2522 * pui64Out [O] Destination
2526 * Failure: E_INVALIDARG, if the source value is invalid
2527 * DISP_E_OVERFLOW, if the value will not fit in the destination
2528 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2530 HRESULT WINAPI
VarUI8FromDate(DATE dateIn
, ULONG64
* pui64Out
)
2532 return VarUI8FromR8(dateIn
, pui64Out
);
2535 /************************************************************************
2536 * VarUI8FromStr (OLEAUT32.435)
2538 * Convert a VT_BSTR to a VT_UI8.
2542 * lcid [I] LCID for the conversion
2543 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2544 * pui64Out [O] Destination
2548 * Failure: E_INVALIDARG, if the source value is invalid
2549 * DISP_E_OVERFLOW, if the value will not fit in the destination
2550 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2552 HRESULT WINAPI
VarUI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG64
* pui64Out
)
2554 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pui64Out
, VT_UI8
);
2557 /************************************************************************
2558 * VarUI8FromDisp (OLEAUT32.436)
2560 * Convert a VT_DISPATCH to a VT_UI8.
2563 * pdispIn [I] Source
2564 * lcid [I] LCID for conversion
2565 * pui64Out [O] Destination
2569 * Failure: E_INVALIDARG, if the source value is invalid
2570 * DISP_E_OVERFLOW, if the value will not fit in the destination
2571 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2573 HRESULT WINAPI
VarUI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG64
* pui64Out
)
2575 return VARIANT_FromDisp(pdispIn
, lcid
, pui64Out
, VT_UI8
, 0);
2578 /************************************************************************
2579 * VarUI8FromBool (OLEAUT32.437)
2581 * Convert a VT_BOOL to a VT_UI8.
2585 * pui64Out [O] Destination
2589 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2591 HRESULT WINAPI
VarUI8FromBool(VARIANT_BOOL boolIn
, ULONG64
* pui64Out
)
2593 return VarI8FromI2(boolIn
, (LONG64
*)pui64Out
);
2595 /************************************************************************
2596 * VarUI8FromI1 (OLEAUT32.438)
2598 * Convert a VT_I1 to a VT_UI8.
2602 * pui64Out [O] Destination
2606 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2608 HRESULT WINAPI
VarUI8FromI1(signed char cIn
, ULONG64
* pui64Out
)
2610 return _VarUI8FromI1(cIn
, pui64Out
);
2613 /************************************************************************
2614 * VarUI8FromUI2 (OLEAUT32.439)
2616 * Convert a VT_UI2 to a VT_UI8.
2620 * pui64Out [O] Destination
2625 HRESULT WINAPI
VarUI8FromUI2(USHORT usIn
, ULONG64
* pui64Out
)
2627 return _VarUI8FromUI2(usIn
, pui64Out
);
2630 /************************************************************************
2631 * VarUI8FromUI4 (OLEAUT32.440)
2633 * Convert a VT_UI4 to a VT_UI8.
2637 * pui64Out [O] Destination
2642 HRESULT WINAPI
VarUI8FromUI4(ULONG ulIn
, ULONG64
* pui64Out
)
2644 return _VarUI8FromUI4(ulIn
, pui64Out
);
2647 /************************************************************************
2648 * VarUI8FromDec (OLEAUT32.441)
2650 * Convert a VT_DECIMAL to a VT_UI8.
2654 * pui64Out [O] Destination
2658 * Failure: E_INVALIDARG, if the source value is invalid
2659 * DISP_E_OVERFLOW, if the value will not fit in the destination
2662 * Under native Win32, if the source value has a scale of 0, its sign is
2663 * ignored, i.e. this function takes the absolute value rather than fail
2664 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2665 * (use VarAbs() on pDecIn first if you really want this behaviour).
2667 HRESULT WINAPI
VarUI8FromDec(DECIMAL
*pdecIn
, ULONG64
* pui64Out
)
2669 if (!DEC_SCALE(pdecIn
))
2671 /* This decimal is just a 96 bit integer */
2672 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2673 return E_INVALIDARG
;
2675 if (DEC_HI32(pdecIn
))
2676 return DISP_E_OVERFLOW
;
2678 if (DEC_SIGN(pdecIn
))
2680 WARN("Sign would be ignored under Win32!\n");
2681 return DISP_E_OVERFLOW
;
2684 *pui64Out
= DEC_LO64(pdecIn
);
2689 /* Decimal contains a floating point number */
2693 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2694 if (SUCCEEDED(hRet
))
2695 hRet
= VarUI8FromR8(dbl
, pui64Out
);
2703 /************************************************************************
2704 * VarR4FromUI1 (OLEAUT32.68)
2706 * Convert a VT_UI1 to a VT_R4.
2710 * pFltOut [O] Destination
2715 HRESULT WINAPI
VarR4FromUI1(BYTE bIn
, float *pFltOut
)
2717 return _VarR4FromUI1(bIn
, pFltOut
);
2720 /************************************************************************
2721 * VarR4FromI2 (OLEAUT32.69)
2723 * Convert a VT_I2 to a VT_R4.
2727 * pFltOut [O] Destination
2732 HRESULT WINAPI
VarR4FromI2(SHORT sIn
, float *pFltOut
)
2734 return _VarR4FromI2(sIn
, pFltOut
);
2737 /************************************************************************
2738 * VarR4FromI4 (OLEAUT32.70)
2740 * Convert a VT_I4 to a VT_R4.
2744 * pFltOut [O] Destination
2749 HRESULT WINAPI
VarR4FromI4(LONG lIn
, float *pFltOut
)
2751 return _VarR4FromI4(lIn
, pFltOut
);
2754 /************************************************************************
2755 * VarR4FromR8 (OLEAUT32.71)
2757 * Convert a VT_R8 to a VT_R4.
2761 * pFltOut [O] Destination
2765 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2767 HRESULT WINAPI
VarR4FromR8(double dblIn
, float *pFltOut
)
2769 double d
= dblIn
< 0.0 ? -dblIn
: dblIn
;
2770 if (d
> R4_MAX
) return DISP_E_OVERFLOW
;
2775 /************************************************************************
2776 * VarR4FromCy (OLEAUT32.72)
2778 * Convert a VT_CY to a VT_R4.
2782 * pFltOut [O] Destination
2787 HRESULT WINAPI
VarR4FromCy(CY cyIn
, float *pFltOut
)
2789 *pFltOut
= (double)cyIn
.int64
/ CY_MULTIPLIER_F
;
2793 /************************************************************************
2794 * VarR4FromDate (OLEAUT32.73)
2796 * Convert a VT_DATE to a VT_R4.
2800 * pFltOut [O] Destination
2804 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2806 HRESULT WINAPI
VarR4FromDate(DATE dateIn
, float *pFltOut
)
2808 return VarR4FromR8(dateIn
, pFltOut
);
2811 /************************************************************************
2812 * VarR4FromStr (OLEAUT32.74)
2814 * Convert a VT_BSTR to a VT_R4.
2818 * lcid [I] LCID for the conversion
2819 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2820 * pFltOut [O] Destination
2824 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2825 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2827 HRESULT WINAPI
VarR4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, float *pFltOut
)
2829 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pFltOut
, VT_R4
);
2832 /************************************************************************
2833 * VarR4FromDisp (OLEAUT32.75)
2835 * Convert a VT_DISPATCH to a VT_R4.
2838 * pdispIn [I] Source
2839 * lcid [I] LCID for conversion
2840 * pFltOut [O] Destination
2844 * Failure: E_INVALIDARG, if the source value is invalid
2845 * DISP_E_OVERFLOW, if the value will not fit in the destination
2846 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2848 HRESULT WINAPI
VarR4FromDisp(IDispatch
* pdispIn
, LCID lcid
, float *pFltOut
)
2850 return VARIANT_FromDisp(pdispIn
, lcid
, pFltOut
, VT_R4
, 0);
2853 /************************************************************************
2854 * VarR4FromBool (OLEAUT32.76)
2856 * Convert a VT_BOOL to a VT_R4.
2860 * pFltOut [O] Destination
2865 HRESULT WINAPI
VarR4FromBool(VARIANT_BOOL boolIn
, float *pFltOut
)
2867 return VarR4FromI2(boolIn
, pFltOut
);
2870 /************************************************************************
2871 * VarR4FromI1 (OLEAUT32.213)
2873 * Convert a VT_I1 to a VT_R4.
2877 * pFltOut [O] Destination
2881 * Failure: E_INVALIDARG, if the source value is invalid
2882 * DISP_E_OVERFLOW, if the value will not fit in the destination
2883 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2885 HRESULT WINAPI
VarR4FromI1(signed char cIn
, float *pFltOut
)
2887 return _VarR4FromI1(cIn
, pFltOut
);
2890 /************************************************************************
2891 * VarR4FromUI2 (OLEAUT32.214)
2893 * Convert a VT_UI2 to a VT_R4.
2897 * pFltOut [O] Destination
2901 * Failure: E_INVALIDARG, if the source value is invalid
2902 * DISP_E_OVERFLOW, if the value will not fit in the destination
2903 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2905 HRESULT WINAPI
VarR4FromUI2(USHORT usIn
, float *pFltOut
)
2907 return _VarR4FromUI2(usIn
, pFltOut
);
2910 /************************************************************************
2911 * VarR4FromUI4 (OLEAUT32.215)
2913 * Convert a VT_UI4 to a VT_R4.
2917 * pFltOut [O] Destination
2921 * Failure: E_INVALIDARG, if the source value is invalid
2922 * DISP_E_OVERFLOW, if the value will not fit in the destination
2923 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2925 HRESULT WINAPI
VarR4FromUI4(ULONG ulIn
, float *pFltOut
)
2927 return _VarR4FromUI4(ulIn
, pFltOut
);
2930 /************************************************************************
2931 * VarR4FromDec (OLEAUT32.216)
2933 * Convert a VT_DECIMAL to a VT_R4.
2937 * pFltOut [O] Destination
2941 * Failure: E_INVALIDARG, if the source value is invalid.
2943 HRESULT WINAPI
VarR4FromDec(DECIMAL
* pDecIn
, float *pFltOut
)
2945 BYTE scale
= DEC_SCALE(pDecIn
);
2946 double divisor
= 1.0;
2949 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
2950 return E_INVALIDARG
;
2955 if (DEC_SIGN(pDecIn
))
2958 if (DEC_HI32(pDecIn
))
2960 highPart
= (double)DEC_HI32(pDecIn
) / divisor
;
2961 highPart
*= 4294967296.0F
;
2962 highPart
*= 4294967296.0F
;
2967 *pFltOut
= (double)DEC_LO64(pDecIn
) / divisor
+ highPart
;
2971 /************************************************************************
2972 * VarR4FromI8 (OLEAUT32.360)
2974 * Convert a VT_I8 to a VT_R4.
2978 * pFltOut [O] Destination
2983 HRESULT WINAPI
VarR4FromI8(LONG64 llIn
, float *pFltOut
)
2985 return _VarR4FromI8(llIn
, pFltOut
);
2988 /************************************************************************
2989 * VarR4FromUI8 (OLEAUT32.361)
2991 * Convert a VT_UI8 to a VT_R4.
2995 * pFltOut [O] Destination
3000 HRESULT WINAPI
VarR4FromUI8(ULONG64 ullIn
, float *pFltOut
)
3002 return _VarR4FromUI8(ullIn
, pFltOut
);
3005 /************************************************************************
3006 * VarR4CmpR8 (OLEAUT32.316)
3008 * Compare a VT_R4 to a VT_R8.
3011 * fltLeft [I] Source
3012 * dblRight [I] Value to compare
3015 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3016 * equal to or greater than dblRight respectively.
3018 HRESULT WINAPI
VarR4CmpR8(float fltLeft
, double dblRight
)
3020 if (fltLeft
< dblRight
)
3022 else if (fltLeft
> dblRight
)
3030 /************************************************************************
3031 * VarR8FromUI1 (OLEAUT32.78)
3033 * Convert a VT_UI1 to a VT_R8.
3037 * pDblOut [O] Destination
3042 HRESULT WINAPI
VarR8FromUI1(BYTE bIn
, double *pDblOut
)
3044 return _VarR8FromUI1(bIn
, pDblOut
);
3047 /************************************************************************
3048 * VarR8FromI2 (OLEAUT32.79)
3050 * Convert a VT_I2 to a VT_R8.
3054 * pDblOut [O] Destination
3059 HRESULT WINAPI
VarR8FromI2(SHORT sIn
, double *pDblOut
)
3061 return _VarR8FromI2(sIn
, pDblOut
);
3064 /************************************************************************
3065 * VarR8FromI4 (OLEAUT32.80)
3067 * Convert a VT_I4 to a VT_R8.
3071 * pDblOut [O] Destination
3076 HRESULT WINAPI
VarR8FromI4(LONG lIn
, double *pDblOut
)
3078 return _VarR8FromI4(lIn
, pDblOut
);
3081 /************************************************************************
3082 * VarR8FromR4 (OLEAUT32.81)
3084 * Convert a VT_R4 to a VT_R8.
3088 * pDblOut [O] Destination
3093 HRESULT WINAPI
VarR8FromR4(FLOAT fltIn
, double *pDblOut
)
3095 return _VarR8FromR4(fltIn
, pDblOut
);
3098 /************************************************************************
3099 * VarR8FromCy (OLEAUT32.82)
3101 * Convert a VT_CY to a VT_R8.
3105 * pDblOut [O] Destination
3110 HRESULT WINAPI
VarR8FromCy(CY cyIn
, double *pDblOut
)
3112 return _VarR8FromCy(cyIn
, pDblOut
);
3115 /************************************************************************
3116 * VarR8FromDate (OLEAUT32.83)
3118 * Convert a VT_DATE to a VT_R8.
3122 * pDblOut [O] Destination
3127 HRESULT WINAPI
VarR8FromDate(DATE dateIn
, double *pDblOut
)
3129 return _VarR8FromDate(dateIn
, pDblOut
);
3132 /************************************************************************
3133 * VarR8FromStr (OLEAUT32.84)
3135 * Convert a VT_BSTR to a VT_R8.
3139 * lcid [I] LCID for the conversion
3140 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3141 * pDblOut [O] Destination
3145 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3146 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3148 HRESULT WINAPI
VarR8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, double *pDblOut
)
3150 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDblOut
, VT_R8
);
3153 /************************************************************************
3154 * VarR8FromDisp (OLEAUT32.85)
3156 * Convert a VT_DISPATCH to a VT_R8.
3159 * pdispIn [I] Source
3160 * lcid [I] LCID for conversion
3161 * pDblOut [O] Destination
3165 * Failure: E_INVALIDARG, if the source value is invalid
3166 * DISP_E_OVERFLOW, if the value will not fit in the destination
3167 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3169 HRESULT WINAPI
VarR8FromDisp(IDispatch
* pdispIn
, LCID lcid
, double *pDblOut
)
3171 return VARIANT_FromDisp(pdispIn
, lcid
, pDblOut
, VT_R8
, 0);
3174 /************************************************************************
3175 * VarR8FromBool (OLEAUT32.86)
3177 * Convert a VT_BOOL to a VT_R8.
3181 * pDblOut [O] Destination
3186 HRESULT WINAPI
VarR8FromBool(VARIANT_BOOL boolIn
, double *pDblOut
)
3188 return VarR8FromI2(boolIn
, pDblOut
);
3191 /************************************************************************
3192 * VarR8FromI1 (OLEAUT32.217)
3194 * Convert a VT_I1 to a VT_R8.
3198 * pDblOut [O] Destination
3202 * Failure: E_INVALIDARG, if the source value is invalid
3203 * DISP_E_OVERFLOW, if the value will not fit in the destination
3204 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3206 HRESULT WINAPI
VarR8FromI1(signed char cIn
, double *pDblOut
)
3208 return _VarR8FromI1(cIn
, pDblOut
);
3211 /************************************************************************
3212 * VarR8FromUI2 (OLEAUT32.218)
3214 * Convert a VT_UI2 to a VT_R8.
3218 * pDblOut [O] Destination
3222 * Failure: E_INVALIDARG, if the source value is invalid
3223 * DISP_E_OVERFLOW, if the value will not fit in the destination
3224 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3226 HRESULT WINAPI
VarR8FromUI2(USHORT usIn
, double *pDblOut
)
3228 return _VarR8FromUI2(usIn
, pDblOut
);
3231 /************************************************************************
3232 * VarR8FromUI4 (OLEAUT32.219)
3234 * Convert a VT_UI4 to a VT_R8.
3238 * pDblOut [O] Destination
3242 * Failure: E_INVALIDARG, if the source value is invalid
3243 * DISP_E_OVERFLOW, if the value will not fit in the destination
3244 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3246 HRESULT WINAPI
VarR8FromUI4(ULONG ulIn
, double *pDblOut
)
3248 return _VarR8FromUI4(ulIn
, pDblOut
);
3251 /************************************************************************
3252 * VarR8FromDec (OLEAUT32.220)
3254 * Convert a VT_DECIMAL to a VT_R8.
3258 * pDblOut [O] Destination
3262 * Failure: E_INVALIDARG, if the source value is invalid.
3264 HRESULT WINAPI
VarR8FromDec(const DECIMAL
* pDecIn
, double *pDblOut
)
3266 BYTE scale
= DEC_SCALE(pDecIn
);
3267 double divisor
= 1.0, highPart
;
3269 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
3270 return E_INVALIDARG
;
3275 if (DEC_SIGN(pDecIn
))
3278 if (DEC_HI32(pDecIn
))
3280 highPart
= (double)DEC_HI32(pDecIn
) / divisor
;
3281 highPart
*= 4294967296.0F
;
3282 highPart
*= 4294967296.0F
;
3287 *pDblOut
= (double)DEC_LO64(pDecIn
) / divisor
+ highPart
;
3291 /************************************************************************
3292 * VarR8FromI8 (OLEAUT32.362)
3294 * Convert a VT_I8 to a VT_R8.
3298 * pDblOut [O] Destination
3303 HRESULT WINAPI
VarR8FromI8(LONG64 llIn
, double *pDblOut
)
3305 return _VarR8FromI8(llIn
, pDblOut
);
3308 /************************************************************************
3309 * VarR8FromUI8 (OLEAUT32.363)
3311 * Convert a VT_UI8 to a VT_R8.
3315 * pDblOut [O] Destination
3320 HRESULT WINAPI
VarR8FromUI8(ULONG64 ullIn
, double *pDblOut
)
3322 return _VarR8FromUI8(ullIn
, pDblOut
);
3325 /************************************************************************
3326 * VarR8Pow (OLEAUT32.315)
3328 * Raise a VT_R8 to a power.
3331 * dblLeft [I] Source
3332 * dblPow [I] Power to raise dblLeft by
3333 * pDblOut [O] Destination
3336 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3338 HRESULT WINAPI
VarR8Pow(double dblLeft
, double dblPow
, double *pDblOut
)
3340 *pDblOut
= pow(dblLeft
, dblPow
);
3344 /************************************************************************
3345 * VarR8Round (OLEAUT32.317)
3347 * Round a VT_R8 to a given number of decimal points.
3351 * nDig [I] Number of decimal points to round to
3352 * pDblOut [O] Destination for rounded number
3355 * Success: S_OK. pDblOut is rounded to nDig digits.
3356 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3359 * The native version of this function rounds using the internal
3360 * binary representation of the number. Wine uses the dutch rounding
3361 * convention, so therefore small differences can occur in the value returned.
3362 * MSDN says that you should use your own rounding function if you want
3363 * rounding to be predictable in your application.
3365 HRESULT WINAPI
VarR8Round(double dblIn
, int nDig
, double *pDblOut
)
3367 double scale
, whole
, fract
;
3370 return E_INVALIDARG
;
3372 scale
= pow(10.0, nDig
);
3375 whole
= dblIn
< 0 ? ceil(dblIn
) : floor(dblIn
);
3376 fract
= dblIn
- whole
;
3379 dblIn
= whole
+ 1.0;
3380 else if (fract
== 0.5)
3381 dblIn
= whole
+ fmod(whole
, 2.0);
3382 else if (fract
>= 0.0)
3384 else if (fract
== -0.5)
3385 dblIn
= whole
- fmod(whole
, 2.0);
3386 else if (fract
> -0.5)
3389 dblIn
= whole
- 1.0;
3391 *pDblOut
= dblIn
/ scale
;
3398 /* Powers of 10 from 0..4 D.P. */
3399 static const int CY_Divisors
[5] = { CY_MULTIPLIER
/10000, CY_MULTIPLIER
/1000,
3400 CY_MULTIPLIER
/100, CY_MULTIPLIER
/10, CY_MULTIPLIER
};
3402 /************************************************************************
3403 * VarCyFromUI1 (OLEAUT32.98)
3405 * Convert a VT_UI1 to a VT_CY.
3409 * pCyOut [O] Destination
3413 * Failure: E_INVALIDARG, if the source value is invalid
3414 * DISP_E_OVERFLOW, if the value will not fit in the destination
3415 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3417 HRESULT WINAPI
VarCyFromUI1(BYTE bIn
, CY
* pCyOut
)
3419 pCyOut
->int64
= (ULONG64
)bIn
* CY_MULTIPLIER
;
3423 /************************************************************************
3424 * VarCyFromI2 (OLEAUT32.99)
3426 * Convert a VT_I2 to a VT_CY.
3430 * pCyOut [O] Destination
3434 * Failure: E_INVALIDARG, if the source value is invalid
3435 * DISP_E_OVERFLOW, if the value will not fit in the destination
3436 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3438 HRESULT WINAPI
VarCyFromI2(SHORT sIn
, CY
* pCyOut
)
3440 pCyOut
->int64
= (LONG64
)sIn
* CY_MULTIPLIER
;
3444 /************************************************************************
3445 * VarCyFromI4 (OLEAUT32.100)
3447 * Convert a VT_I4 to a VT_CY.
3451 * pCyOut [O] Destination
3455 * Failure: E_INVALIDARG, if the source value is invalid
3456 * DISP_E_OVERFLOW, if the value will not fit in the destination
3457 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3459 HRESULT WINAPI
VarCyFromI4(LONG lIn
, CY
* pCyOut
)
3461 pCyOut
->int64
= (LONG64
)lIn
* CY_MULTIPLIER
;
3465 /************************************************************************
3466 * VarCyFromR4 (OLEAUT32.101)
3468 * Convert a VT_R4 to a VT_CY.
3472 * pCyOut [O] Destination
3476 * Failure: E_INVALIDARG, if the source value is invalid
3477 * DISP_E_OVERFLOW, if the value will not fit in the destination
3478 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3480 HRESULT WINAPI
VarCyFromR4(FLOAT fltIn
, CY
* pCyOut
)
3482 return VarCyFromR8(fltIn
, pCyOut
);
3485 /************************************************************************
3486 * VarCyFromR8 (OLEAUT32.102)
3488 * Convert a VT_R8 to a VT_CY.
3492 * pCyOut [O] Destination
3496 * Failure: E_INVALIDARG, if the source value is invalid
3497 * DISP_E_OVERFLOW, if the value will not fit in the destination
3498 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3500 HRESULT WINAPI
VarCyFromR8(double dblIn
, CY
* pCyOut
)
3502 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3503 /* This code gives identical results to Win32 on Intel.
3504 * Here we use fp exceptions to catch overflows when storing the value.
3506 static const unsigned short r8_fpcontrol
= 0x137f;
3507 static const double r8_multiplier
= CY_MULTIPLIER_F
;
3508 unsigned short old_fpcontrol
, result_fpstatus
;
3510 /* Clear exceptions, save the old fp state and load the new state */
3511 __asm__
__volatile__( "fnclex" );
3512 __asm__
__volatile__( "fstcw %0" : "=m" (old_fpcontrol
) : );
3513 __asm__
__volatile__( "fldcw %0" : : "m" (r8_fpcontrol
) );
3514 /* Perform the conversion. */
3515 __asm__
__volatile__( "fldl %0" : : "m" (dblIn
) );
3516 __asm__
__volatile__( "fmull %0" : : "m" (r8_multiplier
) );
3517 __asm__
__volatile__( "fistpll %0" : : "m" (*pCyOut
) );
3518 /* Save the resulting fp state, load the old state and clear exceptions */
3519 __asm__
__volatile__( "fstsw %0" : "=m" (result_fpstatus
) : );
3520 __asm__
__volatile__( "fnclex" );
3521 __asm__
__volatile__( "fldcw %0" : : "m" (old_fpcontrol
) );
3523 if (result_fpstatus
& 0x9) /* Overflow | Invalid */
3524 return DISP_E_OVERFLOW
;
3526 /* This version produces slightly different results for boundary cases */
3527 if (dblIn
< -922337203685477.5807 || dblIn
>= 922337203685477.5807)
3528 return DISP_E_OVERFLOW
;
3529 dblIn
*= CY_MULTIPLIER_F
;
3530 VARIANT_DutchRound(LONG64
, dblIn
, pCyOut
->int64
);
3535 /************************************************************************
3536 * VarCyFromDate (OLEAUT32.103)
3538 * Convert a VT_DATE to a VT_CY.
3542 * pCyOut [O] Destination
3546 * Failure: E_INVALIDARG, if the source value is invalid
3547 * DISP_E_OVERFLOW, if the value will not fit in the destination
3548 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3550 HRESULT WINAPI
VarCyFromDate(DATE dateIn
, CY
* pCyOut
)
3552 return VarCyFromR8(dateIn
, pCyOut
);
3555 /************************************************************************
3556 * VarCyFromStr (OLEAUT32.104)
3558 * Convert a VT_BSTR to a VT_CY.
3562 * lcid [I] LCID for the conversion
3563 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3564 * pCyOut [O] Destination
3568 * Failure: E_INVALIDARG, if the source value is invalid
3569 * DISP_E_OVERFLOW, if the value will not fit in the destination
3570 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3572 HRESULT WINAPI
VarCyFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, CY
* pCyOut
)
3574 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pCyOut
, VT_CY
);
3577 /************************************************************************
3578 * VarCyFromDisp (OLEAUT32.105)
3580 * Convert a VT_DISPATCH to a VT_CY.
3583 * pdispIn [I] Source
3584 * lcid [I] LCID for conversion
3585 * pCyOut [O] Destination
3589 * Failure: E_INVALIDARG, if the source value is invalid
3590 * DISP_E_OVERFLOW, if the value will not fit in the destination
3591 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3593 HRESULT WINAPI
VarCyFromDisp(IDispatch
* pdispIn
, LCID lcid
, CY
* pCyOut
)
3595 return VARIANT_FromDisp(pdispIn
, lcid
, pCyOut
, VT_CY
, 0);
3598 /************************************************************************
3599 * VarCyFromBool (OLEAUT32.106)
3601 * Convert a VT_BOOL to a VT_CY.
3605 * pCyOut [O] Destination
3609 * Failure: E_INVALIDARG, if the source value is invalid
3610 * DISP_E_OVERFLOW, if the value will not fit in the destination
3611 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3614 * While the sign of the boolean is stored in the currency, the value is
3615 * converted to either 0 or 1.
3617 HRESULT WINAPI
VarCyFromBool(VARIANT_BOOL boolIn
, CY
* pCyOut
)
3619 pCyOut
->int64
= (LONG64
)boolIn
* CY_MULTIPLIER
;
3623 /************************************************************************
3624 * VarCyFromI1 (OLEAUT32.225)
3626 * Convert a VT_I1 to a VT_CY.
3630 * pCyOut [O] Destination
3634 * Failure: E_INVALIDARG, if the source value is invalid
3635 * DISP_E_OVERFLOW, if the value will not fit in the destination
3636 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3638 HRESULT WINAPI
VarCyFromI1(signed char cIn
, CY
* pCyOut
)
3640 pCyOut
->int64
= (LONG64
)cIn
* CY_MULTIPLIER
;
3644 /************************************************************************
3645 * VarCyFromUI2 (OLEAUT32.226)
3647 * Convert a VT_UI2 to a VT_CY.
3651 * pCyOut [O] Destination
3655 * Failure: E_INVALIDARG, if the source value is invalid
3656 * DISP_E_OVERFLOW, if the value will not fit in the destination
3657 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3659 HRESULT WINAPI
VarCyFromUI2(USHORT usIn
, CY
* pCyOut
)
3661 pCyOut
->int64
= (ULONG64
)usIn
* CY_MULTIPLIER
;
3665 /************************************************************************
3666 * VarCyFromUI4 (OLEAUT32.227)
3668 * Convert a VT_UI4 to a VT_CY.
3672 * pCyOut [O] Destination
3676 * Failure: E_INVALIDARG, if the source value is invalid
3677 * DISP_E_OVERFLOW, if the value will not fit in the destination
3678 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3680 HRESULT WINAPI
VarCyFromUI4(ULONG ulIn
, CY
* pCyOut
)
3682 pCyOut
->int64
= (ULONG64
)ulIn
* CY_MULTIPLIER
;
3686 /************************************************************************
3687 * VarCyFromDec (OLEAUT32.228)
3689 * Convert a VT_DECIMAL to a VT_CY.
3693 * pCyOut [O] Destination
3697 * Failure: E_INVALIDARG, if the source value is invalid
3698 * DISP_E_OVERFLOW, if the value will not fit in the destination
3699 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3701 HRESULT WINAPI
VarCyFromDec(DECIMAL
* pdecIn
, CY
* pCyOut
)
3706 hRet
= VarDecRound(pdecIn
, 4, &rounded
);
3708 if (SUCCEEDED(hRet
))
3712 if (DEC_HI32(&rounded
))
3713 return DISP_E_OVERFLOW
;
3715 /* Note: Without the casts this promotes to int64 which loses precision */
3716 d
= (double)DEC_LO64(&rounded
) / (double)CY_Divisors
[DEC_SCALE(&rounded
)];
3717 if (DEC_SIGN(&rounded
))
3719 return VarCyFromR8(d
, pCyOut
);
3724 /************************************************************************
3725 * VarCyFromI8 (OLEAUT32.366)
3727 * Convert a VT_I8 to a VT_CY.
3731 * pCyOut [O] Destination
3735 * Failure: E_INVALIDARG, if the source value is invalid
3736 * DISP_E_OVERFLOW, if the value will not fit in the destination
3737 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3739 HRESULT WINAPI
VarCyFromI8(LONG64 llIn
, CY
* pCyOut
)
3741 if (llIn
<= (I8_MIN
/CY_MULTIPLIER
) || llIn
>= (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3742 pCyOut
->int64
= llIn
* CY_MULTIPLIER
;
3746 /************************************************************************
3747 * VarCyFromUI8 (OLEAUT32.375)
3749 * Convert a VT_UI8 to a VT_CY.
3753 * pCyOut [O] Destination
3757 * Failure: E_INVALIDARG, if the source value is invalid
3758 * DISP_E_OVERFLOW, if the value will not fit in the destination
3759 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3761 HRESULT WINAPI
VarCyFromUI8(ULONG64 ullIn
, CY
* pCyOut
)
3763 if (ullIn
> (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3764 pCyOut
->int64
= ullIn
* CY_MULTIPLIER
;
3768 /************************************************************************
3769 * VarCyAdd (OLEAUT32.299)
3771 * Add one CY to another.
3775 * cyRight [I] Value to add
3776 * pCyOut [O] Destination
3780 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3782 HRESULT WINAPI
VarCyAdd(CY cyLeft
, CY cyRight
, CY
* pCyOut
)
3785 _VarR8FromCy(cyLeft
, &l
);
3786 _VarR8FromCy(cyRight
, &r
);
3788 return VarCyFromR8(l
, pCyOut
);
3791 /************************************************************************
3792 * VarCyMul (OLEAUT32.303)
3794 * Multiply one CY by another.
3798 * cyRight [I] Value to multiply by
3799 * pCyOut [O] Destination
3803 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3805 HRESULT WINAPI
VarCyMul(CY cyLeft
, CY cyRight
, CY
* pCyOut
)
3808 _VarR8FromCy(cyLeft
, &l
);
3809 _VarR8FromCy(cyRight
, &r
);
3811 return VarCyFromR8(l
, pCyOut
);
3814 /************************************************************************
3815 * VarCyMulI4 (OLEAUT32.304)
3817 * Multiply one CY by a VT_I4.
3821 * lRight [I] Value to multiply by
3822 * pCyOut [O] Destination
3826 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3828 HRESULT WINAPI
VarCyMulI4(CY cyLeft
, LONG lRight
, CY
* pCyOut
)
3832 _VarR8FromCy(cyLeft
, &d
);
3834 return VarCyFromR8(d
, pCyOut
);
3837 /************************************************************************
3838 * VarCySub (OLEAUT32.305)
3840 * Subtract one CY from another.
3844 * cyRight [I] Value to subtract
3845 * pCyOut [O] Destination
3849 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3851 HRESULT WINAPI
VarCySub(CY cyLeft
, CY cyRight
, CY
* pCyOut
)
3854 _VarR8FromCy(cyLeft
, &l
);
3855 _VarR8FromCy(cyRight
, &r
);
3857 return VarCyFromR8(l
, pCyOut
);
3860 /************************************************************************
3861 * VarCyAbs (OLEAUT32.306)
3863 * Convert a VT_CY into its absolute value.
3867 * pCyOut [O] Destination
3870 * Success: S_OK. pCyOut contains the absolute value.
3871 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3873 HRESULT WINAPI
VarCyAbs(CY cyIn
, CY
* pCyOut
)
3875 if (cyIn
.s
.Hi
== 0x80000000 && !cyIn
.s
.Lo
)
3876 return DISP_E_OVERFLOW
;
3878 pCyOut
->int64
= cyIn
.int64
< 0 ? -cyIn
.int64
: cyIn
.int64
;
3882 /************************************************************************
3883 * VarCyFix (OLEAUT32.307)
3885 * Return the integer part of a VT_CY.
3889 * pCyOut [O] Destination
3893 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3896 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3897 * negative numbers away from 0, while this function rounds them towards zero.
3899 HRESULT WINAPI
VarCyFix(CY cyIn
, CY
* pCyOut
)
3901 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3902 pCyOut
->int64
*= CY_MULTIPLIER
;
3906 /************************************************************************
3907 * VarCyInt (OLEAUT32.308)
3909 * Return the integer part of a VT_CY.
3913 * pCyOut [O] Destination
3917 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3920 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3921 * negative numbers towards 0, while this function rounds them away from zero.
3923 HRESULT WINAPI
VarCyInt(CY cyIn
, CY
* pCyOut
)
3925 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3926 pCyOut
->int64
*= CY_MULTIPLIER
;
3928 if (cyIn
.int64
< 0 && cyIn
.int64
% CY_MULTIPLIER
!= 0)
3930 pCyOut
->int64
-= CY_MULTIPLIER
;
3935 /************************************************************************
3936 * VarCyNeg (OLEAUT32.309)
3938 * Change the sign of a VT_CY.
3942 * pCyOut [O] Destination
3946 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3948 HRESULT WINAPI
VarCyNeg(CY cyIn
, CY
* pCyOut
)
3950 if (cyIn
.s
.Hi
== 0x80000000 && !cyIn
.s
.Lo
)
3951 return DISP_E_OVERFLOW
;
3953 pCyOut
->int64
= -cyIn
.int64
;
3957 /************************************************************************
3958 * VarCyRound (OLEAUT32.310)
3960 * Change the precision of a VT_CY.
3964 * cDecimals [I] New number of decimals to keep
3965 * pCyOut [O] Destination
3969 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3971 HRESULT WINAPI
VarCyRound(CY cyIn
, int cDecimals
, CY
* pCyOut
)
3974 return E_INVALIDARG
;
3978 /* Rounding to more precision than we have */
3984 double d
, div
= CY_Divisors
[cDecimals
];
3986 _VarR8FromCy(cyIn
, &d
);
3988 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
3989 d
= (double)pCyOut
->int64
/ div
* CY_MULTIPLIER_F
;
3990 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
3995 /************************************************************************
3996 * VarCyCmp (OLEAUT32.311)
3998 * Compare two VT_CY values.
4002 * cyRight [I] Value to compare
4005 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4006 * compare is less, equal or greater than source respectively.
4007 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4009 HRESULT WINAPI
VarCyCmp(CY cyLeft
, CY cyRight
)
4014 /* Subtract right from left, and compare the result to 0 */
4015 hRet
= VarCySub(cyLeft
, cyRight
, &result
);
4017 if (SUCCEEDED(hRet
))
4019 if (result
.int64
< 0)
4020 hRet
= (HRESULT
)VARCMP_LT
;
4021 else if (result
.int64
> 0)
4022 hRet
= (HRESULT
)VARCMP_GT
;
4024 hRet
= (HRESULT
)VARCMP_EQ
;
4029 /************************************************************************
4030 * VarCyCmpR8 (OLEAUT32.312)
4032 * Compare a VT_CY to a double
4035 * cyLeft [I] Currency Source
4036 * dblRight [I] double to compare to cyLeft
4039 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4040 * less than, equal to or greater than cyLeft respectively.
4041 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4043 HRESULT WINAPI
VarCyCmpR8(CY cyLeft
, double dblRight
)
4048 hRet
= VarCyFromR8(dblRight
, &cyRight
);
4050 if (SUCCEEDED(hRet
))
4051 hRet
= VarCyCmp(cyLeft
, cyRight
);
4056 /************************************************************************
4057 * VarCyMulI8 (OLEAUT32.329)
4059 * Multiply a VT_CY by a VT_I8.
4063 * llRight [I] Value to multiply by
4064 * pCyOut [O] Destination
4068 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4070 HRESULT WINAPI
VarCyMulI8(CY cyLeft
, LONG64 llRight
, CY
* pCyOut
)
4074 _VarR8FromCy(cyLeft
, &d
);
4075 d
= d
* (double)llRight
;
4076 return VarCyFromR8(d
, pCyOut
);
4082 /************************************************************************
4083 * VarDecFromUI1 (OLEAUT32.190)
4085 * Convert a VT_UI1 to a DECIMAL.
4089 * pDecOut [O] Destination
4094 HRESULT WINAPI
VarDecFromUI1(BYTE bIn
, DECIMAL
* pDecOut
)
4096 return VarDecFromUI4(bIn
, pDecOut
);
4099 /************************************************************************
4100 * VarDecFromI2 (OLEAUT32.191)
4102 * Convert a VT_I2 to a DECIMAL.
4106 * pDecOut [O] Destination
4111 HRESULT WINAPI
VarDecFromI2(SHORT sIn
, DECIMAL
* pDecOut
)
4113 return VarDecFromI4(sIn
, pDecOut
);
4116 /************************************************************************
4117 * VarDecFromI4 (OLEAUT32.192)
4119 * Convert a VT_I4 to a DECIMAL.
4123 * pDecOut [O] Destination
4128 HRESULT WINAPI
VarDecFromI4(LONG lIn
, DECIMAL
* pDecOut
)
4130 DEC_HI32(pDecOut
) = 0;
4131 DEC_MID32(pDecOut
) = 0;
4135 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4136 DEC_LO32(pDecOut
) = -lIn
;
4140 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4141 DEC_LO32(pDecOut
) = lIn
;
4146 /* internal representation of the value stored in a DECIMAL. The bytes are
4147 stored from LSB at index 0 to MSB at index 11
4149 typedef struct DECIMAL_internal
4151 DWORD bitsnum
[3]; /* 96 significant bits, unsigned */
4152 unsigned char scale
; /* number scaled * 10 ^ -(scale) */
4153 unsigned int sign
: 1; /* 0 - positive, 1 - negative */
4156 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
);
4157 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
);
4158 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
);
4159 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
);
4160 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
);
4161 static BOOL
VARIANT_int_iszero(const DWORD
* p
, unsigned int n
);
4163 /************************************************************************
4164 * VarDecFromR4 (OLEAUT32.193)
4166 * Convert a VT_R4 to a DECIMAL.
4170 * pDecOut [O] Destination
4175 HRESULT WINAPI
VarDecFromR4(FLOAT fltIn
, DECIMAL
* pDecOut
)
4180 hres
= VARIANT_DI_FromR4(fltIn
, &di
);
4181 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4185 /************************************************************************
4186 * VarDecFromR8 (OLEAUT32.194)
4188 * Convert a VT_R8 to a DECIMAL.
4192 * pDecOut [O] Destination
4197 HRESULT WINAPI
VarDecFromR8(double dblIn
, DECIMAL
* pDecOut
)
4202 hres
= VARIANT_DI_FromR8(dblIn
, &di
);
4203 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4207 /************************************************************************
4208 * VarDecFromDate (OLEAUT32.195)
4210 * Convert a VT_DATE to a DECIMAL.
4214 * pDecOut [O] Destination
4219 HRESULT WINAPI
VarDecFromDate(DATE dateIn
, DECIMAL
* pDecOut
)
4221 return VarDecFromR8(dateIn
, pDecOut
);
4224 /************************************************************************
4225 * VarDecFromCy (OLEAUT32.196)
4227 * Convert a VT_CY to a DECIMAL.
4231 * pDecOut [O] Destination
4236 HRESULT WINAPI
VarDecFromCy(CY cyIn
, DECIMAL
* pDecOut
)
4238 DEC_HI32(pDecOut
) = 0;
4240 /* Note: This assumes 2s complement integer representation */
4241 if (cyIn
.s
.Hi
& 0x80000000)
4243 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,4);
4244 DEC_LO64(pDecOut
) = -cyIn
.int64
;
4248 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,4);
4249 DEC_MID32(pDecOut
) = cyIn
.s
.Hi
;
4250 DEC_LO32(pDecOut
) = cyIn
.s
.Lo
;
4255 /************************************************************************
4256 * VarDecFromStr (OLEAUT32.197)
4258 * Convert a VT_BSTR to a DECIMAL.
4262 * lcid [I] LCID for the conversion
4263 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4264 * pDecOut [O] Destination
4268 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4270 HRESULT WINAPI
VarDecFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DECIMAL
* pDecOut
)
4272 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDecOut
, VT_DECIMAL
);
4275 /************************************************************************
4276 * VarDecFromDisp (OLEAUT32.198)
4278 * Convert a VT_DISPATCH to a DECIMAL.
4281 * pdispIn [I] Source
4282 * lcid [I] LCID for conversion
4283 * pDecOut [O] Destination
4287 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4289 HRESULT WINAPI
VarDecFromDisp(IDispatch
* pdispIn
, LCID lcid
, DECIMAL
* pDecOut
)
4291 return VARIANT_FromDisp(pdispIn
, lcid
, pDecOut
, VT_DECIMAL
, 0);
4294 /************************************************************************
4295 * VarDecFromBool (OLEAUT32.199)
4297 * Convert a VT_BOOL to a DECIMAL.
4301 * pDecOut [O] Destination
4307 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4309 HRESULT WINAPI
VarDecFromBool(VARIANT_BOOL bIn
, DECIMAL
* pDecOut
)
4311 DEC_HI32(pDecOut
) = 0;
4312 DEC_MID32(pDecOut
) = 0;
4315 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4316 DEC_LO32(pDecOut
) = 1;
4320 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4321 DEC_LO32(pDecOut
) = 0;
4326 /************************************************************************
4327 * VarDecFromI1 (OLEAUT32.241)
4329 * Convert a VT_I1 to a DECIMAL.
4333 * pDecOut [O] Destination
4338 HRESULT WINAPI
VarDecFromI1(signed char cIn
, DECIMAL
* pDecOut
)
4340 return VarDecFromI4(cIn
, pDecOut
);
4343 /************************************************************************
4344 * VarDecFromUI2 (OLEAUT32.242)
4346 * Convert a VT_UI2 to a DECIMAL.
4350 * pDecOut [O] Destination
4355 HRESULT WINAPI
VarDecFromUI2(USHORT usIn
, DECIMAL
* pDecOut
)
4357 return VarDecFromUI4(usIn
, pDecOut
);
4360 /************************************************************************
4361 * VarDecFromUI4 (OLEAUT32.243)
4363 * Convert a VT_UI4 to a DECIMAL.
4367 * pDecOut [O] Destination
4372 HRESULT WINAPI
VarDecFromUI4(ULONG ulIn
, DECIMAL
* pDecOut
)
4374 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4375 DEC_HI32(pDecOut
) = 0;
4376 DEC_MID32(pDecOut
) = 0;
4377 DEC_LO32(pDecOut
) = ulIn
;
4381 /************************************************************************
4382 * VarDecFromI8 (OLEAUT32.374)
4384 * Convert a VT_I8 to a DECIMAL.
4388 * pDecOut [O] Destination
4393 HRESULT WINAPI
VarDecFromI8(LONG64 llIn
, DECIMAL
* pDecOut
)
4395 PULARGE_INTEGER pLi
= (PULARGE_INTEGER
)&llIn
;
4397 DEC_HI32(pDecOut
) = 0;
4399 /* Note: This assumes 2s complement integer representation */
4400 if (pLi
->u
.HighPart
& 0x80000000)
4402 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4403 DEC_LO64(pDecOut
) = -pLi
->QuadPart
;
4407 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4408 DEC_MID32(pDecOut
) = pLi
->u
.HighPart
;
4409 DEC_LO32(pDecOut
) = pLi
->u
.LowPart
;
4414 /************************************************************************
4415 * VarDecFromUI8 (OLEAUT32.375)
4417 * Convert a VT_UI8 to a DECIMAL.
4421 * pDecOut [O] Destination
4426 HRESULT WINAPI
VarDecFromUI8(ULONG64 ullIn
, DECIMAL
* pDecOut
)
4428 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4429 DEC_HI32(pDecOut
) = 0;
4430 DEC_LO64(pDecOut
) = ullIn
;
4434 /* Make two DECIMALS the same scale; used by math functions below */
4435 static HRESULT
VARIANT_DecScale(const DECIMAL
** ppDecLeft
,
4436 const DECIMAL
** ppDecRight
,
4439 static DECIMAL scaleFactor
;
4440 unsigned char remainder
;
4445 if (DEC_SIGN(*ppDecLeft
) & ~DECIMAL_NEG
|| DEC_SIGN(*ppDecRight
) & ~DECIMAL_NEG
)
4446 return E_INVALIDARG
;
4448 DEC_LO32(&scaleFactor
) = 10;
4450 i
= scaleAmount
= DEC_SCALE(*ppDecLeft
) - DEC_SCALE(*ppDecRight
);
4453 return S_OK
; /* Same scale */
4455 if (scaleAmount
> 0)
4457 decTemp
= *(*ppDecRight
); /* Left is bigger - scale the right hand side */
4458 *ppDecRight
= &pDecOut
[0];
4462 decTemp
= *(*ppDecLeft
); /* Right is bigger - scale the left hand side */
4463 *ppDecLeft
= &pDecOut
[0];
4467 /* Multiply up the value to be scaled by the correct amount (if possible) */
4468 while (i
> 0 && SUCCEEDED(VarDecMul(&decTemp
, &scaleFactor
, &pDecOut
[0])))
4470 decTemp
= pDecOut
[0];
4476 DEC_SCALE(&pDecOut
[0]) += (scaleAmount
> 0) ? scaleAmount
: (-scaleAmount
);
4477 return S_OK
; /* Same scale */
4480 /* Scaling further not possible, reduce accuracy of other argument */
4481 pDecOut
[0] = decTemp
;
4482 if (scaleAmount
> 0)
4484 DEC_SCALE(&pDecOut
[0]) += scaleAmount
- i
;
4485 VARIANT_DIFromDec(*ppDecLeft
, &di
);
4486 *ppDecLeft
= &pDecOut
[1];
4490 DEC_SCALE(&pDecOut
[0]) += (-scaleAmount
) - i
;
4491 VARIANT_DIFromDec(*ppDecRight
, &di
);
4492 *ppDecRight
= &pDecOut
[1];
4497 while (i
-- > 0 && !VARIANT_int_iszero(di
.bitsnum
, ARRAY_SIZE(di
.bitsnum
)))
4499 remainder
= VARIANT_int_divbychar(di
.bitsnum
, ARRAY_SIZE(di
.bitsnum
), 10);
4500 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4503 /* round up the result - native oleaut32 does this */
4504 if (remainder
>= 5) {
4505 for (remainder
= 1, i
= 0; i
< ARRAY_SIZE(di
.bitsnum
) && remainder
; i
++) {
4506 ULONGLONG digit
= di
.bitsnum
[i
] + 1;
4507 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4508 di
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
4512 VARIANT_DecFromDI(&di
, &pDecOut
[1]);
4516 /* Add two unsigned 32 bit values with overflow */
4517 static ULONG
VARIANT_Add(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4519 ULARGE_INTEGER ul64
;
4521 ul64
.QuadPart
= (ULONG64
)ulLeft
+ (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4522 *pulHigh
= ul64
.u
.HighPart
;
4523 return ul64
.u
.LowPart
;
4526 /* Subtract two unsigned 32 bit values with underflow */
4527 static ULONG
VARIANT_Sub(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4529 BOOL invert
= FALSE
;
4530 ULARGE_INTEGER ul64
;
4532 ul64
.QuadPart
= (LONG64
)ulLeft
- (ULONG64
)ulRight
;
4533 if (ulLeft
< ulRight
)
4536 if (ul64
.QuadPart
> (ULONG64
)*pulHigh
)
4537 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4540 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4544 ul64
.u
.HighPart
= -ul64
.u
.HighPart
;
4546 *pulHigh
= ul64
.u
.HighPart
;
4547 return ul64
.u
.LowPart
;
4550 /* Multiply two unsigned 32 bit values with overflow */
4551 static ULONG
VARIANT_Mul(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4553 ULARGE_INTEGER ul64
;
4555 ul64
.QuadPart
= (ULONG64
)ulLeft
* (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4556 *pulHigh
= ul64
.u
.HighPart
;
4557 return ul64
.u
.LowPart
;
4560 /* Compare two decimals that have the same scale */
4561 static inline int VARIANT_DecCmp(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
)
4563 if ( DEC_HI32(pDecLeft
) < DEC_HI32(pDecRight
) ||
4564 (DEC_HI32(pDecLeft
) <= DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) < DEC_LO64(pDecRight
)))
4566 else if (DEC_HI32(pDecLeft
) == DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) == DEC_LO64(pDecRight
))
4571 /************************************************************************
4572 * VarDecAdd (OLEAUT32.177)
4574 * Add one DECIMAL to another.
4577 * pDecLeft [I] Source
4578 * pDecRight [I] Value to add
4579 * pDecOut [O] Destination
4583 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4585 HRESULT WINAPI
VarDecAdd(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
4590 hRet
= VARIANT_DecScale(&pDecLeft
, &pDecRight
, scaled
);
4592 if (SUCCEEDED(hRet
))
4594 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4596 BYTE sign
= DECIMAL_POS
;
4599 /* Correct for the sign of the result */
4600 if (DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4602 /* -x + -y : Negative */
4604 goto VarDecAdd_AsPositive
;
4606 else if (DEC_SIGN(pDecLeft
) && !DEC_SIGN(pDecRight
))
4608 cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4610 /* -x + y : Negative if x > y */
4614 VarDecAdd_AsNegative
:
4615 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4616 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4617 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4621 VarDecAdd_AsInvertedNegative
:
4622 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecRight
), DEC_LO32(pDecLeft
), &overflow
);
4623 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecRight
), DEC_MID32(pDecLeft
), &overflow
);
4624 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecRight
), DEC_HI32(pDecLeft
), &overflow
);
4627 else if (!DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4629 cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4631 /* x + -y : Negative if x <= y */
4635 goto VarDecAdd_AsInvertedNegative
;
4637 goto VarDecAdd_AsNegative
;
4641 /* x + y : Positive */
4642 VarDecAdd_AsPositive
:
4643 DEC_LO32(pDecOut
) = VARIANT_Add(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4644 DEC_MID32(pDecOut
) = VARIANT_Add(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4645 DEC_HI32(pDecOut
) = VARIANT_Add(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4649 return DISP_E_OVERFLOW
; /* overflowed */
4651 DEC_SCALE(pDecOut
) = DEC_SCALE(pDecLeft
);
4652 DEC_SIGN(pDecOut
) = sign
;
4657 /* translate from external DECIMAL format into an internal representation */
4658 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
)
4660 to
->scale
= DEC_SCALE(from
);
4661 to
->sign
= DEC_SIGN(from
) ? 1 : 0;
4663 to
->bitsnum
[0] = DEC_LO32(from
);
4664 to
->bitsnum
[1] = DEC_MID32(from
);
4665 to
->bitsnum
[2] = DEC_HI32(from
);
4668 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
)
4671 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_NEG
, from
->scale
);
4673 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_POS
, from
->scale
);
4676 DEC_LO32(to
) = from
->bitsnum
[0];
4677 DEC_MID32(to
) = from
->bitsnum
[1];
4678 DEC_HI32(to
) = from
->bitsnum
[2];
4681 /* clear an internal representation of a DECIMAL */
4682 static void VARIANT_DI_clear(VARIANT_DI
* i
)
4684 memset(i
, 0, sizeof(VARIANT_DI
));
4687 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4688 size is supported. The value in p is replaced by the quotient of the division, and
4689 the remainder is returned as a result. This routine is most often used with a divisor
4690 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4692 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
)
4697 } else if (divisor
== 1) {
4698 /* dividend remains unchanged */
4701 unsigned char remainder
= 0;
4702 ULONGLONG iTempDividend
;
4705 for (i
= n
- 1; i
>= 0 && !p
[i
]; i
--); /* skip leading zeros */
4706 for (; i
>= 0; i
--) {
4707 iTempDividend
= ((ULONGLONG
)remainder
<< 32) + p
[i
];
4708 remainder
= iTempDividend
% divisor
;
4709 p
[i
] = iTempDividend
/ divisor
;
4716 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4717 static BOOL
VARIANT_int_iszero(const DWORD
* p
, unsigned int n
)
4719 for (; n
> 0; n
--) if (*p
++ != 0) return FALSE
;
4723 /* multiply two DECIMALS, without changing either one, and place result in third
4724 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4725 digits when scale > 0 in order to fit an overflowing result. Final overflow
4728 static int VARIANT_DI_mul(const VARIANT_DI
* a
, const VARIANT_DI
* b
, VARIANT_DI
* result
)
4730 BOOL r_overflow
= FALSE
;
4732 signed int mulstart
;
4734 VARIANT_DI_clear(result
);
4735 result
->sign
= (a
->sign
^ b
->sign
) ? 1 : 0;
4737 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4738 of the result is formed by adding the scales of the operands.
4740 result
->scale
= a
->scale
+ b
->scale
;
4741 memset(running
, 0, sizeof(running
));
4743 /* count number of leading zero-bytes in operand A */
4744 for (mulstart
= ARRAY_SIZE(a
->bitsnum
) - 1; mulstart
>= 0 && !a
->bitsnum
[mulstart
]; mulstart
--);
4746 /* result is 0, because operand A is 0 */
4750 unsigned char remainder
= 0;
4753 /* perform actual multiplication */
4754 for (iA
= 0; iA
<= mulstart
; iA
++) {
4758 for (iOverflowMul
= 0, iB
= 0; iB
< ARRAY_SIZE(b
->bitsnum
); iB
++) {
4762 iRV
= VARIANT_Mul(b
->bitsnum
[iB
], a
->bitsnum
[iA
], &iOverflowMul
);
4765 running
[iR
] = VARIANT_Add(running
[iR
], 0, &iRV
);
4771 /* Too bad - native oleaut does not do this, so we should not either */
4773 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4774 This operation should not lose significant digits, and gives an
4775 opportunity to reduce the possibility of overflows in future
4776 operations issued by the application.
4778 while (result
->scale
> 0) {
4779 memcpy(quotient
, running
, sizeof(quotient
));
4780 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4781 if (remainder
> 0) break;
4782 memcpy(running
, quotient
, sizeof(quotient
));
4786 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4787 This operation *will* lose significant digits of the result because
4788 all the factors of 10 were consumed by the previous operation.
4790 while (result
->scale
> 0 && !VARIANT_int_iszero(running
+ ARRAY_SIZE(result
->bitsnum
),
4791 ARRAY_SIZE(running
) - ARRAY_SIZE(result
->bitsnum
))) {
4793 remainder
= VARIANT_int_divbychar(running
, ARRAY_SIZE(running
), 10);
4794 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4798 /* round up the result - native oleaut32 does this */
4799 if (remainder
>= 5) {
4801 for (remainder
= 1, i
= 0; i
< ARRAY_SIZE(running
) && remainder
; i
++) {
4802 ULONGLONG digit
= running
[i
] + 1;
4803 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4804 running
[i
] = digit
& 0xFFFFFFFF;
4808 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4809 and copy result bits into result structure
4811 r_overflow
= !VARIANT_int_iszero(running
+ ARRAY_SIZE(result
->bitsnum
),
4812 ARRAY_SIZE(running
) - ARRAY_SIZE(result
->bitsnum
));
4813 memcpy(result
->bitsnum
, running
, sizeof(result
->bitsnum
));
4818 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4819 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4820 success, FALSE if insufficient space in output buffer.
4822 static BOOL
VARIANT_DI_tostringW(const VARIANT_DI
* a
, WCHAR
* s
, unsigned int n
)
4824 BOOL overflow
= FALSE
;
4826 unsigned char remainder
;
4829 /* place negative sign */
4830 if (!VARIANT_int_iszero(a
->bitsnum
, ARRAY_SIZE(a
->bitsnum
)) && a
->sign
) {
4835 else overflow
= TRUE
;
4838 /* prepare initial 0 */
4843 } else overflow
= TRUE
;
4847 memcpy(quotient
, a
->bitsnum
, sizeof(a
->bitsnum
));
4848 while (!overflow
&& !VARIANT_int_iszero(quotient
, ARRAY_SIZE(quotient
))) {
4849 remainder
= VARIANT_int_divbychar(quotient
, ARRAY_SIZE(quotient
), 10);
4853 s
[i
++] = '0' + remainder
;
4858 if (!overflow
&& !VARIANT_int_iszero(a
->bitsnum
, ARRAY_SIZE(a
->bitsnum
))) {
4860 /* reverse order of digits */
4861 WCHAR
* x
= s
; WCHAR
* y
= s
+ i
- 1;
4868 /* check for decimal point. "i" now has string length */
4869 if (i
<= a
->scale
) {
4870 unsigned int numzeroes
= a
->scale
+ 1 - i
;
4871 if (i
+ 1 + numzeroes
>= n
) {
4874 memmove(s
+ numzeroes
, s
, (i
+ 1) * sizeof(WCHAR
));
4876 while (numzeroes
> 0) {
4877 s
[--numzeroes
] = '0';
4882 /* place decimal point */
4884 unsigned int periodpos
= i
- a
->scale
;
4888 memmove(s
+ periodpos
+ 1, s
+ periodpos
, (i
+ 1 - periodpos
) * sizeof(WCHAR
));
4889 s
[periodpos
] = '.'; i
++;
4891 /* remove extra zeros at the end, if any */
4892 while (s
[i
- 1] == '0') s
[--i
] = '\0';
4893 if (s
[i
- 1] == '.') s
[--i
] = '\0';
4901 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4902 static void VARIANT_int_shiftleft(DWORD
* p
, unsigned int n
, unsigned int shift
)
4907 /* shift whole DWORDs to the left */
4910 memmove(p
+ 1, p
, (n
- 1) * sizeof(DWORD
));
4911 *p
= 0; shift
-= 32;
4914 /* shift remainder (1..31 bits) */
4916 if (shift
> 0) for (i
= 0; i
< n
; i
++)
4919 b
= p
[i
] >> (32 - shift
);
4920 p
[i
] = (p
[i
] << shift
) | shifted
;
4925 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4926 Value at v is incremented by the value at p. Any size is supported, provided
4927 that v is not shorter than p. Any unapplied carry is returned as a result.
4929 static unsigned char VARIANT_int_add(DWORD
* v
, unsigned int nv
, const DWORD
* p
,
4932 unsigned char carry
= 0;
4938 for (i
= 0; i
< np
; i
++) {
4939 sum
= (ULONGLONG
)v
[i
]
4942 v
[i
] = sum
& 0xffffffff;
4945 for (; i
< nv
&& carry
; i
++) {
4946 sum
= (ULONGLONG
)v
[i
]
4948 v
[i
] = sum
& 0xffffffff;
4955 /* perform integral division with operand p as dividend. Parameter n indicates
4956 number of available DWORDs in divisor p, but available space in p must be
4957 actually at least 2 * n DWORDs, because the remainder of the integral
4958 division is built in the next n DWORDs past the start of the quotient. This
4959 routine replaces the dividend in p with the quotient, and appends n
4960 additional DWORDs for the remainder.
4962 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4963 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4964 source code to the VLI (Very Large Integer) division operator. This algorithm
4965 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4966 variably-scaled integers such as the MS DECIMAL representation.
4968 static void VARIANT_int_div(DWORD
* p
, unsigned int n
, const DWORD
* divisor
,
4973 DWORD
* negdivisor
= tempsub
+ n
;
4975 /* build 2s-complement of divisor */
4976 for (i
= 0; i
< n
; i
++) negdivisor
[i
] = (i
< dn
) ? ~divisor
[i
] : 0xFFFFFFFF;
4978 VARIANT_int_add(negdivisor
, n
, p
+ n
, 1);
4979 memset(p
+ n
, 0, n
* sizeof(DWORD
));
4981 /* skip all leading zero DWORDs in quotient */
4982 for (i
= 0; i
< n
&& !p
[n
- 1]; i
++) VARIANT_int_shiftleft(p
, n
, 32);
4983 /* i is now number of DWORDs left to process */
4984 for (i
<<= 5; i
< (n
<< 5); i
++) {
4985 VARIANT_int_shiftleft(p
, n
<< 1, 1); /* shl quotient+remainder */
4987 /* trial subtraction */
4988 memcpy(tempsub
, p
+ n
, n
* sizeof(DWORD
));
4989 VARIANT_int_add(tempsub
, n
, negdivisor
, n
);
4991 /* check whether result of subtraction was negative */
4992 if ((tempsub
[n
- 1] & 0x80000000) == 0) {
4993 memcpy(p
+ n
, tempsub
, n
* sizeof(DWORD
));
4999 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
5000 static unsigned char VARIANT_int_mulbychar(DWORD
* p
, unsigned int n
, unsigned char m
)
5005 for (iOverflowMul
= 0, i
= 0; i
< n
; i
++)
5006 p
[i
] = VARIANT_Mul(p
[i
], m
, &iOverflowMul
);
5007 return (unsigned char)iOverflowMul
;
5010 /* increment value in A by the value indicated in B, with scale adjusting.
5011 Modifies parameters by adjusting scales. Returns 0 if addition was
5012 successful, nonzero if a parameter underflowed before it could be
5013 successfully used in the addition.
5015 static int VARIANT_int_addlossy(
5016 DWORD
* a
, int * ascale
, unsigned int an
,
5017 DWORD
* b
, int * bscale
, unsigned int bn
)
5021 if (VARIANT_int_iszero(a
, an
)) {
5022 /* if A is zero, copy B into A, after removing digits */
5023 while (bn
> an
&& !VARIANT_int_iszero(b
+ an
, bn
- an
)) {
5024 VARIANT_int_divbychar(b
, bn
, 10);
5027 memcpy(a
, b
, an
* sizeof(DWORD
));
5029 } else if (!VARIANT_int_iszero(b
, bn
)) {
5030 unsigned int tn
= an
+ 1;
5033 if (bn
+ 1 > tn
) tn
= bn
+ 1;
5034 if (*ascale
!= *bscale
) {
5035 /* first (optimistic) try - try to scale down the one with the bigger
5036 scale, while this number is divisible by 10 */
5037 DWORD
* digitchosen
;
5038 unsigned int nchosen
;
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 /* divide by 10 until target scale is reached */
5057 while (*scalechosen
> targetscale
) {
5058 unsigned char remainder
= VARIANT_int_divbychar(t
, tn
, 10);
5061 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5066 if (*ascale
!= *bscale
) {
5067 DWORD
* digitchosen
;
5068 unsigned int nchosen
;
5072 /* try to scale up the one with the smaller scale */
5073 if (*ascale
> *bscale
) {
5074 targetscale
= *ascale
;
5075 scalechosen
= bscale
;
5079 targetscale
= *bscale
;
5080 scalechosen
= ascale
;
5084 memset(t
, 0, tn
* sizeof(DWORD
));
5085 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5087 /* multiply by 10 until target scale is reached, or
5088 significant bytes overflow the number
5090 while (*scalechosen
< targetscale
&& t
[nchosen
] == 0) {
5091 VARIANT_int_mulbychar(t
, tn
, 10);
5092 if (t
[nchosen
] == 0) {
5093 /* still does not overflow */
5095 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5100 if (*ascale
!= *bscale
) {
5101 /* still different? try to scale down the one with the bigger scale
5102 (this *will* lose significant digits) */
5103 DWORD
* digitchosen
;
5104 unsigned int nchosen
;
5108 if (*ascale
< *bscale
) {
5109 targetscale
= *ascale
;
5110 scalechosen
= bscale
;
5114 targetscale
= *bscale
;
5115 scalechosen
= ascale
;
5119 memset(t
, 0, tn
* sizeof(DWORD
));
5120 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5122 /* divide by 10 until target scale is reached */
5123 while (*scalechosen
> targetscale
) {
5124 VARIANT_int_divbychar(t
, tn
, 10);
5126 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5130 /* check whether any of the operands still has significant digits
5133 if (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
)) {
5136 /* at this step, both numbers have the same scale and can be added
5137 as integers. However, the result might not fit in A, so further
5138 scaling down might be necessary.
5140 while (!underflow
) {
5141 memset(t
, 0, tn
* sizeof(DWORD
));
5142 memcpy(t
, a
, an
* sizeof(DWORD
));
5144 VARIANT_int_add(t
, tn
, b
, bn
);
5145 if (VARIANT_int_iszero(t
+ an
, tn
- an
)) {
5146 /* addition was successful */
5147 memcpy(a
, t
, an
* sizeof(DWORD
));
5150 /* addition overflowed - remove significant digits
5151 from both operands and try again */
5152 VARIANT_int_divbychar(a
, an
, 10); (*ascale
)--;
5153 VARIANT_int_divbychar(b
, bn
, 10); (*bscale
)--;
5154 /* check whether any operand keeps significant digits after
5155 scaledown (underflow case 2)
5157 underflow
= (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
));
5165 /* perform complete DECIMAL division in the internal representation. Returns
5166 0 if the division was completed (even if quotient is set to 0), or nonzero
5167 in case of quotient overflow.
5169 static HRESULT
VARIANT_DI_div(const VARIANT_DI
* dividend
, const VARIANT_DI
* divisor
,
5170 VARIANT_DI
* quotient
, BOOL round_remainder
)
5172 HRESULT r_overflow
= S_OK
;
5174 if (VARIANT_int_iszero(divisor
->bitsnum
, ARRAY_SIZE(divisor
->bitsnum
))) {
5176 r_overflow
= DISP_E_DIVBYZERO
;
5177 } else if (VARIANT_int_iszero(dividend
->bitsnum
, ARRAY_SIZE(dividend
->bitsnum
))) {
5178 VARIANT_DI_clear(quotient
);
5180 int quotientscale
, remainderscale
, tempquotientscale
;
5181 DWORD remainderplusquotient
[8];
5184 quotientscale
= remainderscale
= (int)dividend
->scale
- (int)divisor
->scale
;
5185 tempquotientscale
= quotientscale
;
5186 VARIANT_DI_clear(quotient
);
5187 quotient
->sign
= (dividend
->sign
^ divisor
->sign
) ? 1 : 0;
5189 /* The following strategy is used for division
5190 1) if there was a nonzero remainder from previous iteration, use it as
5191 dividend for this iteration, else (for first iteration) use intended
5193 2) perform integer division in temporary buffer, develop quotient in
5194 low-order part, remainder in high-order part
5195 3) add quotient from step 2 to final result, with possible loss of
5197 4) multiply integer part of remainder by 10, while incrementing the
5198 scale of the remainder. This operation preserves the intended value
5200 5) loop to step 1 until one of the following is true:
5201 a) remainder is zero (exact division achieved)
5202 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5204 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5205 memcpy(remainderplusquotient
, dividend
->bitsnum
, sizeof(dividend
->bitsnum
));
5207 VARIANT_int_div(remainderplusquotient
, 4, divisor
->bitsnum
, ARRAY_SIZE(divisor
->bitsnum
));
5208 underflow
= VARIANT_int_addlossy( quotient
->bitsnum
, "ientscale
,
5209 ARRAY_SIZE(quotient
->bitsnum
), remainderplusquotient
, &tempquotientscale
, 4);
5210 if (round_remainder
) {
5211 if(remainderplusquotient
[4] >= 5){
5213 unsigned char remainder
= 1;
5214 for (i
= 0; i
< ARRAY_SIZE(quotient
->bitsnum
) && remainder
; i
++) {
5215 ULONGLONG digit
= quotient
->bitsnum
[i
] + 1;
5216 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5217 quotient
->bitsnum
[i
] = digit
& 0xFFFFFFFF;
5220 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5222 VARIANT_int_mulbychar(remainderplusquotient
+ 4, 4, 10);
5223 memcpy(remainderplusquotient
, remainderplusquotient
+ 4, 4 * sizeof(DWORD
));
5225 tempquotientscale
= ++remainderscale
;
5226 } while (!underflow
&& !VARIANT_int_iszero(remainderplusquotient
+ 4, 4));
5228 /* quotient scale might now be negative (extremely big number). If, so, try
5229 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5230 until scale is 0. If this cannot be done, it is a real overflow.
5232 while (r_overflow
== S_OK
&& quotientscale
< 0) {
5233 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5234 memcpy(remainderplusquotient
, quotient
->bitsnum
, sizeof(quotient
->bitsnum
));
5235 VARIANT_int_mulbychar(remainderplusquotient
, ARRAY_SIZE(remainderplusquotient
), 10);
5236 if (VARIANT_int_iszero(remainderplusquotient
+ ARRAY_SIZE(quotient
->bitsnum
),
5237 ARRAY_SIZE(remainderplusquotient
) - ARRAY_SIZE(quotient
->bitsnum
))) {
5239 memcpy(quotient
->bitsnum
, remainderplusquotient
, sizeof(quotient
->bitsnum
));
5240 } else r_overflow
= DISP_E_OVERFLOW
;
5242 if (r_overflow
== S_OK
) {
5243 if (quotientscale
<= 255) quotient
->scale
= quotientscale
;
5244 else VARIANT_DI_clear(quotient
);
5250 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5251 with an undefined scale, which will be assigned to (if possible). It also
5252 receives an exponent of 2. This procedure will then manipulate the mantissa
5253 and calculate a corresponding scale, so that the exponent2 value is assimilated
5254 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5255 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5257 static HRESULT
VARIANT_DI_normalize(VARIANT_DI
* val
, int exponent2
, BOOL isDouble
)
5259 HRESULT hres
= S_OK
;
5260 int exponent5
, exponent10
;
5262 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5263 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5264 exponent10 might be used to set the VARIANT_DI scale directly. However,
5265 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5266 exponent5
= -exponent2
;
5267 exponent10
= exponent2
;
5269 /* Handle exponent5 > 0 */
5270 while (exponent5
> 0) {
5274 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5275 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5276 somehow the mantissa should be divided by 2. */
5277 if ((val
->bitsnum
[0] & 1) == 0) {
5278 /* The mantissa is divisible by 2. Therefore the division can be done
5279 without losing significant digits. */
5280 exponent10
++; exponent5
--;
5283 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5284 val
->bitsnum
[2] >>= 1;
5285 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5286 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5287 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5289 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5290 be multiplied by 5, unless the multiplication overflows. */
5291 DWORD temp_bitsnum
[3];
5295 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5296 if (0 == VARIANT_int_mulbychar(temp_bitsnum
, 3, 5)) {
5297 /* Multiplication succeeded without overflow, so copy result back
5299 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5301 /* Mask out 3 extraneous bits introduced by the multiply */
5303 /* Multiplication by 5 overflows. The mantissa should be divided
5304 by 2, and therefore will lose significant digits. */
5308 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5309 val
->bitsnum
[2] >>= 1;
5310 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5311 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5312 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5317 /* Handle exponent5 < 0 */
5318 while (exponent5
< 0) {
5319 /* In order to divide the value represented by the VARIANT_DI by 5, it
5320 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5321 and the mantissa should be multiplied by 2 */
5322 if ((val
->bitsnum
[2] & 0x80000000) == 0) {
5323 /* The mantissa can withstand a shift-left without overflowing */
5324 exponent10
--; exponent5
++;
5325 VARIANT_int_shiftleft(val
->bitsnum
, 3, 1);
5327 /* The mantissa would overflow if shifted. Therefore it should be
5328 directly divided by 5. This will lose significant digits, unless
5329 by chance the mantissa happens to be divisible by 5 */
5331 VARIANT_int_divbychar(val
->bitsnum
, 3, 5);
5335 /* At this point, the mantissa has assimilated the exponent5, but the
5336 exponent10 might not be suitable for assignment. The exponent10 must be
5337 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5338 down appropriately. */
5339 while (hres
== S_OK
&& exponent10
> 0) {
5340 /* In order to bring exponent10 down to 0, the mantissa should be
5341 multiplied by 10 to compensate. If the exponent10 is too big, this
5342 will cause the mantissa to overflow. */
5343 if (0 == VARIANT_int_mulbychar(val
->bitsnum
, 3, 10)) {
5346 hres
= DISP_E_OVERFLOW
;
5349 while (exponent10
< -DEC_MAX_SCALE
) {
5351 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5352 be divided by 10 to compensate. If the exponent10 is too small, this
5353 will cause the mantissa to underflow and become 0 */
5354 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5356 if (VARIANT_int_iszero(val
->bitsnum
, 3)) {
5357 /* Underflow, unable to keep dividing */
5359 } else if (rem10
>= 5) {
5361 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5364 /* This step is required in order to remove excess bits of precision from the
5365 end of the bit representation, down to the precision guaranteed by the
5366 floating point number. */
5368 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || (val
->bitsnum
[1] & 0xFFE00000) != 0)) {
5371 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5375 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5379 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || val
->bitsnum
[1] != 0 ||
5380 (val
->bitsnum
[2] == 0 && val
->bitsnum
[1] == 0 && (val
->bitsnum
[0] & 0xFF000000) != 0))) {
5383 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5387 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5391 /* Remove multiples of 10 from the representation */
5392 while (exponent10
< 0) {
5393 DWORD temp_bitsnum
[3];
5395 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5396 if (0 == VARIANT_int_divbychar(temp_bitsnum
, 3, 10)) {
5398 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5402 /* Scale assignment */
5403 if (hres
== S_OK
) val
->scale
= -exponent10
;
5412 unsigned int m
: 23;
5413 unsigned int exp_bias
: 8;
5414 unsigned int sign
: 1;
5419 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5420 intermediate string step. */
5421 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
)
5423 HRESULT hres
= S_OK
;
5428 /* Detect special cases */
5429 if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0) {
5430 /* Floating-point zero */
5431 VARIANT_DI_clear(dest
);
5432 } else if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0xFF) {
5433 /* Floating-point infinity */
5434 hres
= DISP_E_OVERFLOW
;
5435 } else if (fx
.i
.exp_bias
== 0xFF) {
5436 /* Floating-point NaN */
5437 hres
= DISP_E_BADVARTYPE
;
5440 VARIANT_DI_clear(dest
);
5442 exponent2
= fx
.i
.exp_bias
- 127; /* Get unbiased exponent */
5443 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5445 /* Copy significant bits to VARIANT_DI mantissa */
5446 dest
->bitsnum
[0] = fx
.i
.m
;
5447 dest
->bitsnum
[0] &= 0x007FFFFF;
5448 if (fx
.i
.exp_bias
== 0) {
5449 /* Denormalized number - correct exponent */
5452 /* Add hidden bit to mantissa */
5453 dest
->bitsnum
[0] |= 0x00800000;
5456 /* The act of copying a FP mantissa as integer bits is equivalent to
5457 shifting left the mantissa 23 bits. The exponent2 is reduced to
5461 hres
= VARIANT_DI_normalize(dest
, exponent2
, FALSE
);
5471 unsigned int m_lo
: 32; /* 52 bits of precision */
5472 unsigned int m_hi
: 20;
5473 unsigned int exp_bias
: 11; /* bias == 1023 */
5474 unsigned int sign
: 1;
5479 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5480 intermediate string step. */
5481 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
)
5483 HRESULT hres
= S_OK
;
5488 /* Detect special cases */
5489 if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0) {
5490 /* Floating-point zero */
5491 VARIANT_DI_clear(dest
);
5492 } else if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0x7FF) {
5493 /* Floating-point infinity */
5494 hres
= DISP_E_OVERFLOW
;
5495 } else if (fx
.i
.exp_bias
== 0x7FF) {
5496 /* Floating-point NaN */
5497 hres
= DISP_E_BADVARTYPE
;
5500 VARIANT_DI_clear(dest
);
5502 exponent2
= fx
.i
.exp_bias
- 1023; /* Get unbiased exponent */
5503 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5505 /* Copy significant bits to VARIANT_DI mantissa */
5506 dest
->bitsnum
[0] = fx
.i
.m_lo
;
5507 dest
->bitsnum
[1] = fx
.i
.m_hi
;
5508 dest
->bitsnum
[1] &= 0x000FFFFF;
5509 if (fx
.i
.exp_bias
== 0) {
5510 /* Denormalized number - correct exponent */
5513 /* Add hidden bit to mantissa */
5514 dest
->bitsnum
[1] |= 0x00100000;
5517 /* The act of copying a FP mantissa as integer bits is equivalent to
5518 shifting left the mantissa 52 bits. The exponent2 is reduced to
5522 hres
= VARIANT_DI_normalize(dest
, exponent2
, TRUE
);
5528 static HRESULT
VARIANT_do_division(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
, DECIMAL
*pDecOut
,
5531 HRESULT hRet
= S_OK
;
5532 VARIANT_DI di_left
, di_right
, di_result
;
5535 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5536 VARIANT_DIFromDec(pDecRight
, &di_right
);
5537 divresult
= VARIANT_DI_div(&di_left
, &di_right
, &di_result
, round
);
5538 if (divresult
!= S_OK
)
5540 /* division actually overflowed */
5547 if (di_result
.scale
> DEC_MAX_SCALE
)
5549 unsigned char remainder
= 0;
5551 /* division underflowed. In order to comply with the MSDN
5552 specifications for DECIMAL ranges, some significant digits
5555 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5557 while (di_result
.scale
> DEC_MAX_SCALE
&&
5558 !VARIANT_int_iszero(di_result
.bitsnum
, ARRAY_SIZE(di_result
.bitsnum
)))
5560 remainder
= VARIANT_int_divbychar(di_result
.bitsnum
, ARRAY_SIZE(di_result
.bitsnum
), 10);
5563 if (di_result
.scale
> DEC_MAX_SCALE
)
5565 WARN("result underflowed, setting to 0\n");
5566 di_result
.scale
= 0;
5569 else if (remainder
>= 5) /* round up result - native oleaut32 does this */
5572 for (remainder
= 1, i
= 0; i
< ARRAY_SIZE(di_result
.bitsnum
) && remainder
; i
++) {
5573 ULONGLONG digit
= di_result
.bitsnum
[i
] + 1;
5574 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5575 di_result
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
5579 VARIANT_DecFromDI(&di_result
, pDecOut
);
5584 /************************************************************************
5585 * VarDecDiv (OLEAUT32.178)
5587 * Divide one DECIMAL by another.
5590 * pDecLeft [I] Source
5591 * pDecRight [I] Value to divide by
5592 * pDecOut [O] Destination
5596 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5598 HRESULT WINAPI
VarDecDiv(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5600 if (!pDecLeft
|| !pDecRight
|| !pDecOut
) return E_INVALIDARG
;
5602 return VARIANT_do_division(pDecLeft
, pDecRight
, pDecOut
, FALSE
);
5605 /************************************************************************
5606 * VarDecMul (OLEAUT32.179)
5608 * Multiply one DECIMAL by another.
5611 * pDecLeft [I] Source
5612 * pDecRight [I] Value to multiply by
5613 * pDecOut [O] Destination
5617 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5619 HRESULT WINAPI
VarDecMul(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5621 HRESULT hRet
= S_OK
;
5622 VARIANT_DI di_left
, di_right
, di_result
;
5625 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5626 VARIANT_DIFromDec(pDecRight
, &di_right
);
5627 mulresult
= VARIANT_DI_mul(&di_left
, &di_right
, &di_result
);
5630 /* multiplication actually overflowed */
5631 hRet
= DISP_E_OVERFLOW
;
5635 if (di_result
.scale
> DEC_MAX_SCALE
)
5637 /* multiplication underflowed. In order to comply with the MSDN
5638 specifications for DECIMAL ranges, some significant digits
5641 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5643 while (di_result
.scale
> DEC_MAX_SCALE
&&
5644 !VARIANT_int_iszero(di_result
.bitsnum
, ARRAY_SIZE(di_result
.bitsnum
)))
5646 VARIANT_int_divbychar(di_result
.bitsnum
, ARRAY_SIZE(di_result
.bitsnum
), 10);
5649 if (di_result
.scale
> DEC_MAX_SCALE
)
5651 WARN("result underflowed, setting to 0\n");
5652 di_result
.scale
= 0;
5656 VARIANT_DecFromDI(&di_result
, pDecOut
);
5661 /************************************************************************
5662 * VarDecSub (OLEAUT32.181)
5664 * Subtract one DECIMAL from another.
5667 * pDecLeft [I] Source
5668 * pDecRight [I] DECIMAL to subtract from pDecLeft
5669 * pDecOut [O] Destination
5672 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5674 HRESULT WINAPI
VarDecSub(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5678 /* Implement as addition of the negative */
5679 VarDecNeg(pDecRight
, &decRight
);
5680 return VarDecAdd(pDecLeft
, &decRight
, pDecOut
);
5683 /************************************************************************
5684 * VarDecAbs (OLEAUT32.182)
5686 * Convert a DECIMAL into its absolute value.
5690 * pDecOut [O] Destination
5693 * S_OK. This function does not fail.
5695 HRESULT WINAPI
VarDecAbs(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5698 DEC_SIGN(pDecOut
) &= ~DECIMAL_NEG
;
5702 /************************************************************************
5703 * VarDecFix (OLEAUT32.187)
5705 * Return the integer portion of a DECIMAL.
5709 * pDecOut [O] Destination
5713 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5716 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5717 * negative numbers away from 0, while this function rounds them towards zero.
5719 HRESULT WINAPI
VarDecFix(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5724 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5725 return E_INVALIDARG
;
5727 if (!DEC_SCALE(pDecIn
))
5729 *pDecOut
= *pDecIn
; /* Already an integer */
5733 hr
= VarR8FromDec(pDecIn
, &dbl
);
5734 if (SUCCEEDED(hr
)) {
5735 LONGLONG rounded
= dbl
;
5737 hr
= VarDecFromI8(rounded
, pDecOut
);
5742 /************************************************************************
5743 * VarDecInt (OLEAUT32.188)
5745 * Return the integer portion of a DECIMAL.
5749 * pDecOut [O] Destination
5753 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5756 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5757 * negative numbers towards 0, while this function rounds them away from zero.
5759 HRESULT WINAPI
VarDecInt(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5764 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5765 return E_INVALIDARG
;
5767 if (!(DEC_SIGN(pDecIn
) & DECIMAL_NEG
) || !DEC_SCALE(pDecIn
))
5768 return VarDecFix(pDecIn
, pDecOut
); /* The same, if +ve or no fractionals */
5770 hr
= VarR8FromDec(pDecIn
, &dbl
);
5771 if (SUCCEEDED(hr
)) {
5772 LONGLONG rounded
= dbl
>= 0.0 ? dbl
+ 0.5 : dbl
- 0.5;
5774 hr
= VarDecFromI8(rounded
, pDecOut
);
5779 /************************************************************************
5780 * VarDecNeg (OLEAUT32.189)
5782 * Change the sign of a DECIMAL.
5786 * pDecOut [O] Destination
5789 * S_OK. This function does not fail.
5791 HRESULT WINAPI
VarDecNeg(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5794 DEC_SIGN(pDecOut
) ^= DECIMAL_NEG
;
5798 /************************************************************************
5799 * VarDecRound (OLEAUT32.203)
5801 * Change the precision of a DECIMAL.
5805 * cDecimals [I] New number of decimals to keep
5806 * pDecOut [O] Destination
5809 * Success: S_OK. pDecOut contains the rounded value.
5810 * Failure: E_INVALIDARG if any argument is invalid.
5812 HRESULT WINAPI
VarDecRound(const DECIMAL
* pDecIn
, int cDecimals
, DECIMAL
* pDecOut
)
5814 DECIMAL divisor
, tmp
;
5818 if (cDecimals
< 0 || (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
) || DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
)
5819 return E_INVALIDARG
;
5821 if (cDecimals
>= DEC_SCALE(pDecIn
))
5823 *pDecOut
= *pDecIn
; /* More precision than we have */
5827 /* truncate significant digits and rescale */
5828 memset(&divisor
, 0, sizeof(divisor
));
5829 DEC_LO64(&divisor
) = 1;
5831 memset(&tmp
, 0, sizeof(tmp
));
5832 DEC_LO64(&tmp
) = 10;
5833 for (i
= 0; i
< DEC_SCALE(pDecIn
) - cDecimals
; ++i
)
5835 hr
= VarDecMul(&divisor
, &tmp
, &divisor
);
5840 hr
= VARIANT_do_division(pDecIn
, &divisor
, pDecOut
, TRUE
);
5844 DEC_SCALE(pDecOut
) = cDecimals
;
5849 /************************************************************************
5850 * VarDecCmp (OLEAUT32.204)
5852 * Compare two DECIMAL values.
5855 * pDecLeft [I] Source
5856 * pDecRight [I] Value to compare
5859 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5860 * is less than, equal to or greater than pDecRight respectively.
5861 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5863 HRESULT WINAPI
VarDecCmp(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
)
5868 if (!pDecLeft
|| !pDecRight
)
5871 if ((!(DEC_SIGN(pDecLeft
) & DECIMAL_NEG
)) && (DEC_SIGN(pDecRight
) & DECIMAL_NEG
) &&
5872 (DEC_HI32(pDecLeft
) | DEC_MID32(pDecLeft
) | DEC_LO32(pDecLeft
)))
5874 else if ((DEC_SIGN(pDecLeft
) & DECIMAL_NEG
) && (!(DEC_SIGN(pDecRight
) & DECIMAL_NEG
)) &&
5875 (DEC_HI32(pDecLeft
) | DEC_MID32(pDecLeft
) | DEC_LO32(pDecLeft
)))
5878 /* Subtract right from left, and compare the result to 0 */
5879 hRet
= VarDecSub(pDecLeft
, pDecRight
, &result
);
5881 if (SUCCEEDED(hRet
))
5883 int non_zero
= DEC_HI32(&result
) | DEC_MID32(&result
) | DEC_LO32(&result
);
5885 if ((DEC_SIGN(&result
) & DECIMAL_NEG
) && non_zero
)
5886 hRet
= (HRESULT
)VARCMP_LT
;
5888 hRet
= (HRESULT
)VARCMP_GT
;
5890 hRet
= (HRESULT
)VARCMP_EQ
;
5895 /************************************************************************
5896 * VarDecCmpR8 (OLEAUT32.298)
5898 * Compare a DECIMAL to a double
5901 * pDecLeft [I] DECIMAL Source
5902 * dblRight [I] double to compare to pDecLeft
5905 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5906 * is less than, equal to or greater than pDecLeft respectively.
5907 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5909 HRESULT WINAPI
VarDecCmpR8(const DECIMAL
* pDecLeft
, double dblRight
)
5914 hRet
= VarDecFromR8(dblRight
, &decRight
);
5916 if (SUCCEEDED(hRet
))
5917 hRet
= VarDecCmp(pDecLeft
, &decRight
);
5925 /************************************************************************
5926 * VarBoolFromUI1 (OLEAUT32.118)
5928 * Convert a VT_UI1 to a VT_BOOL.
5932 * pBoolOut [O] Destination
5937 HRESULT WINAPI
VarBoolFromUI1(BYTE bIn
, VARIANT_BOOL
*pBoolOut
)
5939 *pBoolOut
= bIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5943 /************************************************************************
5944 * VarBoolFromI2 (OLEAUT32.119)
5946 * Convert a VT_I2 to a VT_BOOL.
5950 * pBoolOut [O] Destination
5955 HRESULT WINAPI
VarBoolFromI2(SHORT sIn
, VARIANT_BOOL
*pBoolOut
)
5957 *pBoolOut
= sIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5961 /************************************************************************
5962 * VarBoolFromI4 (OLEAUT32.120)
5964 * Convert a VT_I4 to a VT_BOOL.
5968 * pBoolOut [O] Destination
5973 HRESULT WINAPI
VarBoolFromI4(LONG lIn
, VARIANT_BOOL
*pBoolOut
)
5975 *pBoolOut
= lIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5979 /************************************************************************
5980 * VarBoolFromR4 (OLEAUT32.121)
5982 * Convert a VT_R4 to a VT_BOOL.
5986 * pBoolOut [O] Destination
5991 HRESULT WINAPI
VarBoolFromR4(FLOAT fltIn
, VARIANT_BOOL
*pBoolOut
)
5993 *pBoolOut
= fltIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5997 /************************************************************************
5998 * VarBoolFromR8 (OLEAUT32.122)
6000 * Convert a VT_R8 to a VT_BOOL.
6004 * pBoolOut [O] Destination
6009 HRESULT WINAPI
VarBoolFromR8(double dblIn
, VARIANT_BOOL
*pBoolOut
)
6011 *pBoolOut
= dblIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6015 /************************************************************************
6016 * VarBoolFromDate (OLEAUT32.123)
6018 * Convert a VT_DATE to a VT_BOOL.
6022 * pBoolOut [O] Destination
6027 HRESULT WINAPI
VarBoolFromDate(DATE dateIn
, VARIANT_BOOL
*pBoolOut
)
6029 *pBoolOut
= dateIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6033 /************************************************************************
6034 * VarBoolFromCy (OLEAUT32.124)
6036 * Convert a VT_CY to a VT_BOOL.
6040 * pBoolOut [O] Destination
6045 HRESULT WINAPI
VarBoolFromCy(CY cyIn
, VARIANT_BOOL
*pBoolOut
)
6047 *pBoolOut
= cyIn
.int64
? VARIANT_TRUE
: VARIANT_FALSE
;
6051 /************************************************************************
6052 * VARIANT_GetLocalisedText [internal]
6054 * Get a localized string from the resources
6057 static BOOL
VARIANT_GetLocalisedText(LANGID langId
, DWORD dwId
, WCHAR
*lpszDest
)
6061 hrsrc
= FindResourceExW( hProxyDll
, (LPWSTR
)RT_STRING
,
6062 MAKEINTRESOURCEW((dwId
>> 4) + 1), langId
);
6065 HGLOBAL hmem
= LoadResource( hProxyDll
, hrsrc
);
6072 p
= LockResource( hmem
);
6073 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
6075 memcpy( lpszDest
, p
+ 1, *p
* sizeof(WCHAR
) );
6076 lpszDest
[*p
] = '\0';
6077 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest
), langId
);
6084 /************************************************************************
6085 * VarBoolFromStr (OLEAUT32.125)
6087 * Convert a VT_BSTR to a VT_BOOL.
6091 * lcid [I] LCID for the conversion
6092 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6093 * pBoolOut [O] Destination
6097 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6098 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6101 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6102 * it may contain (in any case mapping) the text "true" or "false".
6103 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6104 * localised text of "True" or "False" in the language specified by lcid.
6105 * - If none of these matches occur, the string is treated as a numeric string
6106 * and the boolean pBoolOut will be set according to whether the number is zero
6107 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6108 * - If the text is not numeric and does not match any of the above, then
6109 * DISP_E_TYPEMISMATCH is returned.
6111 HRESULT WINAPI
VarBoolFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, VARIANT_BOOL
*pBoolOut
)
6114 LANGID langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6115 HRESULT hRes
= S_OK
;
6117 if (!strIn
|| !pBoolOut
)
6118 return DISP_E_TYPEMISMATCH
;
6120 /* Check if we should be comparing against localised text */
6121 if (dwFlags
& VAR_LOCALBOOL
)
6123 /* Convert our LCID into a usable value */
6124 lcid
= ConvertDefaultLocale(lcid
);
6126 langId
= LANGIDFROMLCID(lcid
);
6128 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6129 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6131 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6132 * I don't think this is needed unless any of the localised text strings
6133 * contain characters that can be so mapped. In the event that this is
6134 * true for a given language (possibly some Asian languages), then strIn
6135 * should be mapped here _only_ if langId is an Id for which this can occur.
6139 /* Note that if we are not comparing against localised strings, langId
6140 * will have its default value of LANG_ENGLISH. This allows us to mimic
6141 * the native behaviour of always checking against English strings even
6142 * after we've checked for localised ones.
6144 VarBoolFromStr_CheckLocalised
:
6145 if (VARIANT_GetLocalisedText(langId
, IDS_TRUE
, szBuff
))
6147 /* Compare against localised strings, ignoring case */
6148 if (!wcsicmp(strIn
, szBuff
))
6150 *pBoolOut
= VARIANT_TRUE
; /* Matched localised 'true' text */
6153 VARIANT_GetLocalisedText(langId
, IDS_FALSE
, szBuff
);
6154 if (!wcsicmp(strIn
, szBuff
))
6156 *pBoolOut
= VARIANT_FALSE
; /* Matched localised 'false' text */
6161 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6163 /* We have checked the localised text, now check English */
6164 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6165 goto VarBoolFromStr_CheckLocalised
;
6168 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6169 if (!wcscmp(strIn
, L
"#FALSE#"))
6170 *pBoolOut
= VARIANT_FALSE
;
6171 else if (!wcscmp(strIn
, L
"#TRUE#"))
6172 *pBoolOut
= VARIANT_TRUE
;
6177 /* If this string is a number, convert it as one */
6178 hRes
= VarR8FromStr(strIn
, lcid
, dwFlags
, &d
);
6179 if (SUCCEEDED(hRes
)) *pBoolOut
= d
? VARIANT_TRUE
: VARIANT_FALSE
;
6184 /************************************************************************
6185 * VarBoolFromDisp (OLEAUT32.126)
6187 * Convert a VT_DISPATCH to a VT_BOOL.
6190 * pdispIn [I] Source
6191 * lcid [I] LCID for conversion
6192 * pBoolOut [O] Destination
6196 * Failure: E_INVALIDARG, if the source value is invalid
6197 * DISP_E_OVERFLOW, if the value will not fit in the destination
6198 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6200 HRESULT WINAPI
VarBoolFromDisp(IDispatch
* pdispIn
, LCID lcid
, VARIANT_BOOL
*pBoolOut
)
6202 return VARIANT_FromDisp(pdispIn
, lcid
, pBoolOut
, VT_BOOL
, 0);
6205 /************************************************************************
6206 * VarBoolFromI1 (OLEAUT32.233)
6208 * Convert a VT_I1 to a VT_BOOL.
6212 * pBoolOut [O] Destination
6217 HRESULT WINAPI
VarBoolFromI1(signed char cIn
, VARIANT_BOOL
*pBoolOut
)
6219 *pBoolOut
= cIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6223 /************************************************************************
6224 * VarBoolFromUI2 (OLEAUT32.234)
6226 * Convert a VT_UI2 to a VT_BOOL.
6230 * pBoolOut [O] Destination
6235 HRESULT WINAPI
VarBoolFromUI2(USHORT usIn
, VARIANT_BOOL
*pBoolOut
)
6237 *pBoolOut
= usIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6241 /************************************************************************
6242 * VarBoolFromUI4 (OLEAUT32.235)
6244 * Convert a VT_UI4 to a VT_BOOL.
6248 * pBoolOut [O] Destination
6253 HRESULT WINAPI
VarBoolFromUI4(ULONG ulIn
, VARIANT_BOOL
*pBoolOut
)
6255 *pBoolOut
= ulIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6259 /************************************************************************
6260 * VarBoolFromDec (OLEAUT32.236)
6262 * Convert a VT_DECIMAL to a VT_BOOL.
6266 * pBoolOut [O] Destination
6270 * Failure: E_INVALIDARG, if pDecIn is invalid.
6272 HRESULT WINAPI
VarBoolFromDec(DECIMAL
* pDecIn
, VARIANT_BOOL
*pBoolOut
)
6274 if (DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
|| (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
))
6275 return E_INVALIDARG
;
6277 if (DEC_HI32(pDecIn
) || DEC_MID32(pDecIn
) || DEC_LO32(pDecIn
))
6278 *pBoolOut
= VARIANT_TRUE
;
6280 *pBoolOut
= VARIANT_FALSE
;
6284 /************************************************************************
6285 * VarBoolFromI8 (OLEAUT32.370)
6287 * Convert a VT_I8 to a VT_BOOL.
6291 * pBoolOut [O] Destination
6296 HRESULT WINAPI
VarBoolFromI8(LONG64 llIn
, VARIANT_BOOL
*pBoolOut
)
6298 *pBoolOut
= llIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6302 /************************************************************************
6303 * VarBoolFromUI8 (OLEAUT32.371)
6305 * Convert a VT_UI8 to a VT_BOOL.
6309 * pBoolOut [O] Destination
6314 HRESULT WINAPI
VarBoolFromUI8(ULONG64 ullIn
, VARIANT_BOOL
*pBoolOut
)
6316 *pBoolOut
= ullIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6323 /* Write a number from a UI8 and sign */
6324 static WCHAR
*VARIANT_WriteNumber(ULONG64 ulVal
, WCHAR
* szOut
)
6328 WCHAR ulNextDigit
= ulVal
% 10;
6330 *szOut
-- = '0' + ulNextDigit
;
6331 ulVal
= (ulVal
- ulNextDigit
) / 10;
6338 /* Create a (possibly localised) BSTR from a UI8 and sign */
6339 static BSTR
VARIANT_MakeBstr(LCID lcid
, DWORD dwFlags
, WCHAR
*szOut
)
6341 WCHAR szConverted
[256];
6343 if (dwFlags
& VAR_NEGATIVE
)
6346 if (dwFlags
& LOCALE_USE_NLS
)
6348 /* Format the number for the locale */
6349 szConverted
[0] = '\0';
6350 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6351 szOut
, NULL
, szConverted
, ARRAY_SIZE(szConverted
));
6352 szOut
= szConverted
;
6354 return SysAllocStringByteLen((LPCSTR
)szOut
, lstrlenW(szOut
) * sizeof(WCHAR
));
6357 /* Create a (possibly localised) BSTR from a UI8 and sign */
6358 static HRESULT
VARIANT_BstrFromUInt(ULONG64 ulVal
, LCID lcid
, DWORD dwFlags
, BSTR
*pbstrOut
)
6360 WCHAR szBuff
[64], *szOut
= szBuff
+ ARRAY_SIZE(szBuff
) - 1;
6363 return E_INVALIDARG
;
6365 /* Create the basic number string */
6367 szOut
= VARIANT_WriteNumber(ulVal
, szOut
);
6369 *pbstrOut
= VARIANT_MakeBstr(lcid
, dwFlags
, szOut
);
6370 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6371 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6374 /******************************************************************************
6375 * VarBstrFromUI1 (OLEAUT32.108)
6377 * Convert a VT_UI1 to a VT_BSTR.
6381 * lcid [I] LCID for the conversion
6382 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6383 * pbstrOut [O] Destination
6387 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6388 * E_OUTOFMEMORY, if memory allocation fails.
6390 HRESULT WINAPI
VarBstrFromUI1(BYTE bIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6392 return VARIANT_BstrFromUInt(bIn
, lcid
, dwFlags
, pbstrOut
);
6395 /******************************************************************************
6396 * VarBstrFromI2 (OLEAUT32.109)
6398 * Convert a VT_I2 to a VT_BSTR.
6402 * lcid [I] LCID for the conversion
6403 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6404 * pbstrOut [O] Destination
6408 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6409 * E_OUTOFMEMORY, if memory allocation fails.
6411 HRESULT WINAPI
VarBstrFromI2(short sIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6418 dwFlags
|= VAR_NEGATIVE
;
6420 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6423 /******************************************************************************
6424 * VarBstrFromI4 (OLEAUT32.110)
6426 * Convert a VT_I4 to a VT_BSTR.
6430 * lcid [I] LCID for the conversion
6431 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6432 * pbstrOut [O] Destination
6436 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6437 * E_OUTOFMEMORY, if memory allocation fails.
6439 HRESULT WINAPI
VarBstrFromI4(LONG lIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6445 ul64
= -(LONG64
)lIn
;
6446 dwFlags
|= VAR_NEGATIVE
;
6448 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6451 static BSTR
VARIANT_BstrReplaceDecimal(const WCHAR
* buff
, LCID lcid
, ULONG dwFlags
)
6454 WCHAR lpDecimalSep
[16];
6456 /* Native oleaut32 uses the locale-specific decimal separator even in the
6457 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6458 American locales will see "one thousand and one tenth" as "1000,1"
6459 instead of "1000.1" (notice the comma). The following code checks for
6460 the need to replace the decimal separator, and if so, will prepare an
6461 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6463 GetLocaleInfoW(lcid
, LOCALE_SDECIMAL
| (dwFlags
& LOCALE_NOUSEROVERRIDE
),
6464 lpDecimalSep
, ARRAY_SIZE(lpDecimalSep
));
6465 if (lpDecimalSep
[0] == '.' && lpDecimalSep
[1] == '\0')
6467 /* locale is compatible with English - return original string */
6468 bstrOut
= SysAllocString(buff
);
6474 WCHAR empty
[] = L
"";
6475 NUMBERFMTW minFormat
;
6477 minFormat
.NumDigits
= 0;
6478 minFormat
.LeadingZero
= 0;
6479 minFormat
.Grouping
= 0;
6480 minFormat
.lpDecimalSep
= lpDecimalSep
;
6481 minFormat
.lpThousandSep
= empty
;
6482 minFormat
.NegativeOrder
= 1; /* NLS_NEG_LEFT */
6484 /* count number of decimal digits in string */
6485 p
= wcschr( buff
, '.' );
6486 if (p
) minFormat
.NumDigits
= lstrlenW(p
+ 1);
6489 if (!GetNumberFormatW(lcid
, 0, buff
, &minFormat
, numbuff
, ARRAY_SIZE(numbuff
)))
6491 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6492 bstrOut
= SysAllocString(buff
);
6496 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff
));
6497 bstrOut
= SysAllocString(numbuff
);
6503 static HRESULT
VARIANT_BstrFromReal(DOUBLE dblIn
, LCID lcid
, ULONG dwFlags
,
6504 BSTR
* pbstrOut
, LPCWSTR lpszFormat
)
6510 return E_INVALIDARG
;
6512 if (!(locale
= _create_locale(LC_ALL
, "C"))) return E_OUTOFMEMORY
;
6513 _swprintf_l(buff
, ARRAY_SIZE(buff
), lpszFormat
, locale
, dblIn
);
6514 _free_locale(locale
);
6516 /* Negative zeroes are disallowed (some applications depend on this).
6517 If buff starts with a minus, and then nothing follows but zeroes
6518 and/or a period, it is a negative zero and is replaced with a
6519 canonical zero. This duplicates native oleaut32 behavior.
6523 if (lstrlenW(buff
+ 1) == wcsspn(buff
+ 1, L
"0."))
6524 { buff
[0] = '0'; buff
[1] = '\0'; }
6527 TRACE("created string %s\n", debugstr_w(buff
));
6528 if (dwFlags
& LOCALE_USE_NLS
)
6532 /* Format the number for the locale */
6534 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6535 buff
, NULL
, numbuff
, ARRAY_SIZE(numbuff
));
6536 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
6537 *pbstrOut
= SysAllocString(numbuff
);
6541 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
6543 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6546 /******************************************************************************
6547 * VarBstrFromR4 (OLEAUT32.111)
6549 * Convert a VT_R4 to a VT_BSTR.
6553 * lcid [I] LCID for the conversion
6554 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6555 * pbstrOut [O] Destination
6559 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6560 * E_OUTOFMEMORY, if memory allocation fails.
6562 HRESULT WINAPI
VarBstrFromR4(FLOAT fltIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6564 return VARIANT_BstrFromReal(fltIn
, lcid
, dwFlags
, pbstrOut
, L
"%.7G");
6567 /******************************************************************************
6568 * VarBstrFromR8 (OLEAUT32.112)
6570 * Convert a VT_R8 to a VT_BSTR.
6574 * lcid [I] LCID for the conversion
6575 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6576 * pbstrOut [O] Destination
6580 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6581 * E_OUTOFMEMORY, if memory allocation fails.
6583 HRESULT WINAPI
VarBstrFromR8(double dblIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6585 return VARIANT_BstrFromReal(dblIn
, lcid
, dwFlags
, pbstrOut
, L
"%.15G");
6588 /******************************************************************************
6589 * VarBstrFromCy [OLEAUT32.113]
6591 * Convert a VT_CY to a VT_BSTR.
6595 * lcid [I] LCID for the conversion
6596 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6597 * pbstrOut [O] Destination
6601 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6602 * E_OUTOFMEMORY, if memory allocation fails.
6604 HRESULT WINAPI
VarBstrFromCy(CY cyIn
, LCID lcid
, ULONG dwFlags
, BSTR
*pbstrOut
)
6610 return E_INVALIDARG
;
6614 decVal
.bitsnum
[0] = cyIn
.s
.Lo
;
6615 decVal
.bitsnum
[1] = cyIn
.s
.Hi
;
6616 if (cyIn
.s
.Hi
& 0x80000000UL
) {
6619 /* Negative number! */
6621 decVal
.bitsnum
[0] = ~decVal
.bitsnum
[0];
6622 decVal
.bitsnum
[1] = ~decVal
.bitsnum
[1];
6623 VARIANT_int_add(decVal
.bitsnum
, 3, &one
, 1);
6625 decVal
.bitsnum
[2] = 0;
6626 VARIANT_DI_tostringW(&decVal
, buff
, ARRAY_SIZE(buff
));
6628 if (dwFlags
& LOCALE_USE_NLS
)
6632 /* Format the currency for the locale */
6634 GetCurrencyFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6635 buff
, NULL
, cybuff
, ARRAY_SIZE(cybuff
));
6636 *pbstrOut
= SysAllocString(cybuff
);
6639 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
,lcid
,dwFlags
);
6641 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6644 static inline int output_int_len(int o
, int min_len
, WCHAR
*date
, int date_len
)
6648 if(min_len
>= date_len
)
6651 for(len
=0, tmp
=o
; tmp
; tmp
/=10) len
++;
6656 for(tmp
=min_len
-len
; tmp
>0; tmp
--)
6658 for(tmp
=len
; tmp
>0; tmp
--, o
/=10)
6659 date
[tmp
-1] = '0' + o
%10;
6660 return min_len
>len
? min_len
: len
;
6663 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6664 BOOL
get_date_format(LCID lcid
, DWORD flags
, const SYSTEMTIME
*st
,
6665 const WCHAR
*fmt
, WCHAR
*date
, int date_len
)
6667 static const LCTYPE dayname
[] = {
6668 LOCALE_SDAYNAME7
, LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
,
6669 LOCALE_SDAYNAME4
, LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
6671 static const LCTYPE sdayname
[] = {
6672 LOCALE_SABBREVDAYNAME7
, LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
,
6673 LOCALE_SABBREVDAYNAME3
, LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
,
6674 LOCALE_SABBREVDAYNAME6
6676 static const LCTYPE monthname
[] = {
6677 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
6678 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
6679 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
6681 static const LCTYPE smonthname
[] = {
6682 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
6683 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
6684 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
6685 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
6688 if(flags
& ~(LOCALE_NOUSEROVERRIDE
|VAR_DATEVALUEONLY
))
6689 FIXME("ignoring flags %x\n", flags
);
6690 flags
&= LOCALE_NOUSEROVERRIDE
;
6692 while(*fmt
&& date_len
) {
6700 while(*fmt
== *(fmt
+count
))
6708 count
= GetLocaleInfoW(lcid
, dayname
[st
->wDayOfWeek
] | flags
, date
, date_len
)-1;
6710 count
= GetLocaleInfoW(lcid
, sdayname
[st
->wDayOfWeek
] | flags
, date
, date_len
)-1;
6712 count
= output_int_len(st
->wDay
, count
, date
, date_len
);
6716 count
= GetLocaleInfoW(lcid
, monthname
[st
->wMonth
-1] | flags
, date
, date_len
)-1;
6718 count
= GetLocaleInfoW(lcid
, smonthname
[st
->wMonth
-1] | flags
, date
, date_len
)-1;
6720 count
= output_int_len(st
->wMonth
, count
, date
, date_len
);
6724 count
= output_int_len(st
->wYear
, 0, date
, date_len
);
6726 count
= output_int_len(st
->wYear
%100, count
, date
, date_len
);
6730 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6758 /******************************************************************************
6759 * VarBstrFromDate [OLEAUT32.114]
6761 * Convert a VT_DATE to a VT_BSTR.
6765 * lcid [I] LCID for the conversion
6766 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6767 * pbstrOut [O] Destination
6771 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6772 * E_OUTOFMEMORY, if memory allocation fails.
6774 HRESULT WINAPI
VarBstrFromDate(DATE dateIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6777 DWORD dwFormatFlags
= dwFlags
& LOCALE_NOUSEROVERRIDE
;
6778 WCHAR date
[128], fmt_buff
[80], *time
;
6780 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn
, lcid
, dwFlags
, pbstrOut
);
6782 if (!pbstrOut
|| !VariantTimeToSystemTime(dateIn
, &st
))
6783 return E_INVALIDARG
;
6787 if (dwFlags
& VAR_CALENDAR_THAI
)
6788 st
.wYear
+= 553; /* Use the Thai buddhist calendar year */
6789 else if (dwFlags
& (VAR_CALENDAR_HIJRI
|VAR_CALENDAR_GREGORIAN
))
6790 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6792 if (dwFlags
& LOCALE_USE_NLS
)
6793 dwFlags
&= ~(VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
);
6796 double whole
= dateIn
< 0 ? ceil(dateIn
) : floor(dateIn
);
6797 double partial
= dateIn
- whole
;
6800 dwFlags
|= VAR_TIMEVALUEONLY
;
6801 else if (partial
> -1e-12 && partial
< 1e-12)
6802 dwFlags
|= VAR_DATEVALUEONLY
;
6805 if (dwFlags
& VAR_TIMEVALUEONLY
)
6808 if (!GetLocaleInfoW(lcid
, LOCALE_SSHORTDATE
, fmt_buff
, ARRAY_SIZE(fmt_buff
)) ||
6809 !get_date_format(lcid
, dwFlags
, &st
, fmt_buff
, date
, ARRAY_SIZE(date
)))
6810 return E_INVALIDARG
;
6812 if (!(dwFlags
& VAR_DATEVALUEONLY
))
6814 time
= date
+ lstrlenW(date
);
6817 if (!GetTimeFormatW(lcid
, dwFormatFlags
, &st
, NULL
, time
, ARRAY_SIZE(date
)-(time
-date
)))
6818 return E_INVALIDARG
;
6821 *pbstrOut
= SysAllocString(date
);
6823 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6824 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6827 /******************************************************************************
6828 * VarBstrFromBool (OLEAUT32.116)
6830 * Convert a VT_BOOL to a VT_BSTR.
6834 * lcid [I] LCID for the conversion
6835 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6836 * pbstrOut [O] Destination
6840 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6841 * E_OUTOFMEMORY, if memory allocation fails.
6844 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6845 * localised text of "True" or "False". To convert a bool into a
6846 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6848 HRESULT WINAPI
VarBstrFromBool(VARIANT_BOOL boolIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6851 DWORD dwResId
= IDS_TRUE
;
6854 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn
, lcid
, dwFlags
, pbstrOut
);
6857 return E_INVALIDARG
;
6859 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6860 * for variant formatting */
6861 switch (dwFlags
& (VAR_LOCALBOOL
|VAR_BOOLONOFF
|VAR_BOOLYESNO
))
6872 lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
),SORT_DEFAULT
);
6875 lcid
= ConvertDefaultLocale(lcid
);
6876 langId
= LANGIDFROMLCID(lcid
);
6877 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6878 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6880 if (boolIn
== VARIANT_FALSE
)
6881 dwResId
++; /* Use negative form */
6883 VarBstrFromBool_GetLocalised
:
6884 if (VARIANT_GetLocalisedText(langId
, dwResId
, szBuff
))
6886 *pbstrOut
= SysAllocString(szBuff
);
6887 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6890 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6892 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6893 goto VarBstrFromBool_GetLocalised
;
6896 /* Should never get here */
6897 WARN("Failed to load bool text!\n");
6898 return E_OUTOFMEMORY
;
6901 /******************************************************************************
6902 * VarBstrFromI1 (OLEAUT32.229)
6904 * Convert a VT_I1 to a VT_BSTR.
6908 * lcid [I] LCID for the conversion
6909 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6910 * pbstrOut [O] Destination
6914 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6915 * E_OUTOFMEMORY, if memory allocation fails.
6917 HRESULT WINAPI
VarBstrFromI1(signed char cIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6924 dwFlags
|= VAR_NEGATIVE
;
6926 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6929 /******************************************************************************
6930 * VarBstrFromUI2 (OLEAUT32.230)
6932 * Convert a VT_UI2 to a VT_BSTR.
6936 * lcid [I] LCID for the conversion
6937 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6938 * pbstrOut [O] Destination
6942 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6943 * E_OUTOFMEMORY, if memory allocation fails.
6945 HRESULT WINAPI
VarBstrFromUI2(USHORT usIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6947 return VARIANT_BstrFromUInt(usIn
, lcid
, dwFlags
, pbstrOut
);
6950 /******************************************************************************
6951 * VarBstrFromUI4 (OLEAUT32.231)
6953 * Convert a VT_UI4 to a VT_BSTR.
6957 * lcid [I] LCID for the conversion
6958 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6959 * pbstrOut [O] Destination
6963 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6964 * E_OUTOFMEMORY, if memory allocation fails.
6966 HRESULT WINAPI
VarBstrFromUI4(ULONG ulIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6968 return VARIANT_BstrFromUInt(ulIn
, lcid
, dwFlags
, pbstrOut
);
6971 /******************************************************************************
6972 * VarBstrFromDec (OLEAUT32.232)
6974 * Convert a VT_DECIMAL to a VT_BSTR.
6978 * lcid [I] LCID for the conversion
6979 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6980 * pbstrOut [O] Destination
6984 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6985 * E_OUTOFMEMORY, if memory allocation fails.
6987 HRESULT WINAPI
VarBstrFromDec(DECIMAL
* pDecIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6993 return E_INVALIDARG
;
6995 VARIANT_DIFromDec(pDecIn
, &temp
);
6996 VARIANT_DI_tostringW(&temp
, buff
, 256);
6998 if (dwFlags
& LOCALE_USE_NLS
)
7002 /* Format the number for the locale */
7004 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
7005 buff
, NULL
, numbuff
, ARRAY_SIZE(numbuff
));
7006 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
7007 *pbstrOut
= SysAllocString(numbuff
);
7011 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
7014 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
7015 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
7018 /************************************************************************
7019 * VarBstrFromI8 (OLEAUT32.370)
7021 * Convert a VT_I8 to a VT_BSTR.
7025 * lcid [I] LCID for the conversion
7026 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7027 * pbstrOut [O] Destination
7031 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7032 * E_OUTOFMEMORY, if memory allocation fails.
7034 HRESULT WINAPI
VarBstrFromI8(LONG64 llIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7036 ULONG64 ul64
= llIn
;
7041 dwFlags
|= VAR_NEGATIVE
;
7043 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
7046 /************************************************************************
7047 * VarBstrFromUI8 (OLEAUT32.371)
7049 * Convert a VT_UI8 to a VT_BSTR.
7053 * lcid [I] LCID for the conversion
7054 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7055 * pbstrOut [O] Destination
7059 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7060 * E_OUTOFMEMORY, if memory allocation fails.
7062 HRESULT WINAPI
VarBstrFromUI8(ULONG64 ullIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7064 return VARIANT_BstrFromUInt(ullIn
, lcid
, dwFlags
, pbstrOut
);
7067 /************************************************************************
7068 * VarBstrFromDisp (OLEAUT32.115)
7070 * Convert a VT_DISPATCH to a BSTR.
7073 * pdispIn [I] Source
7074 * lcid [I] LCID for conversion
7075 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7076 * pbstrOut [O] Destination
7080 * Failure: E_INVALIDARG, if the source value is invalid
7081 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7083 HRESULT WINAPI
VarBstrFromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7085 return VARIANT_FromDisp(pdispIn
, lcid
, pbstrOut
, VT_BSTR
, dwFlags
);
7088 /**********************************************************************
7089 * VarBstrCat (OLEAUT32.313)
7091 * Concatenate two BSTR values.
7094 * pbstrLeft [I] Source
7095 * pbstrRight [I] Value to concatenate
7096 * pbstrOut [O] Destination
7100 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7101 * E_OUTOFMEMORY, if memory allocation fails.
7103 HRESULT WINAPI
VarBstrCat(BSTR pbstrLeft
, BSTR pbstrRight
, BSTR
*pbstrOut
)
7105 unsigned int lenLeft
, lenRight
;
7108 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
7109 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), pbstrOut
);
7112 return E_INVALIDARG
;
7114 /* use byte length here to properly handle ansi-allocated BSTRs */
7115 lenLeft
= pbstrLeft
? SysStringByteLen(pbstrLeft
) : 0;
7116 lenRight
= pbstrRight
? SysStringByteLen(pbstrRight
) : 0;
7118 *pbstrOut
= SysAllocStringByteLen(NULL
, lenLeft
+ lenRight
);
7120 return E_OUTOFMEMORY
;
7122 (*pbstrOut
)[0] = '\0';
7125 memcpy(*pbstrOut
, pbstrLeft
, lenLeft
);
7128 memcpy((CHAR
*)*pbstrOut
+ lenLeft
, pbstrRight
, lenRight
);
7130 TRACE("%s\n", debugstr_wn(*pbstrOut
, SysStringLen(*pbstrOut
)));
7134 /**********************************************************************
7135 * VarBstrCmp (OLEAUT32.314)
7137 * Compare two BSTR values.
7140 * pbstrLeft [I] Source
7141 * pbstrRight [I] Value to compare
7142 * lcid [I] LCID for the comparison
7143 * dwFlags [I] Flags to pass directly to CompareStringW().
7146 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7147 * than, equal to or greater than pbstrRight respectively.
7150 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7151 * states. A NULL BSTR pointer is equivalent to an empty string.
7152 * If LCID is equal to 0, a byte by byte comparison is performed.
7154 HRESULT WINAPI
VarBstrCmp(BSTR pbstrLeft
, BSTR pbstrRight
, LCID lcid
, DWORD dwFlags
)
7159 TRACE("%s,%s,%d,%08x\n",
7160 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
7161 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), lcid
, dwFlags
);
7163 if (!pbstrLeft
|| !*pbstrLeft
)
7165 if (pbstrRight
&& *pbstrRight
)
7168 else if (!pbstrRight
|| !*pbstrRight
)
7173 unsigned int lenLeft
= SysStringByteLen(pbstrLeft
);
7174 unsigned int lenRight
= SysStringByteLen(pbstrRight
);
7175 ret
= memcmp(pbstrLeft
, pbstrRight
, min(lenLeft
, lenRight
));
7180 if (lenLeft
< lenRight
)
7182 if (lenLeft
> lenRight
)
7188 unsigned int lenLeft
= SysStringLen(pbstrLeft
);
7189 unsigned int lenRight
= SysStringLen(pbstrRight
);
7191 if (lenLeft
== 0 || lenRight
== 0)
7193 if (lenLeft
== 0 && lenRight
== 0) return VARCMP_EQ
;
7194 return lenLeft
< lenRight
? VARCMP_LT
: VARCMP_GT
;
7197 hres
= CompareStringW(lcid
, dwFlags
, pbstrLeft
, lenLeft
,
7198 pbstrRight
, lenRight
) - CSTR_LESS_THAN
;
7199 TRACE("%d\n", hres
);
7208 /******************************************************************************
7209 * VarDateFromUI1 (OLEAUT32.88)
7211 * Convert a VT_UI1 to a VT_DATE.
7215 * pdateOut [O] Destination
7220 HRESULT WINAPI
VarDateFromUI1(BYTE bIn
, DATE
* pdateOut
)
7222 return VarR8FromUI1(bIn
, pdateOut
);
7225 /******************************************************************************
7226 * VarDateFromI2 (OLEAUT32.89)
7228 * Convert a VT_I2 to a VT_DATE.
7232 * pdateOut [O] Destination
7237 HRESULT WINAPI
VarDateFromI2(short sIn
, DATE
* pdateOut
)
7239 return VarR8FromI2(sIn
, pdateOut
);
7242 /******************************************************************************
7243 * VarDateFromI4 (OLEAUT32.90)
7245 * Convert a VT_I4 to a VT_DATE.
7249 * pdateOut [O] Destination
7254 HRESULT WINAPI
VarDateFromI4(LONG lIn
, DATE
* pdateOut
)
7256 return VarDateFromR8(lIn
, pdateOut
);
7259 /******************************************************************************
7260 * VarDateFromR4 (OLEAUT32.91)
7262 * Convert a VT_R4 to a VT_DATE.
7266 * pdateOut [O] Destination
7271 HRESULT WINAPI
VarDateFromR4(FLOAT fltIn
, DATE
* pdateOut
)
7273 return VarR8FromR4(fltIn
, pdateOut
);
7276 /******************************************************************************
7277 * VarDateFromR8 (OLEAUT32.92)
7279 * Convert a VT_R8 to a VT_DATE.
7283 * pdateOut [O] Destination
7288 HRESULT WINAPI
VarDateFromR8(double dblIn
, DATE
* pdateOut
)
7290 if (dblIn
<= (DATE_MIN
- 1.0) || dblIn
>= (DATE_MAX
+ 1.0)) return DISP_E_OVERFLOW
;
7291 *pdateOut
= (DATE
)dblIn
;
7295 /**********************************************************************
7296 * VarDateFromDisp (OLEAUT32.95)
7298 * Convert a VT_DISPATCH to a VT_DATE.
7301 * pdispIn [I] Source
7302 * lcid [I] LCID for conversion
7303 * pdateOut [O] Destination
7307 * Failure: E_INVALIDARG, if the source value is invalid
7308 * DISP_E_OVERFLOW, if the value will not fit in the destination
7309 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7311 HRESULT WINAPI
VarDateFromDisp(IDispatch
* pdispIn
, LCID lcid
, DATE
* pdateOut
)
7313 return VARIANT_FromDisp(pdispIn
, lcid
, pdateOut
, VT_DATE
, 0);
7316 /******************************************************************************
7317 * VarDateFromBool (OLEAUT32.96)
7319 * Convert a VT_BOOL to a VT_DATE.
7323 * pdateOut [O] Destination
7328 HRESULT WINAPI
VarDateFromBool(VARIANT_BOOL boolIn
, DATE
* pdateOut
)
7330 return VarR8FromBool(boolIn
, pdateOut
);
7333 /**********************************************************************
7334 * VarDateFromCy (OLEAUT32.93)
7336 * Convert a VT_CY to a VT_DATE.
7340 * pdateOut [O] Destination
7345 HRESULT WINAPI
VarDateFromCy(CY cyIn
, DATE
* pdateOut
)
7347 return VarR8FromCy(cyIn
, pdateOut
);
7350 /* Date string parsing */
7351 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7352 #define DP_DATESEP 0x02 /* Date separator */
7353 #define DP_MONTH 0x04 /* Month name */
7354 #define DP_AM 0x08 /* AM */
7355 #define DP_PM 0x10 /* PM */
7357 typedef struct tagDATEPARSE
7359 DWORD dwCount
; /* Number of fields found so far (maximum 6) */
7360 DWORD dwParseFlags
; /* Global parse flags (DP_ Flags above) */
7361 DWORD dwFlags
[6]; /* Flags for each field */
7362 DWORD dwValues
[6]; /* Value of each field */
7365 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7367 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7369 /* Determine if a day is valid in a given month of a given year */
7370 static BOOL
VARIANT_IsValidMonthDay(DWORD day
, DWORD month
, DWORD year
)
7372 static const BYTE days
[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7374 if (day
&& month
&& month
< 13)
7376 if (day
<= days
[month
] || (month
== 2 && day
== 29 && IsLeapYear(year
)))
7382 /* Possible orders for 3 numbers making up a date */
7383 #define ORDER_MDY 0x01
7384 #define ORDER_YMD 0x02
7385 #define ORDER_YDM 0x04
7386 #define ORDER_DMY 0x08
7387 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7389 /* Determine a date for a particular locale, from 3 numbers */
7390 static inline HRESULT
VARIANT_MakeDate(DATEPARSE
*dp
, DWORD iDate
,
7391 DWORD offset
, SYSTEMTIME
*st
)
7393 DWORD dwAllOrders
, dwTry
, dwCount
= 0, v1
, v2
, v3
;
7397 v1
= 30; /* Default to (Variant) 0 date part */
7400 goto VARIANT_MakeDate_OK
;
7403 v1
= dp
->dwValues
[offset
+ 0];
7404 v2
= dp
->dwValues
[offset
+ 1];
7405 if (dp
->dwCount
== 2)
7408 GetSystemTime(¤t
);
7412 v3
= dp
->dwValues
[offset
+ 2];
7414 TRACE("(%d,%d,%d,%d,%d)\n", v1
, v2
, v3
, iDate
, offset
);
7416 /* If one number must be a month (Because a month name was given), then only
7417 * consider orders with the month in that position.
7418 * If we took the current year as 'v3', then only allow a year in that position.
7420 if (dp
->dwFlags
[offset
+ 0] & DP_MONTH
)
7422 dwAllOrders
= ORDER_MDY
;
7424 else if (dp
->dwFlags
[offset
+ 1] & DP_MONTH
)
7426 dwAllOrders
= ORDER_DMY
;
7427 if (dp
->dwCount
> 2)
7428 dwAllOrders
|= ORDER_YMD
;
7430 else if (dp
->dwCount
> 2 && dp
->dwFlags
[offset
+ 2] & DP_MONTH
)
7432 dwAllOrders
= ORDER_YDM
;
7436 dwAllOrders
= ORDER_MDY
|ORDER_DMY
;
7437 if (dp
->dwCount
> 2)
7438 dwAllOrders
|= (ORDER_YMD
|ORDER_YDM
);
7441 VARIANT_MakeDate_Start
:
7442 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders
);
7450 /* First: Try the order given by iDate */
7453 case 0: dwTry
= dwAllOrders
& ORDER_MDY
; break;
7454 case 1: dwTry
= dwAllOrders
& ORDER_DMY
; break;
7455 default: dwTry
= dwAllOrders
& ORDER_YMD
; break;
7458 else if (dwCount
== 1)
7460 /* Second: Try all the orders compatible with iDate */
7463 case 0: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7464 case 1: dwTry
= dwAllOrders
& ~(ORDER_MDY
|ORDER_YDM
|ORDER_MYD
); break;
7465 default: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7470 /* Finally: Try any remaining orders */
7471 dwTry
= dwAllOrders
;
7474 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount
, dwTry
);
7480 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7482 if (dwTry
& ORDER_MDY
)
7484 if (VARIANT_IsValidMonthDay(v2
,v1
,v3
))
7487 goto VARIANT_MakeDate_OK
;
7489 dwAllOrders
&= ~ORDER_MDY
;
7491 if (dwTry
& ORDER_YMD
)
7493 if (VARIANT_IsValidMonthDay(v3
,v2
,v1
))
7496 goto VARIANT_MakeDate_OK
;
7498 dwAllOrders
&= ~ORDER_YMD
;
7500 if (dwTry
& ORDER_YDM
)
7502 if (VARIANT_IsValidMonthDay(v2
,v3
,v1
))
7506 goto VARIANT_MakeDate_OK
;
7508 dwAllOrders
&= ~ORDER_YDM
;
7510 if (dwTry
& ORDER_DMY
)
7512 if (VARIANT_IsValidMonthDay(v1
,v2
,v3
))
7513 goto VARIANT_MakeDate_OK
;
7514 dwAllOrders
&= ~ORDER_DMY
;
7516 if (dwTry
& ORDER_MYD
)
7518 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7519 if (VARIANT_IsValidMonthDay(v3
,v1
,v2
))
7523 goto VARIANT_MakeDate_OK
;
7525 dwAllOrders
&= ~ORDER_MYD
;
7529 if (dp
->dwCount
== 2)
7531 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7532 v3
= 1; /* 1st of the month */
7533 dwAllOrders
= ORDER_YMD
|ORDER_MYD
;
7534 dp
->dwCount
= 0; /* Don't return to this code path again */
7536 goto VARIANT_MakeDate_Start
;
7539 /* No valid dates were able to be constructed */
7540 return DISP_E_TYPEMISMATCH
;
7542 VARIANT_MakeDate_OK
:
7544 /* Check that the time part is ok */
7545 if (st
->wHour
> 23 || st
->wMinute
> 59 || st
->wSecond
> 59)
7546 return DISP_E_TYPEMISMATCH
;
7548 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7549 if (st
->wHour
< 12 && (dp
->dwParseFlags
& DP_PM
))
7551 else if (st
->wHour
== 12 && (dp
->dwParseFlags
& DP_AM
))
7553 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7557 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7558 * be retrieved from:
7559 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7560 * But Wine doesn't have/use that key as at the time of writing.
7562 st
->wYear
= v3
< 30 ? 2000 + v3
: v3
< 100 ? 1900 + v3
: v3
;
7563 TRACE("Returning date %d/%d/%d\n", v1
, v2
, st
->wYear
);
7567 /******************************************************************************
7568 * VarDateFromStr [OLEAUT32.94]
7570 * Convert a VT_BSTR to at VT_DATE.
7573 * strIn [I] String to convert
7574 * lcid [I] Locale identifier for the conversion
7575 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7576 * pdateOut [O] Destination for the converted value
7579 * Success: S_OK. pdateOut contains the converted value.
7580 * FAILURE: An HRESULT error code indicating the problem.
7583 * Any date format that can be created using the date formats from lcid
7584 * (Either from kernel Nls functions, variant conversion or formatting) is a
7585 * valid input to this function. In addition, a few more esoteric formats are
7586 * also supported for compatibility with the native version. The date is
7587 * interpreted according to the date settings in the control panel, unless
7588 * the date is invalid in that format, in which the most compatible format
7589 * that produces a valid date will be used.
7591 HRESULT WINAPI
VarDateFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DATE
* pdateOut
)
7593 static const USHORT ParseDateTokens
[] =
7595 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
7596 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
7597 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
,
7598 LOCALE_SMONTHNAME13
,
7599 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
7600 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
7601 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
7602 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
,
7603 LOCALE_SABBREVMONTHNAME13
,
7604 LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
, LOCALE_SDAYNAME4
,
7605 LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
, LOCALE_SDAYNAME7
,
7606 LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
, LOCALE_SABBREVDAYNAME3
,
7607 LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
, LOCALE_SABBREVDAYNAME6
,
7608 LOCALE_SABBREVDAYNAME7
,
7609 LOCALE_S1159
, LOCALE_S2359
,
7612 static const BYTE ParseDateMonths
[] =
7614 1,2,3,4,5,6,7,8,9,10,11,12,13,
7615 1,2,3,4,5,6,7,8,9,10,11,12,13
7618 BSTR tokens
[ARRAY_SIZE(ParseDateTokens
)];
7620 DWORD dwDateSeps
= 0, iDate
= 0;
7621 HRESULT hRet
= S_OK
;
7623 if ((dwFlags
& (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
)) ==
7624 (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
))
7625 return E_INVALIDARG
;
7628 return DISP_E_TYPEMISMATCH
;
7632 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn
), lcid
, dwFlags
, pdateOut
);
7634 memset(&dp
, 0, sizeof(dp
));
7636 GetLocaleInfoW(lcid
, LOCALE_IDATE
|LOCALE_RETURN_NUMBER
|(dwFlags
& LOCALE_NOUSEROVERRIDE
),
7637 (LPWSTR
)&iDate
, sizeof(iDate
)/sizeof(WCHAR
));
7638 TRACE("iDate is %d\n", iDate
);
7640 /* Get the month/day/am/pm tokens for this locale */
7641 for (i
= 0; i
< ARRAY_SIZE(tokens
); i
++)
7644 LCTYPE lctype
= ParseDateTokens
[i
] | (dwFlags
& LOCALE_NOUSEROVERRIDE
);
7646 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7647 * GetAltMonthNames(). We should really cache these strings too.
7650 GetLocaleInfoW(lcid
, lctype
, buff
, ARRAY_SIZE(buff
));
7651 tokens
[i
] = SysAllocString(buff
);
7652 TRACE("token %d is %s\n", i
, debugstr_w(tokens
[i
]));
7655 /* Parse the string into our structure */
7658 if ('0' <= *strIn
&& *strIn
<= '9')
7660 if (dp
.dwCount
>= 6)
7662 hRet
= DISP_E_TYPEMISMATCH
;
7665 dp
.dwValues
[dp
.dwCount
] = wcstoul(strIn
, &strIn
, 10);
7669 else if (iswalpha(*strIn
))
7671 BOOL bFound
= FALSE
;
7673 for (i
= 0; i
< ARRAY_SIZE(tokens
); i
++)
7675 DWORD dwLen
= lstrlenW(tokens
[i
]);
7676 if (dwLen
&& !wcsnicmp(strIn
, tokens
[i
], dwLen
))
7680 if (dp
.dwCount
>= 6)
7681 hRet
= DISP_E_TYPEMISMATCH
;
7684 dp
.dwValues
[dp
.dwCount
] = ParseDateMonths
[i
];
7685 dp
.dwFlags
[dp
.dwCount
] |= (DP_MONTH
|DP_DATESEP
);
7689 else if (i
> 39 && i
< 42)
7691 if (!dp
.dwCount
|| dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7692 hRet
= DISP_E_TYPEMISMATCH
;
7695 dp
.dwFlags
[dp
.dwCount
- 1] |= (i
== 40 ? DP_AM
: DP_PM
);
7696 dp
.dwParseFlags
|= (i
== 40 ? DP_AM
: DP_PM
);
7699 strIn
+= (dwLen
- 1);
7707 if ((*strIn
== 'a' || *strIn
== 'A' || *strIn
== 'p' || *strIn
== 'P') &&
7708 (dp
.dwCount
&& !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7710 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7711 if (*strIn
== 'a' || *strIn
== 'A')
7713 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_AM
;
7714 dp
.dwParseFlags
|= DP_AM
;
7718 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_PM
;
7719 dp
.dwParseFlags
|= DP_PM
;
7725 TRACE("No matching token for %s\n", debugstr_w(strIn
));
7726 hRet
= DISP_E_TYPEMISMATCH
;
7731 else if (*strIn
== ':' || *strIn
== '.')
7733 if (!dp
.dwCount
|| !strIn
[1])
7734 hRet
= DISP_E_TYPEMISMATCH
;
7736 if (tokens
[42][0] == *strIn
)
7740 hRet
= DISP_E_TYPEMISMATCH
;
7742 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7745 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_TIMESEP
;
7747 else if (*strIn
== '-' || *strIn
== '/')
7750 if (dwDateSeps
> 2 || !dp
.dwCount
|| !strIn
[1])
7751 hRet
= DISP_E_TYPEMISMATCH
;
7753 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7755 else if (*strIn
== ',' || iswspace(*strIn
))
7757 if (*strIn
== ',' && !strIn
[1])
7758 hRet
= DISP_E_TYPEMISMATCH
;
7762 hRet
= DISP_E_TYPEMISMATCH
;
7767 if (!dp
.dwCount
|| dp
.dwCount
> 6 ||
7768 (dp
.dwCount
== 1 && !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7769 hRet
= DISP_E_TYPEMISMATCH
;
7771 if (SUCCEEDED(hRet
))
7774 DWORD dwOffset
= 0; /* Start of date fields in dp.dwValues */
7776 st
.wDayOfWeek
= st
.wHour
= st
.wMinute
= st
.wSecond
= st
.wMilliseconds
= 0;
7778 /* Figure out which numbers correspond to which fields.
7780 * This switch statement works based on the fact that native interprets any
7781 * fields that are not joined with a time separator ('.' or ':') as date
7782 * fields. Thus we construct a value from 0-32 where each set bit indicates
7783 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7784 * For valid permutations, we set dwOffset to point to the first date field
7785 * and shorten dp.dwCount by the number of time fields found. The real
7786 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7787 * each date number must represent in the context of iDate.
7789 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7791 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7793 case 0x1: /* TT TTDD TTDDD */
7794 if (dp
.dwCount
> 3 &&
7795 ((dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) ||
7796 (dp
.dwFlags
[4] & (DP_AM
|DP_PM
))))
7797 hRet
= DISP_E_TYPEMISMATCH
;
7798 else if (dp
.dwCount
!= 2 && dp
.dwCount
!= 4 && dp
.dwCount
!= 5)
7799 hRet
= DISP_E_TYPEMISMATCH
;
7800 st
.wHour
= dp
.dwValues
[0];
7801 st
.wMinute
= dp
.dwValues
[1];
7806 case 0x3: /* TTT TTTDD TTTDDD */
7807 if (dp
.dwCount
> 4 &&
7808 ((dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[4] & (DP_AM
|DP_PM
)) ||
7809 (dp
.dwFlags
[5] & (DP_AM
|DP_PM
))))
7810 hRet
= DISP_E_TYPEMISMATCH
;
7811 else if (dp
.dwCount
!= 3 && dp
.dwCount
!= 5 && dp
.dwCount
!= 6)
7812 hRet
= DISP_E_TYPEMISMATCH
;
7813 st
.wHour
= dp
.dwValues
[0];
7814 st
.wMinute
= dp
.dwValues
[1];
7815 st
.wSecond
= dp
.dwValues
[2];
7820 case 0x4: /* DDTT */
7821 if (dp
.dwCount
!= 4 ||
7822 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7823 hRet
= DISP_E_TYPEMISMATCH
;
7825 st
.wHour
= dp
.dwValues
[2];
7826 st
.wMinute
= dp
.dwValues
[3];
7830 case 0x0: /* T DD DDD TDDD TDDD */
7831 if (dp
.dwCount
== 1 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7833 st
.wHour
= dp
.dwValues
[0]; /* T */
7837 else if (dp
.dwCount
> 4 || (dp
.dwCount
< 3 && dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7839 hRet
= DISP_E_TYPEMISMATCH
;
7841 else if (dp
.dwCount
== 3)
7843 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDD */
7846 st
.wHour
= dp
.dwValues
[0];
7850 if (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) /* DDT */
7853 st
.wHour
= dp
.dwValues
[2];
7856 else if (dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7857 hRet
= DISP_E_TYPEMISMATCH
;
7859 else if (dp
.dwCount
== 4)
7862 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDDD */
7864 st
.wHour
= dp
.dwValues
[0];
7867 else if (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) /* DDDT */
7869 st
.wHour
= dp
.dwValues
[3];
7872 hRet
= DISP_E_TYPEMISMATCH
;
7875 /* .. fall through .. */
7877 case 0x8: /* DDDTT */
7878 if ((dp
.dwCount
== 2 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
))) ||
7879 (dp
.dwCount
== 5 && ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) ||
7880 (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))) ||
7881 dp
.dwCount
== 4 || dp
.dwCount
== 6)
7882 hRet
= DISP_E_TYPEMISMATCH
;
7883 st
.wHour
= dp
.dwValues
[3];
7884 st
.wMinute
= dp
.dwValues
[4];
7885 if (dp
.dwCount
== 5)
7889 case 0xC: /* DDTTT */
7890 if (dp
.dwCount
!= 5 ||
7891 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7892 hRet
= DISP_E_TYPEMISMATCH
;
7893 st
.wHour
= dp
.dwValues
[2];
7894 st
.wMinute
= dp
.dwValues
[3];
7895 st
.wSecond
= dp
.dwValues
[4];
7899 case 0x18: /* DDDTTT */
7900 if ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) ||
7901 (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))
7902 hRet
= DISP_E_TYPEMISMATCH
;
7903 st
.wHour
= dp
.dwValues
[3];
7904 st
.wMinute
= dp
.dwValues
[4];
7905 st
.wSecond
= dp
.dwValues
[5];
7910 hRet
= DISP_E_TYPEMISMATCH
;
7914 if (SUCCEEDED(hRet
))
7916 hRet
= VARIANT_MakeDate(&dp
, iDate
, dwOffset
, &st
);
7918 if (dwFlags
& VAR_TIMEVALUEONLY
)
7924 else if (dwFlags
& VAR_DATEVALUEONLY
)
7925 st
.wHour
= st
.wMinute
= st
.wSecond
= 0;
7927 /* Finally, convert the value to a VT_DATE */
7928 if (SUCCEEDED(hRet
))
7929 hRet
= SystemTimeToVariantTime(&st
, pdateOut
) ? S_OK
: DISP_E_TYPEMISMATCH
;
7933 for (i
= 0; i
< ARRAY_SIZE(tokens
); i
++)
7934 SysFreeString(tokens
[i
]);
7938 /******************************************************************************
7939 * VarDateFromI1 (OLEAUT32.221)
7941 * Convert a VT_I1 to a VT_DATE.
7945 * pdateOut [O] Destination
7950 HRESULT WINAPI
VarDateFromI1(signed char cIn
, DATE
* pdateOut
)
7952 return VarR8FromI1(cIn
, pdateOut
);
7955 /******************************************************************************
7956 * VarDateFromUI2 (OLEAUT32.222)
7958 * Convert a VT_UI2 to a VT_DATE.
7962 * pdateOut [O] Destination
7967 HRESULT WINAPI
VarDateFromUI2(USHORT uiIn
, DATE
* pdateOut
)
7969 return VarR8FromUI2(uiIn
, pdateOut
);
7972 /******************************************************************************
7973 * VarDateFromUI4 (OLEAUT32.223)
7975 * Convert a VT_UI4 to a VT_DATE.
7979 * pdateOut [O] Destination
7984 HRESULT WINAPI
VarDateFromUI4(ULONG ulIn
, DATE
* pdateOut
)
7986 return VarDateFromR8(ulIn
, pdateOut
);
7989 /**********************************************************************
7990 * VarDateFromDec (OLEAUT32.224)
7992 * Convert a VT_DECIMAL to a VT_DATE.
7996 * pdateOut [O] Destination
8001 HRESULT WINAPI
VarDateFromDec(DECIMAL
*pdecIn
, DATE
* pdateOut
)
8003 return VarR8FromDec(pdecIn
, pdateOut
);
8006 /******************************************************************************
8007 * VarDateFromI8 (OLEAUT32.364)
8009 * Convert a VT_I8 to a VT_DATE.
8013 * pdateOut [O] Destination
8017 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8019 HRESULT WINAPI
VarDateFromI8(LONG64 llIn
, DATE
* pdateOut
)
8021 if (llIn
< DATE_MIN
|| llIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
8022 *pdateOut
= (DATE
)llIn
;
8026 /******************************************************************************
8027 * VarDateFromUI8 (OLEAUT32.365)
8029 * Convert a VT_UI8 to a VT_DATE.
8033 * pdateOut [O] Destination
8037 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8039 HRESULT WINAPI
VarDateFromUI8(ULONG64 ullIn
, DATE
* pdateOut
)
8041 if (ullIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
8042 *pdateOut
= (DATE
)ullIn
;