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 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(variant
);
33 extern HMODULE hProxyDll
;
35 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
36 #define CY_MULTIPLIER_F 10000.0
37 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
38 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
40 /* Copy data from one variant to another. */
41 static inline void VARIANT_CopyData(const VARIANT
*srcVar
, VARTYPE vt
, void *pOut
)
46 case VT_UI1
: memcpy(pOut
, &V_UI1(srcVar
), sizeof(BYTE
)); break;
49 case VT_UI2
: memcpy(pOut
, &V_UI2(srcVar
), sizeof(SHORT
)); break;
54 case VT_UI4
: memcpy(pOut
, &V_UI4(srcVar
), sizeof (LONG
)); break;
59 case VT_UI8
: memcpy(pOut
, &V_UI8(srcVar
), sizeof (LONG64
)); break;
60 case VT_INT_PTR
: memcpy(pOut
, &V_INT_PTR(srcVar
), sizeof (INT_PTR
)); break;
61 case VT_DECIMAL
: memcpy(pOut
, &V_DECIMAL(srcVar
), sizeof (DECIMAL
)); break;
62 case VT_BSTR
: memcpy(pOut
, &V_BSTR(srcVar
), sizeof(BSTR
)); break;
64 FIXME("VT_ type %d unhandled, please report!\n", vt
);
68 /* Macro to inline conversion from a float or double to any integer type,
69 * rounding according to the 'dutch' convention.
71 #define VARIANT_DutchRound(typ, value, res) do { \
72 double whole = value < 0 ? ceil(value) : floor(value); \
73 double fract = value - whole; \
74 if (fract > 0.5) res = (typ)whole + (typ)1; \
75 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
76 else if (fract >= 0.0) res = (typ)whole; \
77 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
78 else if (fract > -0.5) res = (typ)whole; \
79 else res = (typ)whole - (typ)1; \
83 /* Coerce VT_BSTR to a numeric type */
84 static HRESULT
VARIANT_NumberFromBstr(const OLECHAR
* pStrIn
, LCID lcid
, ULONG ulFlags
,
85 void* pOut
, VARTYPE vt
)
92 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
93 np
.cDig
= ARRAY_SIZE(rgb
);
94 np
.dwInFlags
= NUMPRS_STD
;
96 hRet
= VarParseNumFromStr(pStrIn
, lcid
, ulFlags
, &np
, rgb
);
100 /* 1 << vt gives us the VTBIT constant for the destination number type */
101 hRet
= VarNumFromParseNum(&np
, rgb
, 1 << vt
, &dstVar
);
103 VARIANT_CopyData(&dstVar
, vt
, pOut
);
108 /* Coerce VT_DISPATCH to another type */
109 static HRESULT
VARIANT_FromDisp(IDispatch
* pdispIn
, LCID lcid
, void* pOut
,
110 VARTYPE vt
, DWORD dwFlags
)
112 static DISPPARAMS emptyParams
= { NULL
, NULL
, 0, 0 };
113 VARIANTARG srcVar
, dstVar
;
117 return DISP_E_BADVARTYPE
;
119 /* Get the default 'value' property from the IDispatch */
120 VariantInit(&srcVar
);
121 hRet
= IDispatch_Invoke(pdispIn
, DISPID_VALUE
, &IID_NULL
, lcid
, DISPATCH_PROPERTYGET
,
122 &emptyParams
, &srcVar
, NULL
, NULL
);
126 /* Convert the property to the requested type */
127 VariantInit(&dstVar
);
128 hRet
= VariantChangeTypeEx(&dstVar
, &srcVar
, lcid
, dwFlags
, vt
);
129 VariantClear(&srcVar
);
132 VARIANT_CopyData(&dstVar
, vt
, pOut
);
135 hRet
= DISP_E_TYPEMISMATCH
;
139 /* Inline return type */
140 #define RETTYP static inline HRESULT
143 /* Simple compiler cast from one type to another */
144 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
145 *out = in; return S_OK; }
147 /* Compiler cast where input cannot be negative */
148 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
149 if (in < 0) { return DISP_E_OVERFLOW; } *out = in; return S_OK; }
151 /* Compiler cast where input cannot be > some number */
152 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
153 if (in > (dest)tst) { return DISP_E_OVERFLOW; } *out = in; return S_OK; }
155 /* Compiler cast where input cannot be < some number or >= some other number */
156 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
157 if (in < (dest)lo || in > hi) { return DISP_E_OVERFLOW; } *out = in; return S_OK; }
160 POSTST(signed char, BYTE
, VarI1FromUI1
, I1_MAX
)
161 BOTHTST(signed char, SHORT
, VarI1FromI2
, I1_MIN
, I1_MAX
)
162 BOTHTST(signed char, LONG
, VarI1FromI4
, I1_MIN
, I1_MAX
)
163 SIMPLE(signed char, VARIANT_BOOL
, VarI1FromBool
)
164 POSTST(signed char, USHORT
, VarI1FromUI2
, I1_MAX
)
165 POSTST(signed char, ULONG
, VarI1FromUI4
, I1_MAX
)
166 BOTHTST(signed char, LONG64
, VarI1FromI8
, I1_MIN
, I1_MAX
)
167 POSTST(signed char, ULONG64
, VarI1FromUI8
, I1_MAX
)
170 BOTHTST(BYTE
, SHORT
, VarUI1FromI2
, UI1_MIN
, UI1_MAX
)
171 SIMPLE(BYTE
, VARIANT_BOOL
, VarUI1FromBool
)
172 NEGTST(BYTE
, signed char, VarUI1FromI1
)
173 POSTST(BYTE
, USHORT
, VarUI1FromUI2
, UI1_MAX
)
174 BOTHTST(BYTE
, LONG
, VarUI1FromI4
, UI1_MIN
, UI1_MAX
)
175 POSTST(BYTE
, ULONG
, VarUI1FromUI4
, UI1_MAX
)
176 BOTHTST(BYTE
, LONG64
, VarUI1FromI8
, UI1_MIN
, UI1_MAX
)
177 POSTST(BYTE
, ULONG64
, VarUI1FromUI8
, UI1_MAX
)
180 SIMPLE(SHORT
, BYTE
, VarI2FromUI1
)
181 BOTHTST(SHORT
, LONG
, VarI2FromI4
, I2_MIN
, I2_MAX
)
182 SIMPLE(SHORT
, VARIANT_BOOL
, VarI2FromBool
)
183 SIMPLE(SHORT
, signed char, VarI2FromI1
)
184 POSTST(SHORT
, USHORT
, VarI2FromUI2
, I2_MAX
)
185 POSTST(SHORT
, ULONG
, VarI2FromUI4
, I2_MAX
)
186 BOTHTST(SHORT
, LONG64
, VarI2FromI8
, I2_MIN
, I2_MAX
)
187 POSTST(SHORT
, ULONG64
, VarI2FromUI8
, I2_MAX
)
190 SIMPLE(USHORT
, BYTE
, VarUI2FromUI1
)
191 NEGTST(USHORT
, SHORT
, VarUI2FromI2
)
192 BOTHTST(USHORT
, LONG
, VarUI2FromI4
, UI2_MIN
, UI2_MAX
)
193 SIMPLE(USHORT
, VARIANT_BOOL
, VarUI2FromBool
)
194 NEGTST(USHORT
, signed char, VarUI2FromI1
)
195 POSTST(USHORT
, ULONG
, VarUI2FromUI4
, UI2_MAX
)
196 BOTHTST(USHORT
, LONG64
, VarUI2FromI8
, UI2_MIN
, UI2_MAX
)
197 POSTST(USHORT
, ULONG64
, VarUI2FromUI8
, UI2_MAX
)
200 SIMPLE(LONG
, BYTE
, VarI4FromUI1
)
201 SIMPLE(LONG
, SHORT
, VarI4FromI2
)
202 SIMPLE(LONG
, VARIANT_BOOL
, VarI4FromBool
)
203 SIMPLE(LONG
, signed char, VarI4FromI1
)
204 SIMPLE(LONG
, USHORT
, VarI4FromUI2
)
205 POSTST(LONG
, ULONG
, VarI4FromUI4
, I4_MAX
)
206 BOTHTST(LONG
, LONG64
, VarI4FromI8
, I4_MIN
, I4_MAX
)
207 POSTST(LONG
, ULONG64
, VarI4FromUI8
, I4_MAX
)
210 SIMPLE(ULONG
, BYTE
, VarUI4FromUI1
)
211 NEGTST(ULONG
, SHORT
, VarUI4FromI2
)
212 NEGTST(ULONG
, LONG
, VarUI4FromI4
)
213 SIMPLE(ULONG
, VARIANT_BOOL
, VarUI4FromBool
)
214 NEGTST(ULONG
, signed char, VarUI4FromI1
)
215 SIMPLE(ULONG
, USHORT
, VarUI4FromUI2
)
216 BOTHTST(ULONG
, LONG64
, VarUI4FromI8
, UI4_MIN
, UI4_MAX
)
217 POSTST(ULONG
, ULONG64
, VarUI4FromUI8
, UI4_MAX
)
220 SIMPLE(LONG64
, BYTE
, VarI8FromUI1
)
221 SIMPLE(LONG64
, SHORT
, VarI8FromI2
)
222 SIMPLE(LONG64
, signed char, VarI8FromI1
)
223 SIMPLE(LONG64
, USHORT
, VarI8FromUI2
)
224 SIMPLE(LONG64
, ULONG
, VarI8FromUI4
)
225 POSTST(LONG64
, ULONG64
, VarI8FromUI8
, I8_MAX
)
228 SIMPLE(ULONG64
, BYTE
, VarUI8FromUI1
)
229 NEGTST(ULONG64
, SHORT
, VarUI8FromI2
)
230 NEGTST(ULONG64
, signed char, VarUI8FromI1
)
231 SIMPLE(ULONG64
, USHORT
, VarUI8FromUI2
)
232 SIMPLE(ULONG64
, ULONG
, VarUI8FromUI4
)
233 NEGTST(ULONG64
, LONG64
, VarUI8FromI8
)
236 SIMPLE(float, BYTE
, VarR4FromUI1
)
237 SIMPLE(float, SHORT
, VarR4FromI2
)
238 SIMPLE(float, signed char, VarR4FromI1
)
239 SIMPLE(float, USHORT
, VarR4FromUI2
)
240 SIMPLE(float, LONG
, VarR4FromI4
)
241 SIMPLE(float, ULONG
, VarR4FromUI4
)
242 SIMPLE(float, LONG64
, VarR4FromI8
)
243 SIMPLE(float, ULONG64
, VarR4FromUI8
)
246 SIMPLE(double, BYTE
, VarR8FromUI1
)
247 SIMPLE(double, SHORT
, VarR8FromI2
)
248 SIMPLE(double, float, VarR8FromR4
)
249 RETTYP
_VarR8FromCy(CY i
, double* o
) { *o
= (double)i
.int64
/ CY_MULTIPLIER_F
; return S_OK
; }
250 SIMPLE(double, DATE
, VarR8FromDate
)
251 SIMPLE(double, signed char, VarR8FromI1
)
252 SIMPLE(double, USHORT
, VarR8FromUI2
)
253 SIMPLE(double, LONG
, VarR8FromI4
)
254 SIMPLE(double, ULONG
, VarR8FromUI4
)
255 SIMPLE(double, LONG64
, VarR8FromI8
)
256 SIMPLE(double, ULONG64
, VarR8FromUI8
)
262 /************************************************************************
263 * VarI1FromUI1 (OLEAUT32.244)
265 * Convert a VT_UI1 to a VT_I1.
269 * pcOut [O] Destination
273 * Failure: E_INVALIDARG, if the source value is invalid
274 * DISP_E_OVERFLOW, if the value will not fit in the destination
276 HRESULT WINAPI
VarI1FromUI1(BYTE bIn
, signed char* pcOut
)
278 return _VarI1FromUI1(bIn
, pcOut
);
281 /************************************************************************
282 * VarI1FromI2 (OLEAUT32.245)
284 * Convert a VT_I2 to a VT_I1.
288 * pcOut [O] Destination
292 * Failure: E_INVALIDARG, if the source value is invalid
293 * DISP_E_OVERFLOW, if the value will not fit in the destination
295 HRESULT WINAPI
VarI1FromI2(SHORT sIn
, signed char* pcOut
)
297 return _VarI1FromI2(sIn
, pcOut
);
300 /************************************************************************
301 * VarI1FromI4 (OLEAUT32.246)
303 * Convert a VT_I4 to a VT_I1.
307 * pcOut [O] Destination
311 * Failure: E_INVALIDARG, if the source value is invalid
312 * DISP_E_OVERFLOW, if the value will not fit in the destination
314 HRESULT WINAPI
VarI1FromI4(LONG iIn
, signed char* pcOut
)
316 return _VarI1FromI4(iIn
, pcOut
);
319 /************************************************************************
320 * VarI1FromR4 (OLEAUT32.247)
322 * Convert a VT_R4 to a VT_I1.
326 * pcOut [O] Destination
330 * Failure: E_INVALIDARG, if the source value is invalid
331 * DISP_E_OVERFLOW, if the value will not fit in the destination
333 HRESULT WINAPI
VarI1FromR4(FLOAT fltIn
, signed char* pcOut
)
335 return VarI1FromR8(fltIn
, pcOut
);
338 /************************************************************************
339 * VarI1FromR8 (OLEAUT32.248)
341 * Convert a VT_R8 to a VT_I1.
345 * pcOut [O] Destination
349 * Failure: E_INVALIDARG, if the source value is invalid
350 * DISP_E_OVERFLOW, if the value will not fit in the destination
353 * See VarI8FromR8() for details concerning rounding.
355 HRESULT WINAPI
VarI1FromR8(double dblIn
, signed char* pcOut
)
357 if (dblIn
< I1_MIN
- 0.5 || dblIn
>= I1_MAX
+ 0.5)
358 return DISP_E_OVERFLOW
;
359 VARIANT_DutchRound(CHAR
, dblIn
, *pcOut
);
363 /************************************************************************
364 * VarI1FromDate (OLEAUT32.249)
366 * Convert a VT_DATE to a VT_I1.
370 * pcOut [O] Destination
374 * Failure: E_INVALIDARG, if the source value is invalid
375 * DISP_E_OVERFLOW, if the value will not fit in the destination
377 HRESULT WINAPI
VarI1FromDate(DATE dateIn
, signed char* pcOut
)
379 return VarI1FromR8(dateIn
, pcOut
);
382 /************************************************************************
383 * VarI1FromCy (OLEAUT32.250)
385 * Convert a VT_CY to a VT_I1.
389 * pcOut [O] Destination
393 * Failure: E_INVALIDARG, if the source value is invalid
394 * DISP_E_OVERFLOW, if the value will not fit in the destination
396 HRESULT WINAPI
VarI1FromCy(CY cyIn
, signed char* pcOut
)
400 VarI4FromCy(cyIn
, &i
);
401 return _VarI1FromI4(i
, pcOut
);
404 /************************************************************************
405 * VarI1FromStr (OLEAUT32.251)
407 * Convert a VT_BSTR to a VT_I1.
411 * lcid [I] LCID for the conversion
412 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
413 * pcOut [O] Destination
417 * Failure: E_INVALIDARG, if the source value is invalid
418 * DISP_E_OVERFLOW, if the value will not fit in the destination
419 * DISP_E_TYPEMISMATCH, if the type cannot be converted
421 HRESULT WINAPI
VarI1FromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, signed char* pcOut
)
423 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pcOut
, VT_I1
);
426 /************************************************************************
427 * VarI1FromDisp (OLEAUT32.252)
429 * Convert a VT_DISPATCH to a VT_I1.
433 * lcid [I] LCID for conversion
434 * pcOut [O] Destination
438 * Failure: E_INVALIDARG, if the source value is invalid
439 * DISP_E_OVERFLOW, if the value will not fit in the destination
440 * DISP_E_TYPEMISMATCH, if the type cannot be converted
442 HRESULT WINAPI
VarI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, signed char* pcOut
)
444 return VARIANT_FromDisp(pdispIn
, lcid
, pcOut
, VT_I1
, 0);
447 /************************************************************************
448 * VarI1FromBool (OLEAUT32.253)
450 * Convert a VT_BOOL to a VT_I1.
454 * pcOut [O] Destination
459 HRESULT WINAPI
VarI1FromBool(VARIANT_BOOL boolIn
, signed char* pcOut
)
461 return _VarI1FromBool(boolIn
, pcOut
);
464 /************************************************************************
465 * VarI1FromUI2 (OLEAUT32.254)
467 * Convert a VT_UI2 to a VT_I1.
471 * pcOut [O] Destination
475 * Failure: E_INVALIDARG, if the source value is invalid
476 * DISP_E_OVERFLOW, if the value will not fit in the destination
478 HRESULT WINAPI
VarI1FromUI2(USHORT usIn
, signed char* pcOut
)
480 return _VarI1FromUI2(usIn
, pcOut
);
483 /************************************************************************
484 * VarI1FromUI4 (OLEAUT32.255)
486 * Convert a VT_UI4 to a VT_I1.
490 * pcOut [O] Destination
494 * Failure: E_INVALIDARG, if the source value is invalid
495 * DISP_E_OVERFLOW, if the value will not fit in the destination
496 * DISP_E_TYPEMISMATCH, if the type cannot be converted
498 HRESULT WINAPI
VarI1FromUI4(ULONG ulIn
, signed char* pcOut
)
500 return _VarI1FromUI4(ulIn
, pcOut
);
503 /************************************************************************
504 * VarI1FromDec (OLEAUT32.256)
506 * Convert a VT_DECIMAL to a VT_I1.
510 * pcOut [O] Destination
514 * Failure: E_INVALIDARG, if the source value is invalid
515 * DISP_E_OVERFLOW, if the value will not fit in the destination
517 HRESULT WINAPI
VarI1FromDec(const DECIMAL
*pdecIn
, signed char* pcOut
)
522 hRet
= VarI8FromDec(pdecIn
, &i64
);
525 hRet
= _VarI1FromI8(i64
, pcOut
);
529 /************************************************************************
530 * VarI1FromI8 (OLEAUT32.376)
532 * Convert a VT_I8 to a VT_I1.
536 * pcOut [O] Destination
540 * Failure: E_INVALIDARG, if the source value is invalid
541 * DISP_E_OVERFLOW, if the value will not fit in the destination
543 HRESULT WINAPI
VarI1FromI8(LONG64 llIn
, signed char* pcOut
)
545 return _VarI1FromI8(llIn
, pcOut
);
548 /************************************************************************
549 * VarI1FromUI8 (OLEAUT32.377)
551 * Convert a VT_UI8 to a VT_I1.
555 * pcOut [O] Destination
559 * Failure: E_INVALIDARG, if the source value is invalid
560 * DISP_E_OVERFLOW, if the value will not fit in the destination
562 HRESULT WINAPI
VarI1FromUI8(ULONG64 ullIn
, signed char* pcOut
)
564 return _VarI1FromUI8(ullIn
, pcOut
);
570 /************************************************************************
571 * VarUI1FromI2 (OLEAUT32.130)
573 * Convert a VT_I2 to a VT_UI1.
577 * pbOut [O] Destination
581 * Failure: E_INVALIDARG, if the source value is invalid
582 * DISP_E_OVERFLOW, if the value will not fit in the destination
584 HRESULT WINAPI
VarUI1FromI2(SHORT sIn
, BYTE
* pbOut
)
586 return _VarUI1FromI2(sIn
, pbOut
);
589 /************************************************************************
590 * VarUI1FromI4 (OLEAUT32.131)
592 * Convert a VT_I4 to a VT_UI1.
596 * pbOut [O] Destination
600 * Failure: E_INVALIDARG, if the source value is invalid
601 * DISP_E_OVERFLOW, if the value will not fit in the destination
603 HRESULT WINAPI
VarUI1FromI4(LONG iIn
, BYTE
* pbOut
)
605 return _VarUI1FromI4(iIn
, pbOut
);
608 /************************************************************************
609 * VarUI1FromR4 (OLEAUT32.132)
611 * Convert a VT_R4 to a VT_UI1.
615 * pbOut [O] Destination
619 * Failure: E_INVALIDARG, if the source value is invalid
620 * DISP_E_OVERFLOW, if the value will not fit in the destination
621 * DISP_E_TYPEMISMATCH, if the type cannot be converted
623 HRESULT WINAPI
VarUI1FromR4(FLOAT fltIn
, BYTE
* pbOut
)
625 return VarUI1FromR8(fltIn
, pbOut
);
628 /************************************************************************
629 * VarUI1FromR8 (OLEAUT32.133)
631 * Convert a VT_R8 to a VT_UI1.
635 * pbOut [O] Destination
639 * Failure: E_INVALIDARG, if the source value is invalid
640 * DISP_E_OVERFLOW, if the value will not fit in the destination
643 * See VarI8FromR8() for details concerning rounding.
645 HRESULT WINAPI
VarUI1FromR8(double dblIn
, BYTE
* pbOut
)
647 if (dblIn
< -0.5 || dblIn
>= UI1_MAX
+ 0.5)
648 return DISP_E_OVERFLOW
;
649 VARIANT_DutchRound(BYTE
, dblIn
, *pbOut
);
653 /************************************************************************
654 * VarUI1FromCy (OLEAUT32.134)
656 * Convert a VT_CY to a VT_UI1.
660 * pbOut [O] Destination
664 * Failure: E_INVALIDARG, if the source value is invalid
665 * DISP_E_OVERFLOW, if the value will not fit in the destination
668 * Negative values >= -5000 will be converted to 0.
670 HRESULT WINAPI
VarUI1FromCy(CY cyIn
, BYTE
* pbOut
)
672 ULONG i
= UI1_MAX
+ 1;
674 VarUI4FromCy(cyIn
, &i
);
675 return _VarUI1FromUI4(i
, pbOut
);
678 /************************************************************************
679 * VarUI1FromDate (OLEAUT32.135)
681 * Convert a VT_DATE to a VT_UI1.
685 * pbOut [O] Destination
689 * Failure: E_INVALIDARG, if the source value is invalid
690 * DISP_E_OVERFLOW, if the value will not fit in the destination
692 HRESULT WINAPI
VarUI1FromDate(DATE dateIn
, BYTE
* pbOut
)
694 return VarUI1FromR8(dateIn
, pbOut
);
697 /************************************************************************
698 * VarUI1FromStr (OLEAUT32.136)
700 * Convert a VT_BSTR to a VT_UI1.
704 * lcid [I] LCID for the conversion
705 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
706 * pbOut [O] Destination
710 * Failure: E_INVALIDARG, if the source value is invalid
711 * DISP_E_OVERFLOW, if the value will not fit in the destination
712 * DISP_E_TYPEMISMATCH, if the type cannot be converted
714 HRESULT WINAPI
VarUI1FromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, BYTE
* pbOut
)
716 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pbOut
, VT_UI1
);
719 /************************************************************************
720 * VarUI1FromDisp (OLEAUT32.137)
722 * Convert a VT_DISPATCH to a VT_UI1.
726 * lcid [I] LCID for conversion
727 * pbOut [O] Destination
731 * Failure: E_INVALIDARG, if the source value is invalid
732 * DISP_E_OVERFLOW, if the value will not fit in the destination
733 * DISP_E_TYPEMISMATCH, if the type cannot be converted
735 HRESULT WINAPI
VarUI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, BYTE
* pbOut
)
737 return VARIANT_FromDisp(pdispIn
, lcid
, pbOut
, VT_UI1
, 0);
740 /************************************************************************
741 * VarUI1FromBool (OLEAUT32.138)
743 * Convert a VT_BOOL to a VT_UI1.
747 * pbOut [O] Destination
752 HRESULT WINAPI
VarUI1FromBool(VARIANT_BOOL boolIn
, BYTE
* pbOut
)
754 return _VarUI1FromBool(boolIn
, pbOut
);
757 /************************************************************************
758 * VarUI1FromI1 (OLEAUT32.237)
760 * Convert a VT_I1 to a VT_UI1.
764 * pbOut [O] Destination
768 * Failure: E_INVALIDARG, if the source value is invalid
769 * DISP_E_OVERFLOW, if the value will not fit in the destination
771 HRESULT WINAPI
VarUI1FromI1(signed char cIn
, BYTE
* pbOut
)
773 return _VarUI1FromI1(cIn
, pbOut
);
776 /************************************************************************
777 * VarUI1FromUI2 (OLEAUT32.238)
779 * Convert a VT_UI2 to a VT_UI1.
783 * pbOut [O] Destination
787 * Failure: E_INVALIDARG, if the source value is invalid
788 * DISP_E_OVERFLOW, if the value will not fit in the destination
790 HRESULT WINAPI
VarUI1FromUI2(USHORT usIn
, BYTE
* pbOut
)
792 return _VarUI1FromUI2(usIn
, pbOut
);
795 /************************************************************************
796 * VarUI1FromUI4 (OLEAUT32.239)
798 * Convert a VT_UI4 to a VT_UI1.
802 * pbOut [O] Destination
806 * Failure: E_INVALIDARG, if the source value is invalid
807 * DISP_E_OVERFLOW, if the value will not fit in the destination
809 HRESULT WINAPI
VarUI1FromUI4(ULONG ulIn
, BYTE
* pbOut
)
811 return _VarUI1FromUI4(ulIn
, pbOut
);
814 /************************************************************************
815 * VarUI1FromDec (OLEAUT32.240)
817 * Convert a VT_DECIMAL to a VT_UI1.
821 * pbOut [O] Destination
825 * Failure: E_INVALIDARG, if the source value is invalid
826 * DISP_E_OVERFLOW, if the value will not fit in the destination
828 HRESULT WINAPI
VarUI1FromDec(const DECIMAL
*pdecIn
, BYTE
* pbOut
)
833 hRet
= VarI8FromDec(pdecIn
, &i64
);
836 hRet
= _VarUI1FromI8(i64
, pbOut
);
840 /************************************************************************
841 * VarUI1FromI8 (OLEAUT32.372)
843 * Convert a VT_I8 to a VT_UI1.
847 * pbOut [O] Destination
851 * Failure: E_INVALIDARG, if the source value is invalid
852 * DISP_E_OVERFLOW, if the value will not fit in the destination
854 HRESULT WINAPI
VarUI1FromI8(LONG64 llIn
, BYTE
* pbOut
)
856 return _VarUI1FromI8(llIn
, pbOut
);
859 /************************************************************************
860 * VarUI1FromUI8 (OLEAUT32.373)
862 * Convert a VT_UI8 to a VT_UI1.
866 * pbOut [O] Destination
870 * Failure: E_INVALIDARG, if the source value is invalid
871 * DISP_E_OVERFLOW, if the value will not fit in the destination
873 HRESULT WINAPI
VarUI1FromUI8(ULONG64 ullIn
, BYTE
* pbOut
)
875 return _VarUI1FromUI8(ullIn
, pbOut
);
882 /************************************************************************
883 * VarI2FromUI1 (OLEAUT32.48)
885 * Convert a VT_UI2 to a VT_I2.
889 * psOut [O] Destination
894 HRESULT WINAPI
VarI2FromUI1(BYTE bIn
, SHORT
* psOut
)
896 return _VarI2FromUI1(bIn
, psOut
);
899 /************************************************************************
900 * VarI2FromI4 (OLEAUT32.49)
902 * Convert a VT_I4 to a VT_I2.
906 * psOut [O] Destination
910 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
912 HRESULT WINAPI
VarI2FromI4(LONG iIn
, SHORT
* psOut
)
914 return _VarI2FromI4(iIn
, psOut
);
917 /************************************************************************
918 * VarI2FromR4 (OLEAUT32.50)
920 * Convert a VT_R4 to a VT_I2.
924 * psOut [O] Destination
928 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
930 HRESULT WINAPI
VarI2FromR4(FLOAT fltIn
, SHORT
* psOut
)
932 return VarI2FromR8(fltIn
, psOut
);
935 /************************************************************************
936 * VarI2FromR8 (OLEAUT32.51)
938 * Convert a VT_R8 to a VT_I2.
942 * psOut [O] Destination
946 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
949 * See VarI8FromR8() for details concerning rounding.
951 HRESULT WINAPI
VarI2FromR8(double dblIn
, SHORT
* psOut
)
953 if (dblIn
< I2_MIN
- 0.5 || dblIn
>= I2_MAX
+ 0.5)
954 return DISP_E_OVERFLOW
;
955 VARIANT_DutchRound(SHORT
, dblIn
, *psOut
);
959 /************************************************************************
960 * VarI2FromCy (OLEAUT32.52)
962 * Convert a VT_CY to a VT_I2.
966 * psOut [O] Destination
970 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
972 HRESULT WINAPI
VarI2FromCy(CY cyIn
, SHORT
* psOut
)
976 VarI4FromCy(cyIn
, &i
);
977 return _VarI2FromI4(i
, psOut
);
980 /************************************************************************
981 * VarI2FromDate (OLEAUT32.53)
983 * Convert a VT_DATE to a VT_I2.
987 * psOut [O] Destination
991 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
993 HRESULT WINAPI
VarI2FromDate(DATE dateIn
, SHORT
* psOut
)
995 return VarI2FromR8(dateIn
, psOut
);
998 /************************************************************************
999 * VarI2FromStr (OLEAUT32.54)
1001 * Convert a VT_BSTR to a VT_I2.
1005 * lcid [I] LCID for the conversion
1006 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1007 * psOut [O] Destination
1011 * Failure: E_INVALIDARG, if any parameter is invalid
1012 * DISP_E_OVERFLOW, if the value will not fit in the destination
1013 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1015 HRESULT WINAPI
VarI2FromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, SHORT
* psOut
)
1017 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, psOut
, VT_I2
);
1020 /************************************************************************
1021 * VarI2FromDisp (OLEAUT32.55)
1023 * Convert a VT_DISPATCH to a VT_I2.
1026 * pdispIn [I] Source
1027 * lcid [I] LCID for conversion
1028 * psOut [O] Destination
1032 * Failure: E_INVALIDARG, if pdispIn is invalid,
1033 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1034 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1036 HRESULT WINAPI
VarI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, SHORT
* psOut
)
1038 return VARIANT_FromDisp(pdispIn
, lcid
, psOut
, VT_I2
, 0);
1041 /************************************************************************
1042 * VarI2FromBool (OLEAUT32.56)
1044 * Convert a VT_BOOL to a VT_I2.
1048 * psOut [O] Destination
1053 HRESULT WINAPI
VarI2FromBool(VARIANT_BOOL boolIn
, SHORT
* psOut
)
1055 return _VarI2FromBool(boolIn
, psOut
);
1058 /************************************************************************
1059 * VarI2FromI1 (OLEAUT32.205)
1061 * Convert a VT_I1 to a VT_I2.
1065 * psOut [O] Destination
1070 HRESULT WINAPI
VarI2FromI1(signed char cIn
, SHORT
* psOut
)
1072 return _VarI2FromI1(cIn
, psOut
);
1075 /************************************************************************
1076 * VarI2FromUI2 (OLEAUT32.206)
1078 * Convert a VT_UI2 to a VT_I2.
1082 * psOut [O] Destination
1086 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1088 HRESULT WINAPI
VarI2FromUI2(USHORT usIn
, SHORT
* psOut
)
1090 return _VarI2FromUI2(usIn
, psOut
);
1093 /************************************************************************
1094 * VarI2FromUI4 (OLEAUT32.207)
1096 * Convert a VT_UI4 to a VT_I2.
1100 * psOut [O] Destination
1104 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1106 HRESULT WINAPI
VarI2FromUI4(ULONG ulIn
, SHORT
* psOut
)
1108 return _VarI2FromUI4(ulIn
, psOut
);
1111 /************************************************************************
1112 * VarI2FromDec (OLEAUT32.208)
1114 * Convert a VT_DECIMAL to a VT_I2.
1118 * psOut [O] Destination
1122 * Failure: E_INVALIDARG, if the source value is invalid
1123 * DISP_E_OVERFLOW, if the value will not fit in the destination
1125 HRESULT WINAPI
VarI2FromDec(const DECIMAL
*pdecIn
, SHORT
* psOut
)
1130 hRet
= VarI8FromDec(pdecIn
, &i64
);
1132 if (SUCCEEDED(hRet
))
1133 hRet
= _VarI2FromI8(i64
, psOut
);
1137 /************************************************************************
1138 * VarI2FromI8 (OLEAUT32.346)
1140 * Convert a VT_I8 to a VT_I2.
1144 * psOut [O] Destination
1148 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1150 HRESULT WINAPI
VarI2FromI8(LONG64 llIn
, SHORT
* psOut
)
1152 return _VarI2FromI8(llIn
, psOut
);
1155 /************************************************************************
1156 * VarI2FromUI8 (OLEAUT32.347)
1158 * Convert a VT_UI8 to a VT_I2.
1162 * psOut [O] Destination
1166 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1168 HRESULT WINAPI
VarI2FromUI8(ULONG64 ullIn
, SHORT
* psOut
)
1170 return _VarI2FromUI8(ullIn
, psOut
);
1176 /************************************************************************
1177 * VarUI2FromUI1 (OLEAUT32.257)
1179 * Convert a VT_UI1 to a VT_UI2.
1183 * pusOut [O] Destination
1188 HRESULT WINAPI
VarUI2FromUI1(BYTE bIn
, USHORT
* pusOut
)
1190 return _VarUI2FromUI1(bIn
, pusOut
);
1193 /************************************************************************
1194 * VarUI2FromI2 (OLEAUT32.258)
1196 * Convert a VT_I2 to a VT_UI2.
1200 * pusOut [O] Destination
1204 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1206 HRESULT WINAPI
VarUI2FromI2(SHORT sIn
, USHORT
* pusOut
)
1208 return _VarUI2FromI2(sIn
, pusOut
);
1211 /************************************************************************
1212 * VarUI2FromI4 (OLEAUT32.259)
1214 * Convert a VT_I4 to a VT_UI2.
1218 * pusOut [O] Destination
1222 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1224 HRESULT WINAPI
VarUI2FromI4(LONG iIn
, USHORT
* pusOut
)
1226 return _VarUI2FromI4(iIn
, pusOut
);
1229 /************************************************************************
1230 * VarUI2FromR4 (OLEAUT32.260)
1232 * Convert a VT_R4 to a VT_UI2.
1236 * pusOut [O] Destination
1240 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1242 HRESULT WINAPI
VarUI2FromR4(FLOAT fltIn
, USHORT
* pusOut
)
1244 return VarUI2FromR8(fltIn
, pusOut
);
1247 /************************************************************************
1248 * VarUI2FromR8 (OLEAUT32.261)
1250 * Convert a VT_R8 to a VT_UI2.
1254 * pusOut [O] Destination
1258 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1261 * See VarI8FromR8() for details concerning rounding.
1263 HRESULT WINAPI
VarUI2FromR8(double dblIn
, USHORT
* pusOut
)
1265 if (dblIn
< -0.5 || dblIn
>= UI2_MAX
+ 0.5)
1266 return DISP_E_OVERFLOW
;
1267 VARIANT_DutchRound(USHORT
, dblIn
, *pusOut
);
1271 /************************************************************************
1272 * VarUI2FromDate (OLEAUT32.262)
1274 * Convert a VT_DATE to a VT_UI2.
1278 * pusOut [O] Destination
1282 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1284 HRESULT WINAPI
VarUI2FromDate(DATE dateIn
, USHORT
* pusOut
)
1286 return VarUI2FromR8(dateIn
, pusOut
);
1289 /************************************************************************
1290 * VarUI2FromCy (OLEAUT32.263)
1292 * Convert a VT_CY to a VT_UI2.
1296 * pusOut [O] Destination
1300 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1303 * Negative values >= -5000 will be converted to 0.
1305 HRESULT WINAPI
VarUI2FromCy(CY cyIn
, USHORT
* pusOut
)
1307 ULONG i
= UI2_MAX
+ 1;
1309 VarUI4FromCy(cyIn
, &i
);
1310 return _VarUI2FromUI4(i
, pusOut
);
1313 /************************************************************************
1314 * VarUI2FromStr (OLEAUT32.264)
1316 * Convert a VT_BSTR to a VT_UI2.
1320 * lcid [I] LCID for the conversion
1321 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1322 * pusOut [O] Destination
1326 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1327 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1329 HRESULT WINAPI
VarUI2FromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, USHORT
* pusOut
)
1331 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pusOut
, VT_UI2
);
1334 /************************************************************************
1335 * VarUI2FromDisp (OLEAUT32.265)
1337 * Convert a VT_DISPATCH to a VT_UI2.
1340 * pdispIn [I] Source
1341 * lcid [I] LCID for conversion
1342 * pusOut [O] Destination
1346 * Failure: E_INVALIDARG, if the source value is invalid
1347 * DISP_E_OVERFLOW, if the value will not fit in the destination
1348 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1350 HRESULT WINAPI
VarUI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, USHORT
* pusOut
)
1352 return VARIANT_FromDisp(pdispIn
, lcid
, pusOut
, VT_UI2
, 0);
1355 /************************************************************************
1356 * VarUI2FromBool (OLEAUT32.266)
1358 * Convert a VT_BOOL to a VT_UI2.
1362 * pusOut [O] Destination
1367 HRESULT WINAPI
VarUI2FromBool(VARIANT_BOOL boolIn
, USHORT
* pusOut
)
1369 return _VarUI2FromBool(boolIn
, pusOut
);
1372 /************************************************************************
1373 * VarUI2FromI1 (OLEAUT32.267)
1375 * Convert a VT_I1 to a VT_UI2.
1379 * pusOut [O] Destination
1383 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1385 HRESULT WINAPI
VarUI2FromI1(signed char cIn
, USHORT
* pusOut
)
1387 return _VarUI2FromI1(cIn
, pusOut
);
1390 /************************************************************************
1391 * VarUI2FromUI4 (OLEAUT32.268)
1393 * Convert a VT_UI4 to a VT_UI2.
1397 * pusOut [O] Destination
1401 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1403 HRESULT WINAPI
VarUI2FromUI4(ULONG ulIn
, USHORT
* pusOut
)
1405 return _VarUI2FromUI4(ulIn
, pusOut
);
1408 /************************************************************************
1409 * VarUI2FromDec (OLEAUT32.269)
1411 * Convert a VT_DECIMAL to a VT_UI2.
1415 * pusOut [O] Destination
1419 * Failure: E_INVALIDARG, if the source value is invalid
1420 * DISP_E_OVERFLOW, if the value will not fit in the destination
1422 HRESULT WINAPI
VarUI2FromDec(const DECIMAL
*pdecIn
, USHORT
* pusOut
)
1427 hRet
= VarI8FromDec(pdecIn
, &i64
);
1429 if (SUCCEEDED(hRet
))
1430 hRet
= _VarUI2FromI8(i64
, pusOut
);
1434 /************************************************************************
1435 * VarUI2FromI8 (OLEAUT32.378)
1437 * Convert a VT_I8 to a VT_UI2.
1441 * pusOut [O] Destination
1445 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1447 HRESULT WINAPI
VarUI2FromI8(LONG64 llIn
, USHORT
* pusOut
)
1449 return _VarUI2FromI8(llIn
, pusOut
);
1452 /************************************************************************
1453 * VarUI2FromUI8 (OLEAUT32.379)
1455 * Convert a VT_UI8 to a VT_UI2.
1459 * pusOut [O] Destination
1463 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1465 HRESULT WINAPI
VarUI2FromUI8(ULONG64 ullIn
, USHORT
* pusOut
)
1467 return _VarUI2FromUI8(ullIn
, pusOut
);
1473 /************************************************************************
1474 * VarI4FromUI1 (OLEAUT32.58)
1476 * Convert a VT_UI1 to a VT_I4.
1480 * piOut [O] Destination
1485 HRESULT WINAPI
VarI4FromUI1(BYTE bIn
, LONG
*piOut
)
1487 return _VarI4FromUI1(bIn
, piOut
);
1490 /************************************************************************
1491 * VarI4FromI2 (OLEAUT32.59)
1493 * Convert a VT_I2 to a VT_I4.
1497 * piOut [O] Destination
1501 * Failure: E_INVALIDARG, if the source value is invalid
1502 * DISP_E_OVERFLOW, if the value will not fit in the destination
1504 HRESULT WINAPI
VarI4FromI2(SHORT sIn
, LONG
*piOut
)
1506 return _VarI4FromI2(sIn
, piOut
);
1509 /************************************************************************
1510 * VarI4FromR4 (OLEAUT32.60)
1512 * Convert a VT_R4 to a VT_I4.
1516 * piOut [O] Destination
1520 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1522 HRESULT WINAPI
VarI4FromR4(FLOAT fltIn
, LONG
*piOut
)
1524 return VarI4FromR8(fltIn
, piOut
);
1527 /************************************************************************
1528 * VarI4FromR8 (OLEAUT32.61)
1530 * Convert a VT_R8 to a VT_I4.
1534 * piOut [O] Destination
1538 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1541 * See VarI8FromR8() for details concerning rounding.
1543 HRESULT WINAPI
VarI4FromR8(double dblIn
, LONG
*piOut
)
1545 if (dblIn
< I4_MIN
- 0.5 || dblIn
>= I4_MAX
+ 0.5)
1546 return DISP_E_OVERFLOW
;
1547 VARIANT_DutchRound(LONG
, dblIn
, *piOut
);
1551 /************************************************************************
1552 * VarI4FromCy (OLEAUT32.62)
1554 * Convert a VT_CY to a VT_I4.
1558 * piOut [O] Destination
1562 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1564 HRESULT WINAPI
VarI4FromCy(CY cyIn
, LONG
*piOut
)
1566 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1567 return VarI4FromR8(d
, piOut
);
1570 /************************************************************************
1571 * VarI4FromDate (OLEAUT32.63)
1573 * Convert a VT_DATE to a VT_I4.
1577 * piOut [O] Destination
1581 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1583 HRESULT WINAPI
VarI4FromDate(DATE dateIn
, LONG
*piOut
)
1585 return VarI4FromR8(dateIn
, piOut
);
1588 /************************************************************************
1589 * VarI4FromStr (OLEAUT32.64)
1591 * Convert a VT_BSTR to a VT_I4.
1595 * lcid [I] LCID for the conversion
1596 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1597 * piOut [O] Destination
1601 * Failure: E_INVALIDARG, if any parameter is invalid
1602 * DISP_E_OVERFLOW, if the value will not fit in the destination
1603 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1605 HRESULT WINAPI
VarI4FromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG
*piOut
)
1607 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, piOut
, VT_I4
);
1610 /************************************************************************
1611 * VarI4FromDisp (OLEAUT32.65)
1613 * Convert a VT_DISPATCH to a VT_I4.
1616 * pdispIn [I] Source
1617 * lcid [I] LCID for conversion
1618 * piOut [O] Destination
1622 * Failure: E_INVALIDARG, if the source value is invalid
1623 * DISP_E_OVERFLOW, if the value will not fit in the destination
1624 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1626 HRESULT WINAPI
VarI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG
*piOut
)
1628 return VARIANT_FromDisp(pdispIn
, lcid
, piOut
, VT_I4
, 0);
1631 /************************************************************************
1632 * VarI4FromBool (OLEAUT32.66)
1634 * Convert a VT_BOOL to a VT_I4.
1638 * piOut [O] Destination
1643 HRESULT WINAPI
VarI4FromBool(VARIANT_BOOL boolIn
, LONG
*piOut
)
1645 return _VarI4FromBool(boolIn
, piOut
);
1648 /************************************************************************
1649 * VarI4FromI1 (OLEAUT32.209)
1651 * Convert a VT_I1 to a VT_I4.
1655 * piOut [O] Destination
1660 HRESULT WINAPI
VarI4FromI1(signed char cIn
, LONG
*piOut
)
1662 return _VarI4FromI1(cIn
, piOut
);
1665 /************************************************************************
1666 * VarI4FromUI2 (OLEAUT32.210)
1668 * Convert a VT_UI2 to a VT_I4.
1672 * piOut [O] Destination
1677 HRESULT WINAPI
VarI4FromUI2(USHORT usIn
, LONG
*piOut
)
1679 return _VarI4FromUI2(usIn
, piOut
);
1682 /************************************************************************
1683 * VarI4FromUI4 (OLEAUT32.211)
1685 * Convert a VT_UI4 to a VT_I4.
1689 * piOut [O] Destination
1693 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1695 HRESULT WINAPI
VarI4FromUI4(ULONG ulIn
, LONG
*piOut
)
1697 return _VarI4FromUI4(ulIn
, piOut
);
1700 /************************************************************************
1701 * VarI4FromDec (OLEAUT32.212)
1703 * Convert a VT_DECIMAL to a VT_I4.
1707 * piOut [O] Destination
1711 * Failure: E_INVALIDARG, if pdecIn is invalid
1712 * DISP_E_OVERFLOW, if the value will not fit in the destination
1714 HRESULT WINAPI
VarI4FromDec(const DECIMAL
*pdecIn
, LONG
*piOut
)
1719 hRet
= VarI8FromDec(pdecIn
, &i64
);
1721 if (SUCCEEDED(hRet
))
1722 hRet
= _VarI4FromI8(i64
, piOut
);
1726 /************************************************************************
1727 * VarI4FromI8 (OLEAUT32.348)
1729 * Convert a VT_I8 to a VT_I4.
1733 * piOut [O] Destination
1737 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1739 HRESULT WINAPI
VarI4FromI8(LONG64 llIn
, LONG
*piOut
)
1741 return _VarI4FromI8(llIn
, piOut
);
1744 /************************************************************************
1745 * VarI4FromUI8 (OLEAUT32.349)
1747 * Convert a VT_UI8 to a VT_I4.
1751 * piOut [O] Destination
1755 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1757 HRESULT WINAPI
VarI4FromUI8(ULONG64 ullIn
, LONG
*piOut
)
1759 return _VarI4FromUI8(ullIn
, piOut
);
1765 /************************************************************************
1766 * VarUI4FromUI1 (OLEAUT32.270)
1768 * Convert a VT_UI1 to a VT_UI4.
1772 * pulOut [O] Destination
1777 HRESULT WINAPI
VarUI4FromUI1(BYTE bIn
, ULONG
*pulOut
)
1779 return _VarUI4FromUI1(bIn
, pulOut
);
1782 /************************************************************************
1783 * VarUI4FromI2 (OLEAUT32.271)
1785 * Convert a VT_I2 to a VT_UI4.
1789 * pulOut [O] Destination
1793 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1795 HRESULT WINAPI
VarUI4FromI2(SHORT sIn
, ULONG
*pulOut
)
1797 return _VarUI4FromI2(sIn
, pulOut
);
1800 /************************************************************************
1801 * VarUI4FromI4 (OLEAUT32.272)
1803 * Convert a VT_I4 to a VT_UI4.
1807 * pulOut [O] Destination
1811 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1813 HRESULT WINAPI
VarUI4FromI4(LONG iIn
, ULONG
*pulOut
)
1815 return _VarUI4FromI4(iIn
, pulOut
);
1818 /************************************************************************
1819 * VarUI4FromR4 (OLEAUT32.273)
1821 * Convert a VT_R4 to a VT_UI4.
1825 * pulOut [O] Destination
1829 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1831 HRESULT WINAPI
VarUI4FromR4(FLOAT fltIn
, ULONG
*pulOut
)
1833 return VarUI4FromR8(fltIn
, pulOut
);
1836 /************************************************************************
1837 * VarUI4FromR8 (OLEAUT32.274)
1839 * Convert a VT_R8 to a VT_UI4.
1843 * pulOut [O] Destination
1847 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1850 * See VarI8FromR8() for details concerning rounding.
1852 HRESULT WINAPI
VarUI4FromR8(double dblIn
, ULONG
*pulOut
)
1854 if (dblIn
< -0.5 || dblIn
>= UI4_MAX
+ 0.5)
1855 return DISP_E_OVERFLOW
;
1856 VARIANT_DutchRound(ULONG
, dblIn
, *pulOut
);
1860 /************************************************************************
1861 * VarUI4FromDate (OLEAUT32.275)
1863 * Convert a VT_DATE to a VT_UI4.
1867 * pulOut [O] Destination
1871 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1873 HRESULT WINAPI
VarUI4FromDate(DATE dateIn
, ULONG
*pulOut
)
1875 return VarUI4FromR8(dateIn
, pulOut
);
1878 /************************************************************************
1879 * VarUI4FromCy (OLEAUT32.276)
1881 * Convert a VT_CY to a VT_UI4.
1885 * pulOut [O] Destination
1889 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1891 HRESULT WINAPI
VarUI4FromCy(CY cyIn
, ULONG
*pulOut
)
1893 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1894 return VarUI4FromR8(d
, pulOut
);
1897 /************************************************************************
1898 * VarUI4FromStr (OLEAUT32.277)
1900 * Convert a VT_BSTR to a VT_UI4.
1904 * lcid [I] LCID for the conversion
1905 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1906 * pulOut [O] Destination
1910 * Failure: E_INVALIDARG, if any parameter is invalid
1911 * DISP_E_OVERFLOW, if the value will not fit in the destination
1912 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1914 HRESULT WINAPI
VarUI4FromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG
*pulOut
)
1916 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pulOut
, VT_UI4
);
1919 /************************************************************************
1920 * VarUI4FromDisp (OLEAUT32.278)
1922 * Convert a VT_DISPATCH to a VT_UI4.
1925 * pdispIn [I] Source
1926 * lcid [I] LCID for conversion
1927 * pulOut [O] Destination
1931 * Failure: E_INVALIDARG, if the source value is invalid
1932 * DISP_E_OVERFLOW, if the value will not fit in the destination
1933 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1935 HRESULT WINAPI
VarUI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG
*pulOut
)
1937 return VARIANT_FromDisp(pdispIn
, lcid
, pulOut
, VT_UI4
, 0);
1940 /************************************************************************
1941 * VarUI4FromBool (OLEAUT32.279)
1943 * Convert a VT_BOOL to a VT_UI4.
1947 * pulOut [O] Destination
1952 HRESULT WINAPI
VarUI4FromBool(VARIANT_BOOL boolIn
, ULONG
*pulOut
)
1954 return _VarUI4FromBool(boolIn
, pulOut
);
1957 /************************************************************************
1958 * VarUI4FromI1 (OLEAUT32.280)
1960 * Convert a VT_I1 to a VT_UI4.
1964 * pulOut [O] Destination
1968 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1970 HRESULT WINAPI
VarUI4FromI1(signed char cIn
, ULONG
*pulOut
)
1972 return _VarUI4FromI1(cIn
, pulOut
);
1975 /************************************************************************
1976 * VarUI4FromUI2 (OLEAUT32.281)
1978 * Convert a VT_UI2 to a VT_UI4.
1982 * pulOut [O] Destination
1987 HRESULT WINAPI
VarUI4FromUI2(USHORT usIn
, ULONG
*pulOut
)
1989 return _VarUI4FromUI2(usIn
, pulOut
);
1992 /************************************************************************
1993 * VarUI4FromDec (OLEAUT32.282)
1995 * Convert a VT_DECIMAL to a VT_UI4.
1999 * pulOut [O] Destination
2003 * Failure: E_INVALIDARG, if pdecIn is invalid
2004 * DISP_E_OVERFLOW, if the value will not fit in the destination
2006 HRESULT WINAPI
VarUI4FromDec(const DECIMAL
*pdecIn
, ULONG
*pulOut
)
2011 hRet
= VarI8FromDec(pdecIn
, &i64
);
2013 if (SUCCEEDED(hRet
))
2014 hRet
= _VarUI4FromI8(i64
, pulOut
);
2018 /************************************************************************
2019 * VarUI4FromI8 (OLEAUT32.425)
2021 * Convert a VT_I8 to a VT_UI4.
2025 * pulOut [O] Destination
2029 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2031 HRESULT WINAPI
VarUI4FromI8(LONG64 llIn
, ULONG
*pulOut
)
2033 return _VarUI4FromI8(llIn
, pulOut
);
2036 /************************************************************************
2037 * VarUI4FromUI8 (OLEAUT32.426)
2039 * Convert a VT_UI8 to a VT_UI4.
2043 * pulOut [O] Destination
2047 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2049 HRESULT WINAPI
VarUI4FromUI8(ULONG64 ullIn
, ULONG
*pulOut
)
2051 return _VarUI4FromUI8(ullIn
, pulOut
);
2057 /************************************************************************
2058 * VarI8FromUI1 (OLEAUT32.333)
2060 * Convert a VT_UI1 to a VT_I8.
2064 * pi64Out [O] Destination
2069 HRESULT WINAPI
VarI8FromUI1(BYTE bIn
, LONG64
* pi64Out
)
2071 return _VarI8FromUI1(bIn
, pi64Out
);
2075 /************************************************************************
2076 * VarI8FromI2 (OLEAUT32.334)
2078 * Convert a VT_I2 to a VT_I8.
2082 * pi64Out [O] Destination
2087 HRESULT WINAPI
VarI8FromI2(SHORT sIn
, LONG64
* pi64Out
)
2089 return _VarI8FromI2(sIn
, pi64Out
);
2092 /************************************************************************
2093 * VarI8FromR4 (OLEAUT32.335)
2095 * Convert a VT_R4 to a VT_I8.
2099 * pi64Out [O] Destination
2103 * Failure: E_INVALIDARG, if the source value is invalid
2104 * DISP_E_OVERFLOW, if the value will not fit in the destination
2106 HRESULT WINAPI
VarI8FromR4(FLOAT fltIn
, LONG64
* pi64Out
)
2108 return VarI8FromR8(fltIn
, pi64Out
);
2111 /************************************************************************
2112 * VarI8FromR8 (OLEAUT32.336)
2114 * Convert a VT_R8 to a VT_I8.
2118 * pi64Out [O] Destination
2122 * Failure: E_INVALIDARG, if the source value is invalid
2123 * DISP_E_OVERFLOW, if the value will not fit in the destination
2126 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2127 * very high or low values will not be accurately converted.
2129 * Numbers are rounded using Dutch rounding, as follows:
2131 *| Fractional Part Sign Direction Example
2132 *| --------------- ---- --------- -------
2133 *| < 0.5 + Down 0.4 -> 0.0
2134 *| < 0.5 - Up -0.4 -> 0.0
2135 *| > 0.5 + Up 0.6 -> 1.0
2136 *| < 0.5 - Up -0.6 -> -1.0
2137 *| = 0.5 + Up/Down Down if even, Up if odd
2138 *| = 0.5 - Up/Down Up if even, Down if odd
2140 * This system is often used in supermarkets.
2142 HRESULT WINAPI
VarI8FromR8(double dblIn
, LONG64
* pi64Out
)
2144 if ( dblIn
< -4611686018427387904.0 || dblIn
>= 4611686018427387904.0)
2145 return DISP_E_OVERFLOW
;
2146 VARIANT_DutchRound(LONG64
, dblIn
, *pi64Out
);
2150 /************************************************************************
2151 * VarI8FromCy (OLEAUT32.337)
2153 * Convert a VT_CY to a VT_I8.
2157 * pi64Out [O] Destination
2163 * All negative numbers are rounded down by 1, including those that are
2164 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2165 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2168 HRESULT WINAPI
VarI8FromCy(CY cyIn
, LONG64
* pi64Out
)
2170 *pi64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2173 (*pi64Out
)--; /* Mimic Win32 bug */
2176 cyIn
.int64
-= *pi64Out
* CY_MULTIPLIER
; /* cyIn.Lo now holds fractional remainder */
2178 if (cyIn
.Lo
> CY_HALF
|| (cyIn
.Lo
== CY_HALF
&& (*pi64Out
& 0x1)))
2184 /************************************************************************
2185 * VarI8FromDate (OLEAUT32.338)
2187 * Convert a VT_DATE to a VT_I8.
2191 * pi64Out [O] Destination
2195 * Failure: E_INVALIDARG, if the source value is invalid
2196 * DISP_E_OVERFLOW, if the value will not fit in the destination
2197 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2199 HRESULT WINAPI
VarI8FromDate(DATE dateIn
, LONG64
* pi64Out
)
2201 return VarI8FromR8(dateIn
, pi64Out
);
2204 /************************************************************************
2205 * VarI8FromStr (OLEAUT32.339)
2207 * Convert a VT_BSTR to a VT_I8.
2211 * lcid [I] LCID for the conversion
2212 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2213 * pi64Out [O] Destination
2217 * Failure: E_INVALIDARG, if the source value is invalid
2218 * DISP_E_OVERFLOW, if the value will not fit in the destination
2219 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2221 HRESULT WINAPI
VarI8FromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG64
* pi64Out
)
2223 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pi64Out
, VT_I8
);
2226 /************************************************************************
2227 * VarI8FromDisp (OLEAUT32.340)
2229 * Convert a VT_DISPATCH to a VT_I8.
2232 * pdispIn [I] Source
2233 * lcid [I] LCID for conversion
2234 * pi64Out [O] Destination
2238 * Failure: E_INVALIDARG, if the source value is invalid
2239 * DISP_E_OVERFLOW, if the value will not fit in the destination
2240 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2242 HRESULT WINAPI
VarI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG64
* pi64Out
)
2244 return VARIANT_FromDisp(pdispIn
, lcid
, pi64Out
, VT_I8
, 0);
2247 /************************************************************************
2248 * VarI8FromBool (OLEAUT32.341)
2250 * Convert a VT_BOOL to a VT_I8.
2254 * pi64Out [O] Destination
2259 HRESULT WINAPI
VarI8FromBool(VARIANT_BOOL boolIn
, LONG64
* pi64Out
)
2261 return VarI8FromI2(boolIn
, pi64Out
);
2264 /************************************************************************
2265 * VarI8FromI1 (OLEAUT32.342)
2267 * Convert a VT_I1 to a VT_I8.
2271 * pi64Out [O] Destination
2276 HRESULT WINAPI
VarI8FromI1(signed char cIn
, LONG64
* pi64Out
)
2278 return _VarI8FromI1(cIn
, pi64Out
);
2281 /************************************************************************
2282 * VarI8FromUI2 (OLEAUT32.343)
2284 * Convert a VT_UI2 to a VT_I8.
2288 * pi64Out [O] Destination
2293 HRESULT WINAPI
VarI8FromUI2(USHORT usIn
, LONG64
* pi64Out
)
2295 return _VarI8FromUI2(usIn
, pi64Out
);
2298 /************************************************************************
2299 * VarI8FromUI4 (OLEAUT32.344)
2301 * Convert a VT_UI4 to a VT_I8.
2305 * pi64Out [O] Destination
2310 HRESULT WINAPI
VarI8FromUI4(ULONG ulIn
, LONG64
* pi64Out
)
2312 return _VarI8FromUI4(ulIn
, pi64Out
);
2315 /************************************************************************
2316 * VarI8FromDec (OLEAUT32.345)
2318 * Convert a VT_DECIMAL to a VT_I8.
2322 * pi64Out [O] Destination
2326 * Failure: E_INVALIDARG, if the source value is invalid
2327 * DISP_E_OVERFLOW, if the value will not fit in the destination
2329 HRESULT WINAPI
VarI8FromDec(const DECIMAL
*pdecIn
, LONG64
* pi64Out
)
2333 /* This decimal is just a 96 bit integer */
2334 if (pdecIn
->sign
& ~DECIMAL_NEG
)
2335 return E_INVALIDARG
;
2337 if (pdecIn
->Hi32
|| pdecIn
->Mid32
& 0x80000000)
2338 return DISP_E_OVERFLOW
;
2341 *pi64Out
= -pdecIn
->Lo64
;
2343 *pi64Out
= pdecIn
->Lo64
;
2348 /* Decimal contains a floating point number */
2352 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2353 if (SUCCEEDED(hRet
))
2354 hRet
= VarI8FromR8(dbl
, pi64Out
);
2359 /************************************************************************
2360 * VarI8FromUI8 (OLEAUT32.427)
2362 * Convert a VT_UI8 to a VT_I8.
2366 * pi64Out [O] Destination
2370 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2372 HRESULT WINAPI
VarI8FromUI8(ULONG64 ullIn
, LONG64
* pi64Out
)
2374 return _VarI8FromUI8(ullIn
, pi64Out
);
2380 /************************************************************************
2381 * VarUI8FromI8 (OLEAUT32.428)
2383 * Convert a VT_I8 to a VT_UI8.
2387 * pui64Out [O] Destination
2391 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2393 HRESULT WINAPI
VarUI8FromI8(LONG64 llIn
, ULONG64
* pui64Out
)
2395 return _VarUI8FromI8(llIn
, pui64Out
);
2398 /************************************************************************
2399 * VarUI8FromUI1 (OLEAUT32.429)
2401 * Convert a VT_UI1 to a VT_UI8.
2405 * pui64Out [O] Destination
2410 HRESULT WINAPI
VarUI8FromUI1(BYTE bIn
, ULONG64
* pui64Out
)
2412 return _VarUI8FromUI1(bIn
, pui64Out
);
2415 /************************************************************************
2416 * VarUI8FromI2 (OLEAUT32.430)
2418 * Convert a VT_I2 to a VT_UI8.
2422 * pui64Out [O] Destination
2427 HRESULT WINAPI
VarUI8FromI2(SHORT sIn
, ULONG64
* pui64Out
)
2429 return _VarUI8FromI2(sIn
, pui64Out
);
2432 /************************************************************************
2433 * VarUI8FromR4 (OLEAUT32.431)
2435 * Convert a VT_R4 to a VT_UI8.
2439 * pui64Out [O] Destination
2443 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2445 HRESULT WINAPI
VarUI8FromR4(FLOAT fltIn
, ULONG64
* pui64Out
)
2447 return VarUI8FromR8(fltIn
, pui64Out
);
2450 /************************************************************************
2451 * VarUI8FromR8 (OLEAUT32.432)
2453 * Convert a VT_R8 to a VT_UI8.
2457 * pui64Out [O] Destination
2461 * Failure: E_INVALIDARG, if the source value is invalid
2462 * DISP_E_OVERFLOW, if the value will not fit in the destination
2465 * See VarI8FromR8() for details concerning rounding.
2467 HRESULT WINAPI
VarUI8FromR8(double dblIn
, ULONG64
* pui64Out
)
2469 if (dblIn
< -0.5 || dblIn
> 1.844674407370955e19
)
2470 return DISP_E_OVERFLOW
;
2471 VARIANT_DutchRound(ULONG64
, dblIn
, *pui64Out
);
2475 /************************************************************************
2476 * VarUI8FromCy (OLEAUT32.433)
2478 * Convert a VT_CY to a VT_UI8.
2482 * pui64Out [O] Destination
2486 * Failure: E_INVALIDARG, if the source value is invalid
2487 * DISP_E_OVERFLOW, if the value will not fit in the destination
2490 * Negative values >= -5000 will be converted to 0.
2492 HRESULT WINAPI
VarUI8FromCy(CY cyIn
, ULONG64
* pui64Out
)
2496 if (cyIn
.int64
< -CY_HALF
)
2497 return DISP_E_OVERFLOW
;
2502 *pui64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2504 cyIn
.int64
-= *pui64Out
* CY_MULTIPLIER
; /* cyIn.Lo now holds fractional remainder */
2506 if (cyIn
.Lo
> CY_HALF
|| (cyIn
.Lo
== CY_HALF
&& (*pui64Out
& 0x1)))
2512 /************************************************************************
2513 * VarUI8FromDate (OLEAUT32.434)
2515 * Convert a VT_DATE to a VT_UI8.
2519 * pui64Out [O] Destination
2523 * Failure: E_INVALIDARG, if the source value is invalid
2524 * DISP_E_OVERFLOW, if the value will not fit in the destination
2525 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2527 HRESULT WINAPI
VarUI8FromDate(DATE dateIn
, ULONG64
* pui64Out
)
2529 return VarUI8FromR8(dateIn
, pui64Out
);
2532 /************************************************************************
2533 * VarUI8FromStr (OLEAUT32.435)
2535 * Convert a VT_BSTR to a VT_UI8.
2539 * lcid [I] LCID for the conversion
2540 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2541 * pui64Out [O] Destination
2545 * Failure: E_INVALIDARG, if the source value is invalid
2546 * DISP_E_OVERFLOW, if the value will not fit in the destination
2547 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2549 HRESULT WINAPI
VarUI8FromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG64
* pui64Out
)
2551 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pui64Out
, VT_UI8
);
2554 /************************************************************************
2555 * VarUI8FromDisp (OLEAUT32.436)
2557 * Convert a VT_DISPATCH to a VT_UI8.
2560 * pdispIn [I] Source
2561 * lcid [I] LCID for conversion
2562 * pui64Out [O] Destination
2566 * Failure: E_INVALIDARG, if the source value is invalid
2567 * DISP_E_OVERFLOW, if the value will not fit in the destination
2568 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2570 HRESULT WINAPI
VarUI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG64
* pui64Out
)
2572 return VARIANT_FromDisp(pdispIn
, lcid
, pui64Out
, VT_UI8
, 0);
2575 /************************************************************************
2576 * VarUI8FromBool (OLEAUT32.437)
2578 * Convert a VT_BOOL to a VT_UI8.
2582 * pui64Out [O] Destination
2586 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2588 HRESULT WINAPI
VarUI8FromBool(VARIANT_BOOL boolIn
, ULONG64
* pui64Out
)
2590 return VarI8FromI2(boolIn
, (LONG64
*)pui64Out
);
2592 /************************************************************************
2593 * VarUI8FromI1 (OLEAUT32.438)
2595 * Convert a VT_I1 to a VT_UI8.
2599 * pui64Out [O] Destination
2603 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2605 HRESULT WINAPI
VarUI8FromI1(signed char cIn
, ULONG64
* pui64Out
)
2607 return _VarUI8FromI1(cIn
, pui64Out
);
2610 /************************************************************************
2611 * VarUI8FromUI2 (OLEAUT32.439)
2613 * Convert a VT_UI2 to a VT_UI8.
2617 * pui64Out [O] Destination
2622 HRESULT WINAPI
VarUI8FromUI2(USHORT usIn
, ULONG64
* pui64Out
)
2624 return _VarUI8FromUI2(usIn
, pui64Out
);
2627 /************************************************************************
2628 * VarUI8FromUI4 (OLEAUT32.440)
2630 * Convert a VT_UI4 to a VT_UI8.
2634 * pui64Out [O] Destination
2639 HRESULT WINAPI
VarUI8FromUI4(ULONG ulIn
, ULONG64
* pui64Out
)
2641 return _VarUI8FromUI4(ulIn
, pui64Out
);
2644 /************************************************************************
2645 * VarUI8FromDec (OLEAUT32.441)
2647 * Convert a VT_DECIMAL to a VT_UI8.
2651 * pui64Out [O] Destination
2655 * Failure: E_INVALIDARG, if the source value is invalid
2656 * DISP_E_OVERFLOW, if the value will not fit in the destination
2659 * Under native Win32, if the source value has a scale of 0, its sign is
2660 * ignored, i.e. this function takes the absolute value rather than fail
2661 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2662 * (use VarAbs() on pDecIn first if you really want this behaviour).
2664 HRESULT WINAPI
VarUI8FromDec(const DECIMAL
*pdecIn
, ULONG64
* pui64Out
)
2668 /* This decimal is just a 96 bit integer */
2669 if (pdecIn
->sign
& ~DECIMAL_NEG
)
2670 return E_INVALIDARG
;
2673 return DISP_E_OVERFLOW
;
2677 WARN("Sign would be ignored under Win32!\n");
2678 return DISP_E_OVERFLOW
;
2681 *pui64Out
= pdecIn
->Lo64
;
2686 /* Decimal contains a floating point number */
2690 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2691 if (SUCCEEDED(hRet
))
2692 hRet
= VarUI8FromR8(dbl
, pui64Out
);
2700 /************************************************************************
2701 * VarR4FromUI1 (OLEAUT32.68)
2703 * Convert a VT_UI1 to a VT_R4.
2707 * pFltOut [O] Destination
2712 HRESULT WINAPI
VarR4FromUI1(BYTE bIn
, float *pFltOut
)
2714 return _VarR4FromUI1(bIn
, pFltOut
);
2717 /************************************************************************
2718 * VarR4FromI2 (OLEAUT32.69)
2720 * Convert a VT_I2 to a VT_R4.
2724 * pFltOut [O] Destination
2729 HRESULT WINAPI
VarR4FromI2(SHORT sIn
, float *pFltOut
)
2731 return _VarR4FromI2(sIn
, pFltOut
);
2734 /************************************************************************
2735 * VarR4FromI4 (OLEAUT32.70)
2737 * Convert a VT_I4 to a VT_R4.
2741 * pFltOut [O] Destination
2746 HRESULT WINAPI
VarR4FromI4(LONG lIn
, float *pFltOut
)
2748 return _VarR4FromI4(lIn
, pFltOut
);
2751 /************************************************************************
2752 * VarR4FromR8 (OLEAUT32.71)
2754 * Convert a VT_R8 to a VT_R4.
2758 * pFltOut [O] Destination
2762 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2764 HRESULT WINAPI
VarR4FromR8(double dblIn
, float *pFltOut
)
2766 double d
= dblIn
< 0.0 ? -dblIn
: dblIn
;
2767 if (d
> R4_MAX
) return DISP_E_OVERFLOW
;
2772 /************************************************************************
2773 * VarR4FromCy (OLEAUT32.72)
2775 * Convert a VT_CY to a VT_R4.
2779 * pFltOut [O] Destination
2784 HRESULT WINAPI
VarR4FromCy(CY cyIn
, float *pFltOut
)
2786 *pFltOut
= (double)cyIn
.int64
/ CY_MULTIPLIER_F
;
2790 /************************************************************************
2791 * VarR4FromDate (OLEAUT32.73)
2793 * Convert a VT_DATE to a VT_R4.
2797 * pFltOut [O] Destination
2801 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2803 HRESULT WINAPI
VarR4FromDate(DATE dateIn
, float *pFltOut
)
2805 return VarR4FromR8(dateIn
, pFltOut
);
2808 /************************************************************************
2809 * VarR4FromStr (OLEAUT32.74)
2811 * Convert a VT_BSTR to a VT_R4.
2815 * lcid [I] LCID for the conversion
2816 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2817 * pFltOut [O] Destination
2821 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2822 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2824 HRESULT WINAPI
VarR4FromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, float *pFltOut
)
2826 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pFltOut
, VT_R4
);
2829 /************************************************************************
2830 * VarR4FromDisp (OLEAUT32.75)
2832 * Convert a VT_DISPATCH to a VT_R4.
2835 * pdispIn [I] Source
2836 * lcid [I] LCID for conversion
2837 * pFltOut [O] Destination
2841 * Failure: E_INVALIDARG, if the source value is invalid
2842 * DISP_E_OVERFLOW, if the value will not fit in the destination
2843 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2845 HRESULT WINAPI
VarR4FromDisp(IDispatch
* pdispIn
, LCID lcid
, float *pFltOut
)
2847 return VARIANT_FromDisp(pdispIn
, lcid
, pFltOut
, VT_R4
, 0);
2850 /************************************************************************
2851 * VarR4FromBool (OLEAUT32.76)
2853 * Convert a VT_BOOL to a VT_R4.
2857 * pFltOut [O] Destination
2862 HRESULT WINAPI
VarR4FromBool(VARIANT_BOOL boolIn
, float *pFltOut
)
2864 return VarR4FromI2(boolIn
, pFltOut
);
2867 /************************************************************************
2868 * VarR4FromI1 (OLEAUT32.213)
2870 * Convert a VT_I1 to a VT_R4.
2874 * pFltOut [O] Destination
2878 * Failure: E_INVALIDARG, if the source value is invalid
2879 * DISP_E_OVERFLOW, if the value will not fit in the destination
2880 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2882 HRESULT WINAPI
VarR4FromI1(signed char cIn
, float *pFltOut
)
2884 return _VarR4FromI1(cIn
, pFltOut
);
2887 /************************************************************************
2888 * VarR4FromUI2 (OLEAUT32.214)
2890 * Convert a VT_UI2 to a VT_R4.
2894 * pFltOut [O] Destination
2898 * Failure: E_INVALIDARG, if the source value is invalid
2899 * DISP_E_OVERFLOW, if the value will not fit in the destination
2900 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2902 HRESULT WINAPI
VarR4FromUI2(USHORT usIn
, float *pFltOut
)
2904 return _VarR4FromUI2(usIn
, pFltOut
);
2907 /************************************************************************
2908 * VarR4FromUI4 (OLEAUT32.215)
2910 * Convert a VT_UI4 to a VT_R4.
2914 * pFltOut [O] Destination
2918 * Failure: E_INVALIDARG, if the source value is invalid
2919 * DISP_E_OVERFLOW, if the value will not fit in the destination
2920 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2922 HRESULT WINAPI
VarR4FromUI4(ULONG ulIn
, float *pFltOut
)
2924 return _VarR4FromUI4(ulIn
, pFltOut
);
2927 /************************************************************************
2928 * VarR4FromDec (OLEAUT32.216)
2930 * Convert a VT_DECIMAL to a VT_R4.
2934 * pFltOut [O] Destination
2938 * Failure: E_INVALIDARG, if the source value is invalid.
2940 HRESULT WINAPI
VarR4FromDec(const DECIMAL
* pDecIn
, float *pFltOut
)
2942 BYTE scale
= pDecIn
->scale
;
2943 double divisor
= 1.0;
2946 if (scale
> DEC_MAX_SCALE
|| pDecIn
->sign
& ~DECIMAL_NEG
)
2947 return E_INVALIDARG
;
2957 highPart
= (double)pDecIn
->Hi32
/ divisor
;
2958 highPart
*= 4294967296.0F
;
2959 highPart
*= 4294967296.0F
;
2964 *pFltOut
= (double)pDecIn
->Lo64
/ divisor
+ highPart
;
2968 /************************************************************************
2969 * VarR4FromI8 (OLEAUT32.360)
2971 * Convert a VT_I8 to a VT_R4.
2975 * pFltOut [O] Destination
2980 HRESULT WINAPI
VarR4FromI8(LONG64 llIn
, float *pFltOut
)
2982 return _VarR4FromI8(llIn
, pFltOut
);
2985 /************************************************************************
2986 * VarR4FromUI8 (OLEAUT32.361)
2988 * Convert a VT_UI8 to a VT_R4.
2992 * pFltOut [O] Destination
2997 HRESULT WINAPI
VarR4FromUI8(ULONG64 ullIn
, float *pFltOut
)
2999 return _VarR4FromUI8(ullIn
, pFltOut
);
3002 /************************************************************************
3003 * VarR4CmpR8 (OLEAUT32.316)
3005 * Compare a VT_R4 to a VT_R8.
3008 * fltLeft [I] Source
3009 * dblRight [I] Value to compare
3012 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3013 * equal to or greater than dblRight respectively.
3015 HRESULT WINAPI
VarR4CmpR8(float fltLeft
, double dblRight
)
3017 if (fltLeft
< dblRight
)
3019 else if (fltLeft
> dblRight
)
3027 /************************************************************************
3028 * VarR8FromUI1 (OLEAUT32.78)
3030 * Convert a VT_UI1 to a VT_R8.
3034 * pDblOut [O] Destination
3039 HRESULT WINAPI
VarR8FromUI1(BYTE bIn
, double *pDblOut
)
3041 return _VarR8FromUI1(bIn
, pDblOut
);
3044 /************************************************************************
3045 * VarR8FromI2 (OLEAUT32.79)
3047 * Convert a VT_I2 to a VT_R8.
3051 * pDblOut [O] Destination
3056 HRESULT WINAPI
VarR8FromI2(SHORT sIn
, double *pDblOut
)
3058 return _VarR8FromI2(sIn
, pDblOut
);
3061 /************************************************************************
3062 * VarR8FromI4 (OLEAUT32.80)
3064 * Convert a VT_I4 to a VT_R8.
3068 * pDblOut [O] Destination
3073 HRESULT WINAPI
VarR8FromI4(LONG lIn
, double *pDblOut
)
3075 return _VarR8FromI4(lIn
, pDblOut
);
3078 /************************************************************************
3079 * VarR8FromR4 (OLEAUT32.81)
3081 * Convert a VT_R4 to a VT_R8.
3085 * pDblOut [O] Destination
3090 HRESULT WINAPI
VarR8FromR4(FLOAT fltIn
, double *pDblOut
)
3092 return _VarR8FromR4(fltIn
, pDblOut
);
3095 /************************************************************************
3096 * VarR8FromCy (OLEAUT32.82)
3098 * Convert a VT_CY to a VT_R8.
3102 * pDblOut [O] Destination
3107 HRESULT WINAPI
VarR8FromCy(CY cyIn
, double *pDblOut
)
3109 return _VarR8FromCy(cyIn
, pDblOut
);
3112 /************************************************************************
3113 * VarR8FromDate (OLEAUT32.83)
3115 * Convert a VT_DATE to a VT_R8.
3119 * pDblOut [O] Destination
3124 HRESULT WINAPI
VarR8FromDate(DATE dateIn
, double *pDblOut
)
3126 return _VarR8FromDate(dateIn
, pDblOut
);
3129 /************************************************************************
3130 * VarR8FromStr (OLEAUT32.84)
3132 * Convert a VT_BSTR to a VT_R8.
3136 * lcid [I] LCID for the conversion
3137 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3138 * pDblOut [O] Destination
3142 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3143 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3145 HRESULT WINAPI
VarR8FromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, double *pDblOut
)
3147 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDblOut
, VT_R8
);
3150 /************************************************************************
3151 * VarR8FromDisp (OLEAUT32.85)
3153 * Convert a VT_DISPATCH to a VT_R8.
3156 * pdispIn [I] Source
3157 * lcid [I] LCID for conversion
3158 * pDblOut [O] Destination
3162 * Failure: E_INVALIDARG, if the source value is invalid
3163 * DISP_E_OVERFLOW, if the value will not fit in the destination
3164 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3166 HRESULT WINAPI
VarR8FromDisp(IDispatch
* pdispIn
, LCID lcid
, double *pDblOut
)
3168 return VARIANT_FromDisp(pdispIn
, lcid
, pDblOut
, VT_R8
, 0);
3171 /************************************************************************
3172 * VarR8FromBool (OLEAUT32.86)
3174 * Convert a VT_BOOL to a VT_R8.
3178 * pDblOut [O] Destination
3183 HRESULT WINAPI
VarR8FromBool(VARIANT_BOOL boolIn
, double *pDblOut
)
3185 return VarR8FromI2(boolIn
, pDblOut
);
3188 /************************************************************************
3189 * VarR8FromI1 (OLEAUT32.217)
3191 * Convert a VT_I1 to a VT_R8.
3195 * pDblOut [O] Destination
3199 * Failure: E_INVALIDARG, if the source value is invalid
3200 * DISP_E_OVERFLOW, if the value will not fit in the destination
3201 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3203 HRESULT WINAPI
VarR8FromI1(signed char cIn
, double *pDblOut
)
3205 return _VarR8FromI1(cIn
, pDblOut
);
3208 /************************************************************************
3209 * VarR8FromUI2 (OLEAUT32.218)
3211 * Convert a VT_UI2 to a VT_R8.
3215 * pDblOut [O] Destination
3219 * Failure: E_INVALIDARG, if the source value is invalid
3220 * DISP_E_OVERFLOW, if the value will not fit in the destination
3221 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3223 HRESULT WINAPI
VarR8FromUI2(USHORT usIn
, double *pDblOut
)
3225 return _VarR8FromUI2(usIn
, pDblOut
);
3228 /************************************************************************
3229 * VarR8FromUI4 (OLEAUT32.219)
3231 * Convert a VT_UI4 to a VT_R8.
3235 * pDblOut [O] Destination
3239 * Failure: E_INVALIDARG, if the source value is invalid
3240 * DISP_E_OVERFLOW, if the value will not fit in the destination
3241 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3243 HRESULT WINAPI
VarR8FromUI4(ULONG ulIn
, double *pDblOut
)
3245 return _VarR8FromUI4(ulIn
, pDblOut
);
3248 /************************************************************************
3249 * VarR8FromDec (OLEAUT32.220)
3251 * Convert a VT_DECIMAL to a VT_R8.
3255 * pDblOut [O] Destination
3259 * Failure: E_INVALIDARG, if the source value is invalid.
3261 HRESULT WINAPI
VarR8FromDec(const DECIMAL
* pDecIn
, double *pDblOut
)
3263 BYTE scale
= pDecIn
->scale
;
3264 double divisor
= 1.0, highPart
;
3266 if (scale
> DEC_MAX_SCALE
|| pDecIn
->sign
& ~DECIMAL_NEG
)
3267 return E_INVALIDARG
;
3277 highPart
= (double)pDecIn
->Hi32
/ divisor
;
3278 highPart
*= 4294967296.0F
;
3279 highPart
*= 4294967296.0F
;
3284 *pDblOut
= (double)pDecIn
->Lo64
/ divisor
+ highPart
;
3288 /************************************************************************
3289 * VarR8FromI8 (OLEAUT32.362)
3291 * Convert a VT_I8 to a VT_R8.
3295 * pDblOut [O] Destination
3300 HRESULT WINAPI
VarR8FromI8(LONG64 llIn
, double *pDblOut
)
3302 return _VarR8FromI8(llIn
, pDblOut
);
3305 /************************************************************************
3306 * VarR8FromUI8 (OLEAUT32.363)
3308 * Convert a VT_UI8 to a VT_R8.
3312 * pDblOut [O] Destination
3317 HRESULT WINAPI
VarR8FromUI8(ULONG64 ullIn
, double *pDblOut
)
3319 return _VarR8FromUI8(ullIn
, pDblOut
);
3322 /************************************************************************
3323 * VarR8Pow (OLEAUT32.315)
3325 * Raise a VT_R8 to a power.
3328 * dblLeft [I] Source
3329 * dblPow [I] Power to raise dblLeft by
3330 * pDblOut [O] Destination
3333 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3335 HRESULT WINAPI
VarR8Pow(double dblLeft
, double dblPow
, double *pDblOut
)
3337 *pDblOut
= pow(dblLeft
, dblPow
);
3341 /************************************************************************
3342 * VarR8Round (OLEAUT32.317)
3344 * Round a VT_R8 to a given number of decimal points.
3348 * nDig [I] Number of decimal points to round to
3349 * pDblOut [O] Destination for rounded number
3352 * Success: S_OK. pDblOut is rounded to nDig digits.
3353 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3356 * The native version of this function rounds using the internal
3357 * binary representation of the number. Wine uses the dutch rounding
3358 * convention, so therefore small differences can occur in the value returned.
3359 * MSDN says that you should use your own rounding function if you want
3360 * rounding to be predictable in your application.
3362 HRESULT WINAPI
VarR8Round(double dblIn
, int nDig
, double *pDblOut
)
3364 double scale
, whole
, fract
;
3367 return E_INVALIDARG
;
3369 scale
= pow(10.0, nDig
);
3372 whole
= dblIn
< 0 ? ceil(dblIn
) : floor(dblIn
);
3373 fract
= dblIn
- whole
;
3376 dblIn
= whole
+ 1.0;
3377 else if (fract
== 0.5)
3378 dblIn
= whole
+ fmod(whole
, 2.0);
3379 else if (fract
>= 0.0)
3381 else if (fract
== -0.5)
3382 dblIn
= whole
- fmod(whole
, 2.0);
3383 else if (fract
> -0.5)
3386 dblIn
= whole
- 1.0;
3388 *pDblOut
= dblIn
/ scale
;
3395 /* Powers of 10 from 0..4 D.P. */
3396 static const int CY_Divisors
[5] = { CY_MULTIPLIER
/10000, CY_MULTIPLIER
/1000,
3397 CY_MULTIPLIER
/100, CY_MULTIPLIER
/10, CY_MULTIPLIER
};
3399 /************************************************************************
3400 * VarCyFromUI1 (OLEAUT32.98)
3402 * Convert a VT_UI1 to a VT_CY.
3406 * pCyOut [O] Destination
3410 * Failure: E_INVALIDARG, if the source value is invalid
3411 * DISP_E_OVERFLOW, if the value will not fit in the destination
3412 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3414 HRESULT WINAPI
VarCyFromUI1(BYTE bIn
, CY
* pCyOut
)
3416 pCyOut
->int64
= (ULONG64
)bIn
* CY_MULTIPLIER
;
3420 /************************************************************************
3421 * VarCyFromI2 (OLEAUT32.99)
3423 * Convert a VT_I2 to a VT_CY.
3427 * pCyOut [O] Destination
3431 * Failure: E_INVALIDARG, if the source value is invalid
3432 * DISP_E_OVERFLOW, if the value will not fit in the destination
3433 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3435 HRESULT WINAPI
VarCyFromI2(SHORT sIn
, CY
* pCyOut
)
3437 pCyOut
->int64
= (LONG64
)sIn
* CY_MULTIPLIER
;
3441 /************************************************************************
3442 * VarCyFromI4 (OLEAUT32.100)
3444 * Convert a VT_I4 to a VT_CY.
3448 * pCyOut [O] Destination
3452 * Failure: E_INVALIDARG, if the source value is invalid
3453 * DISP_E_OVERFLOW, if the value will not fit in the destination
3454 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3456 HRESULT WINAPI
VarCyFromI4(LONG lIn
, CY
* pCyOut
)
3458 pCyOut
->int64
= (LONG64
)lIn
* CY_MULTIPLIER
;
3462 /************************************************************************
3463 * VarCyFromR4 (OLEAUT32.101)
3465 * Convert a VT_R4 to a VT_CY.
3469 * pCyOut [O] Destination
3473 * Failure: E_INVALIDARG, if the source value is invalid
3474 * DISP_E_OVERFLOW, if the value will not fit in the destination
3475 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3477 HRESULT WINAPI
VarCyFromR4(FLOAT fltIn
, CY
* pCyOut
)
3479 return VarCyFromR8(fltIn
, pCyOut
);
3482 /************************************************************************
3483 * VarCyFromR8 (OLEAUT32.102)
3485 * Convert a VT_R8 to a VT_CY.
3489 * pCyOut [O] Destination
3493 * Failure: E_INVALIDARG, if the source value is invalid
3494 * DISP_E_OVERFLOW, if the value will not fit in the destination
3495 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3497 HRESULT WINAPI
VarCyFromR8(double dblIn
, CY
* pCyOut
)
3499 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3500 /* This code gives identical results to Win32 on Intel.
3501 * Here we use fp exceptions to catch overflows when storing the value.
3503 static const unsigned short r8_fpcontrol
= 0x137f;
3504 static const double r8_multiplier
= CY_MULTIPLIER_F
;
3505 unsigned short old_fpcontrol
, result_fpstatus
;
3507 /* Clear exceptions, save the old fp state and load the new state */
3508 __asm__
__volatile__( "fnclex" );
3509 __asm__
__volatile__( "fstcw %0" : "=m" (old_fpcontrol
) : );
3510 __asm__
__volatile__( "fldcw %0" : : "m" (r8_fpcontrol
) );
3511 /* Perform the conversion. */
3512 __asm__
__volatile__( "fldl %0" : : "m" (dblIn
) );
3513 __asm__
__volatile__( "fmull %0" : : "m" (r8_multiplier
) );
3514 __asm__
__volatile__( "fistpll %0" : : "m" (*pCyOut
) );
3515 /* Save the resulting fp state, load the old state and clear exceptions */
3516 __asm__
__volatile__( "fstsw %0" : "=m" (result_fpstatus
) : );
3517 __asm__
__volatile__( "fnclex" );
3518 __asm__
__volatile__( "fldcw %0" : : "m" (old_fpcontrol
) );
3520 if (result_fpstatus
& 0x9) /* Overflow | Invalid */
3521 return DISP_E_OVERFLOW
;
3523 /* This version produces slightly different results for boundary cases */
3524 if (dblIn
< -922337203685477.5807 || dblIn
>= 922337203685477.5807)
3525 return DISP_E_OVERFLOW
;
3526 dblIn
*= CY_MULTIPLIER_F
;
3527 VARIANT_DutchRound(LONG64
, dblIn
, pCyOut
->int64
);
3532 /************************************************************************
3533 * VarCyFromDate (OLEAUT32.103)
3535 * Convert a VT_DATE to a VT_CY.
3539 * pCyOut [O] Destination
3543 * Failure: E_INVALIDARG, if the source value is invalid
3544 * DISP_E_OVERFLOW, if the value will not fit in the destination
3545 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3547 HRESULT WINAPI
VarCyFromDate(DATE dateIn
, CY
* pCyOut
)
3549 return VarCyFromR8(dateIn
, pCyOut
);
3552 /************************************************************************
3553 * VarCyFromStr (OLEAUT32.104)
3555 * Convert a VT_BSTR to a VT_CY.
3559 * lcid [I] LCID for the conversion
3560 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3561 * pCyOut [O] Destination
3565 * Failure: E_INVALIDARG, if the source value is invalid
3566 * DISP_E_OVERFLOW, if the value will not fit in the destination
3567 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3569 HRESULT WINAPI
VarCyFromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, CY
* pCyOut
)
3571 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pCyOut
, VT_CY
);
3574 /************************************************************************
3575 * VarCyFromDisp (OLEAUT32.105)
3577 * Convert a VT_DISPATCH to a VT_CY.
3580 * pdispIn [I] Source
3581 * lcid [I] LCID for conversion
3582 * pCyOut [O] Destination
3586 * Failure: E_INVALIDARG, if the source value is invalid
3587 * DISP_E_OVERFLOW, if the value will not fit in the destination
3588 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3590 HRESULT WINAPI
VarCyFromDisp(IDispatch
* pdispIn
, LCID lcid
, CY
* pCyOut
)
3592 return VARIANT_FromDisp(pdispIn
, lcid
, pCyOut
, VT_CY
, 0);
3595 /************************************************************************
3596 * VarCyFromBool (OLEAUT32.106)
3598 * Convert a VT_BOOL to a VT_CY.
3602 * pCyOut [O] Destination
3606 * Failure: E_INVALIDARG, if the source value is invalid
3607 * DISP_E_OVERFLOW, if the value will not fit in the destination
3608 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3611 * While the sign of the boolean is stored in the currency, the value is
3612 * converted to either 0 or 1.
3614 HRESULT WINAPI
VarCyFromBool(VARIANT_BOOL boolIn
, CY
* pCyOut
)
3616 pCyOut
->int64
= (LONG64
)boolIn
* CY_MULTIPLIER
;
3620 /************************************************************************
3621 * VarCyFromI1 (OLEAUT32.225)
3623 * Convert a VT_I1 to a VT_CY.
3627 * pCyOut [O] Destination
3631 * Failure: E_INVALIDARG, if the source value is invalid
3632 * DISP_E_OVERFLOW, if the value will not fit in the destination
3633 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3635 HRESULT WINAPI
VarCyFromI1(signed char cIn
, CY
* pCyOut
)
3637 pCyOut
->int64
= (LONG64
)cIn
* CY_MULTIPLIER
;
3641 /************************************************************************
3642 * VarCyFromUI2 (OLEAUT32.226)
3644 * Convert a VT_UI2 to a VT_CY.
3648 * pCyOut [O] Destination
3652 * Failure: E_INVALIDARG, if the source value is invalid
3653 * DISP_E_OVERFLOW, if the value will not fit in the destination
3654 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3656 HRESULT WINAPI
VarCyFromUI2(USHORT usIn
, CY
* pCyOut
)
3658 pCyOut
->int64
= (ULONG64
)usIn
* CY_MULTIPLIER
;
3662 /************************************************************************
3663 * VarCyFromUI4 (OLEAUT32.227)
3665 * Convert a VT_UI4 to a VT_CY.
3669 * pCyOut [O] Destination
3673 * Failure: E_INVALIDARG, if the source value is invalid
3674 * DISP_E_OVERFLOW, if the value will not fit in the destination
3675 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3677 HRESULT WINAPI
VarCyFromUI4(ULONG ulIn
, CY
* pCyOut
)
3679 pCyOut
->int64
= (ULONG64
)ulIn
* CY_MULTIPLIER
;
3683 /************************************************************************
3684 * VarCyFromDec (OLEAUT32.228)
3686 * Convert a VT_DECIMAL to a VT_CY.
3690 * pCyOut [O] Destination
3694 * Failure: E_INVALIDARG, if the source value is invalid
3695 * DISP_E_OVERFLOW, if the value will not fit in the destination
3696 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3698 HRESULT WINAPI
VarCyFromDec(const DECIMAL
* pdecIn
, CY
* pCyOut
)
3703 hRet
= VarDecRound(pdecIn
, 4, &rounded
);
3705 if (SUCCEEDED(hRet
))
3710 return DISP_E_OVERFLOW
;
3712 /* Note: Without the casts this promotes to int64 which loses precision */
3713 d
= (double)rounded
.Lo64
/ (double)CY_Divisors
[rounded
.scale
];
3716 return VarCyFromR8(d
, pCyOut
);
3721 /************************************************************************
3722 * VarCyFromI8 (OLEAUT32.366)
3724 * Convert a VT_I8 to a VT_CY.
3728 * pCyOut [O] Destination
3732 * Failure: E_INVALIDARG, if the source value is invalid
3733 * DISP_E_OVERFLOW, if the value will not fit in the destination
3734 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3736 HRESULT WINAPI
VarCyFromI8(LONG64 llIn
, CY
* pCyOut
)
3738 if (llIn
<= (I8_MIN
/CY_MULTIPLIER
) || llIn
>= (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3739 pCyOut
->int64
= llIn
* CY_MULTIPLIER
;
3743 /************************************************************************
3744 * VarCyFromUI8 (OLEAUT32.375)
3746 * Convert a VT_UI8 to a VT_CY.
3750 * pCyOut [O] Destination
3754 * Failure: E_INVALIDARG, if the source value is invalid
3755 * DISP_E_OVERFLOW, if the value will not fit in the destination
3756 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3758 HRESULT WINAPI
VarCyFromUI8(ULONG64 ullIn
, CY
* pCyOut
)
3760 if (ullIn
> (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3761 pCyOut
->int64
= ullIn
* CY_MULTIPLIER
;
3765 /************************************************************************
3766 * VarCyAdd (OLEAUT32.299)
3768 * Add one CY to another.
3772 * cyRight [I] Value to add
3773 * pCyOut [O] Destination
3777 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3779 HRESULT WINAPI
VarCyAdd(CY cyLeft
, CY cyRight
, CY
* pCyOut
)
3782 _VarR8FromCy(cyLeft
, &l
);
3783 _VarR8FromCy(cyRight
, &r
);
3785 return VarCyFromR8(l
, pCyOut
);
3788 /************************************************************************
3789 * VarCyMul (OLEAUT32.303)
3791 * Multiply one CY by another.
3795 * cyRight [I] Value to multiply by
3796 * pCyOut [O] Destination
3800 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3802 HRESULT WINAPI
VarCyMul(CY cyLeft
, CY cyRight
, CY
* pCyOut
)
3805 _VarR8FromCy(cyLeft
, &l
);
3806 _VarR8FromCy(cyRight
, &r
);
3808 return VarCyFromR8(l
, pCyOut
);
3811 /************************************************************************
3812 * VarCyMulI4 (OLEAUT32.304)
3814 * Multiply one CY by a VT_I4.
3818 * lRight [I] Value to multiply by
3819 * pCyOut [O] Destination
3823 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3825 HRESULT WINAPI
VarCyMulI4(CY cyLeft
, LONG lRight
, CY
* pCyOut
)
3829 _VarR8FromCy(cyLeft
, &d
);
3831 return VarCyFromR8(d
, pCyOut
);
3834 /************************************************************************
3835 * VarCySub (OLEAUT32.305)
3837 * Subtract one CY from another.
3841 * cyRight [I] Value to subtract
3842 * pCyOut [O] Destination
3846 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3848 HRESULT WINAPI
VarCySub(CY cyLeft
, CY cyRight
, CY
* pCyOut
)
3851 _VarR8FromCy(cyLeft
, &l
);
3852 _VarR8FromCy(cyRight
, &r
);
3854 return VarCyFromR8(l
, pCyOut
);
3857 /************************************************************************
3858 * VarCyAbs (OLEAUT32.306)
3860 * Convert a VT_CY into its absolute value.
3864 * pCyOut [O] Destination
3867 * Success: S_OK. pCyOut contains the absolute value.
3868 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3870 HRESULT WINAPI
VarCyAbs(CY cyIn
, CY
* pCyOut
)
3872 if (cyIn
.Hi
== 0x80000000 && !cyIn
.Lo
)
3873 return DISP_E_OVERFLOW
;
3875 pCyOut
->int64
= cyIn
.int64
< 0 ? -cyIn
.int64
: cyIn
.int64
;
3879 /************************************************************************
3880 * VarCyFix (OLEAUT32.307)
3882 * Return the integer part of a VT_CY.
3886 * pCyOut [O] Destination
3890 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3893 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3894 * negative numbers away from 0, while this function rounds them towards zero.
3896 HRESULT WINAPI
VarCyFix(CY cyIn
, CY
* pCyOut
)
3898 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3899 pCyOut
->int64
*= CY_MULTIPLIER
;
3903 /************************************************************************
3904 * VarCyInt (OLEAUT32.308)
3906 * Return the integer part of a VT_CY.
3910 * pCyOut [O] Destination
3914 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3917 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3918 * negative numbers towards 0, while this function rounds them away from zero.
3920 HRESULT WINAPI
VarCyInt(CY cyIn
, CY
* pCyOut
)
3922 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3923 pCyOut
->int64
*= CY_MULTIPLIER
;
3925 if (cyIn
.int64
< 0 && cyIn
.int64
% CY_MULTIPLIER
!= 0)
3927 pCyOut
->int64
-= CY_MULTIPLIER
;
3932 /************************************************************************
3933 * VarCyNeg (OLEAUT32.309)
3935 * Change the sign of a VT_CY.
3939 * pCyOut [O] Destination
3943 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3945 HRESULT WINAPI
VarCyNeg(CY cyIn
, CY
* pCyOut
)
3947 if (cyIn
.Hi
== 0x80000000 && !cyIn
.Lo
)
3948 return DISP_E_OVERFLOW
;
3950 pCyOut
->int64
= -cyIn
.int64
;
3954 /************************************************************************
3955 * VarCyRound (OLEAUT32.310)
3957 * Change the precision of a VT_CY.
3961 * cDecimals [I] New number of decimals to keep
3962 * pCyOut [O] Destination
3966 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3968 HRESULT WINAPI
VarCyRound(CY cyIn
, int cDecimals
, CY
* pCyOut
)
3971 return E_INVALIDARG
;
3975 /* Rounding to more precision than we have */
3981 double d
, div
= CY_Divisors
[cDecimals
];
3983 _VarR8FromCy(cyIn
, &d
);
3985 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
3986 d
= (double)pCyOut
->int64
/ div
* CY_MULTIPLIER_F
;
3987 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
3992 /************************************************************************
3993 * VarCyCmp (OLEAUT32.311)
3995 * Compare two VT_CY values.
3999 * cyRight [I] Value to compare
4002 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4003 * compare is less, equal or greater than source respectively.
4004 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4006 HRESULT WINAPI
VarCyCmp(CY cyLeft
, CY cyRight
)
4011 /* Subtract right from left, and compare the result to 0 */
4012 hRet
= VarCySub(cyLeft
, cyRight
, &result
);
4014 if (SUCCEEDED(hRet
))
4016 if (result
.int64
< 0)
4017 hRet
= (HRESULT
)VARCMP_LT
;
4018 else if (result
.int64
> 0)
4019 hRet
= (HRESULT
)VARCMP_GT
;
4021 hRet
= (HRESULT
)VARCMP_EQ
;
4026 /************************************************************************
4027 * VarCyCmpR8 (OLEAUT32.312)
4029 * Compare a VT_CY to a double
4032 * cyLeft [I] Currency Source
4033 * dblRight [I] double to compare to cyLeft
4036 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4037 * less than, equal to or greater than cyLeft respectively.
4038 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4040 HRESULT WINAPI
VarCyCmpR8(CY cyLeft
, double dblRight
)
4045 hRet
= VarCyFromR8(dblRight
, &cyRight
);
4047 if (SUCCEEDED(hRet
))
4048 hRet
= VarCyCmp(cyLeft
, cyRight
);
4053 /************************************************************************
4054 * VarCyMulI8 (OLEAUT32.329)
4056 * Multiply a VT_CY by a VT_I8.
4060 * llRight [I] Value to multiply by
4061 * pCyOut [O] Destination
4065 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4067 HRESULT WINAPI
VarCyMulI8(CY cyLeft
, LONG64 llRight
, CY
* pCyOut
)
4071 _VarR8FromCy(cyLeft
, &d
);
4072 d
= d
* (double)llRight
;
4073 return VarCyFromR8(d
, pCyOut
);
4079 /************************************************************************
4080 * VarDecFromUI1 (OLEAUT32.190)
4082 * Convert a VT_UI1 to a DECIMAL.
4086 * pDecOut [O] Destination
4091 HRESULT WINAPI
VarDecFromUI1(BYTE bIn
, DECIMAL
* pDecOut
)
4093 return VarDecFromUI4(bIn
, pDecOut
);
4096 /************************************************************************
4097 * VarDecFromI2 (OLEAUT32.191)
4099 * Convert a VT_I2 to a DECIMAL.
4103 * pDecOut [O] Destination
4108 HRESULT WINAPI
VarDecFromI2(SHORT sIn
, DECIMAL
* pDecOut
)
4110 return VarDecFromI4(sIn
, pDecOut
);
4113 /************************************************************************
4114 * VarDecFromI4 (OLEAUT32.192)
4116 * Convert a VT_I4 to a DECIMAL.
4120 * pDecOut [O] Destination
4125 HRESULT WINAPI
VarDecFromI4(LONG lIn
, DECIMAL
* pDecOut
)
4133 pDecOut
->sign
= DECIMAL_NEG
;
4134 pDecOut
->Lo32
= -lIn
;
4138 pDecOut
->sign
= DECIMAL_POS
;
4139 pDecOut
->Lo32
= lIn
;
4144 /* internal representation of the value stored in a DECIMAL. The bytes are
4145 stored from LSB at index 0 to MSB at index 11
4147 typedef struct DECIMAL_internal
4149 DWORD bitsnum
[3]; /* 96 significant bits, unsigned */
4150 unsigned char scale
; /* number scaled * 10 ^ -(scale) */
4151 unsigned int sign
: 1; /* 0 - positive, 1 - negative */
4154 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
);
4155 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
);
4156 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
);
4157 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
);
4158 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
);
4159 static BOOL
VARIANT_int_iszero(const DWORD
* p
, unsigned int n
);
4161 /************************************************************************
4162 * VarDecFromR4 (OLEAUT32.193)
4164 * Convert a VT_R4 to a DECIMAL.
4168 * pDecOut [O] Destination
4173 HRESULT WINAPI
VarDecFromR4(FLOAT fltIn
, DECIMAL
* pDecOut
)
4178 hres
= VARIANT_DI_FromR4(fltIn
, &di
);
4179 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4183 /************************************************************************
4184 * VarDecFromR8 (OLEAUT32.194)
4186 * Convert a VT_R8 to a DECIMAL.
4190 * pDecOut [O] Destination
4195 HRESULT WINAPI
VarDecFromR8(double dblIn
, DECIMAL
* pDecOut
)
4200 hres
= VARIANT_DI_FromR8(dblIn
, &di
);
4201 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4205 /************************************************************************
4206 * VarDecFromDate (OLEAUT32.195)
4208 * Convert a VT_DATE to a DECIMAL.
4212 * pDecOut [O] Destination
4217 HRESULT WINAPI
VarDecFromDate(DATE dateIn
, DECIMAL
* pDecOut
)
4219 return VarDecFromR8(dateIn
, pDecOut
);
4222 /************************************************************************
4223 * VarDecFromCy (OLEAUT32.196)
4225 * Convert a VT_CY to a DECIMAL.
4229 * pDecOut [O] Destination
4234 HRESULT WINAPI
VarDecFromCy(CY cyIn
, DECIMAL
* pDecOut
)
4241 pDecOut
->sign
= DECIMAL_NEG
;
4242 pDecOut
->Lo64
= -cyIn
.int64
;
4246 pDecOut
->sign
= DECIMAL_POS
;
4247 pDecOut
->Lo64
= cyIn
.int64
;
4252 /************************************************************************
4253 * VarDecFromStr (OLEAUT32.197)
4255 * Convert a VT_BSTR to a DECIMAL.
4259 * lcid [I] LCID for the conversion
4260 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4261 * pDecOut [O] Destination
4265 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4267 HRESULT WINAPI
VarDecFromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DECIMAL
* pDecOut
)
4269 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDecOut
, VT_DECIMAL
);
4272 /************************************************************************
4273 * VarDecFromDisp (OLEAUT32.198)
4275 * Convert a VT_DISPATCH to a DECIMAL.
4278 * pdispIn [I] Source
4279 * lcid [I] LCID for conversion
4280 * pDecOut [O] Destination
4284 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4286 HRESULT WINAPI
VarDecFromDisp(IDispatch
* pdispIn
, LCID lcid
, DECIMAL
* pDecOut
)
4288 return VARIANT_FromDisp(pdispIn
, lcid
, pDecOut
, VT_DECIMAL
, 0);
4291 /************************************************************************
4292 * VarDecFromBool (OLEAUT32.199)
4294 * Convert a VT_BOOL to a DECIMAL.
4298 * pDecOut [O] Destination
4304 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4306 HRESULT WINAPI
VarDecFromBool(VARIANT_BOOL bIn
, DECIMAL
* pDecOut
)
4312 pDecOut
->sign
= DECIMAL_NEG
;
4317 pDecOut
->sign
= DECIMAL_POS
;
4323 /************************************************************************
4324 * VarDecFromI1 (OLEAUT32.241)
4326 * Convert a VT_I1 to a DECIMAL.
4330 * pDecOut [O] Destination
4335 HRESULT WINAPI
VarDecFromI1(signed char cIn
, DECIMAL
* pDecOut
)
4337 return VarDecFromI4(cIn
, pDecOut
);
4340 /************************************************************************
4341 * VarDecFromUI2 (OLEAUT32.242)
4343 * Convert a VT_UI2 to a DECIMAL.
4347 * pDecOut [O] Destination
4352 HRESULT WINAPI
VarDecFromUI2(USHORT usIn
, DECIMAL
* pDecOut
)
4354 return VarDecFromUI4(usIn
, pDecOut
);
4357 /************************************************************************
4358 * VarDecFromUI4 (OLEAUT32.243)
4360 * Convert a VT_UI4 to a DECIMAL.
4364 * pDecOut [O] Destination
4369 HRESULT WINAPI
VarDecFromUI4(ULONG ulIn
, DECIMAL
* pDecOut
)
4371 pDecOut
->sign
= DECIMAL_POS
;
4374 pDecOut
->Lo64
= ulIn
;
4378 /************************************************************************
4379 * VarDecFromI8 (OLEAUT32.374)
4381 * Convert a VT_I8 to a DECIMAL.
4385 * pDecOut [O] Destination
4390 HRESULT WINAPI
VarDecFromI8(LONG64 llIn
, DECIMAL
* pDecOut
)
4397 pDecOut
->sign
= DECIMAL_NEG
;
4398 pDecOut
->Lo64
= -llIn
;
4402 pDecOut
->sign
= DECIMAL_POS
;
4403 pDecOut
->Lo64
= llIn
;
4408 /************************************************************************
4409 * VarDecFromUI8 (OLEAUT32.375)
4411 * Convert a VT_UI8 to a DECIMAL.
4415 * pDecOut [O] Destination
4420 HRESULT WINAPI
VarDecFromUI8(ULONG64 ullIn
, DECIMAL
* pDecOut
)
4422 pDecOut
->sign
= DECIMAL_POS
;
4425 pDecOut
->Lo64
= ullIn
;
4429 /* Make two DECIMALS the same scale; used by math functions below */
4430 static HRESULT
VARIANT_DecScale(const DECIMAL
** ppDecLeft
,
4431 const DECIMAL
** ppDecRight
,
4434 static DECIMAL scaleFactor
;
4435 unsigned char remainder
;
4440 if ((*ppDecLeft
)->sign
& ~DECIMAL_NEG
|| (*ppDecRight
)->sign
& ~DECIMAL_NEG
)
4441 return E_INVALIDARG
;
4443 scaleFactor
.Lo32
= 10;
4445 i
= scaleAmount
= (*ppDecLeft
)->scale
- (*ppDecRight
)->scale
;
4448 return S_OK
; /* Same scale */
4450 if (scaleAmount
> 0)
4452 decTemp
= *(*ppDecRight
); /* Left is bigger - scale the right hand side */
4453 *ppDecRight
= &pDecOut
[0];
4457 decTemp
= *(*ppDecLeft
); /* Right is bigger - scale the left hand side */
4458 *ppDecLeft
= &pDecOut
[0];
4462 /* Multiply up the value to be scaled by the correct amount (if possible) */
4463 while (i
> 0 && SUCCEEDED(VarDecMul(&decTemp
, &scaleFactor
, &pDecOut
[0])))
4465 decTemp
= pDecOut
[0];
4471 pDecOut
[0].scale
+= (scaleAmount
> 0) ? scaleAmount
: (-scaleAmount
);
4472 return S_OK
; /* Same scale */
4475 /* Scaling further not possible, reduce accuracy of other argument */
4476 pDecOut
[0] = decTemp
;
4477 if (scaleAmount
> 0)
4479 pDecOut
[0].scale
+= scaleAmount
- i
;
4480 VARIANT_DIFromDec(*ppDecLeft
, &di
);
4481 *ppDecLeft
= &pDecOut
[1];
4485 pDecOut
[0].scale
+= (-scaleAmount
) - i
;
4486 VARIANT_DIFromDec(*ppDecRight
, &di
);
4487 *ppDecRight
= &pDecOut
[1];
4492 while (i
-- > 0 && !VARIANT_int_iszero(di
.bitsnum
, ARRAY_SIZE(di
.bitsnum
)))
4494 remainder
= VARIANT_int_divbychar(di
.bitsnum
, ARRAY_SIZE(di
.bitsnum
), 10);
4495 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4498 /* round up the result - native oleaut32 does this */
4499 if (remainder
>= 5) {
4500 for (remainder
= 1, i
= 0; i
< ARRAY_SIZE(di
.bitsnum
) && remainder
; i
++) {
4501 ULONGLONG digit
= di
.bitsnum
[i
] + 1;
4502 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4503 di
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
4507 VARIANT_DecFromDI(&di
, &pDecOut
[1]);
4511 /* Add two unsigned 32 bit values with overflow */
4512 static ULONG
VARIANT_Add(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4514 ULARGE_INTEGER ul64
;
4516 ul64
.QuadPart
= (ULONG64
)ulLeft
+ (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4517 *pulHigh
= ul64
.HighPart
;
4518 return ul64
.LowPart
;
4521 /* Subtract two unsigned 32 bit values with underflow */
4522 static ULONG
VARIANT_Sub(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4524 BOOL invert
= FALSE
;
4525 ULARGE_INTEGER ul64
;
4527 ul64
.QuadPart
= (LONG64
)ulLeft
- (ULONG64
)ulRight
;
4528 if (ulLeft
< ulRight
)
4531 if (ul64
.QuadPart
> (ULONG64
)*pulHigh
)
4532 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4535 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4539 ul64
.HighPart
= -ul64
.HighPart
;
4541 *pulHigh
= ul64
.HighPart
;
4542 return ul64
.LowPart
;
4545 /* Multiply two unsigned 32 bit values with overflow */
4546 static ULONG
VARIANT_Mul(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4548 ULARGE_INTEGER ul64
;
4550 ul64
.QuadPart
= (ULONG64
)ulLeft
* (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4551 *pulHigh
= ul64
.HighPart
;
4552 return ul64
.LowPart
;
4555 /* Compare two decimals that have the same scale */
4556 static inline int VARIANT_DecCmp(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
)
4558 if ( pDecLeft
->Hi32
< pDecRight
->Hi32
||
4559 (pDecLeft
->Hi32
<= pDecRight
->Hi32
&& pDecLeft
->Lo64
< pDecRight
->Lo64
))
4561 else if (pDecLeft
->Hi32
== pDecRight
->Hi32
&& pDecLeft
->Lo64
== pDecRight
->Lo64
)
4566 /************************************************************************
4567 * VarDecAdd (OLEAUT32.177)
4569 * Add one DECIMAL to another.
4572 * pDecLeft [I] Source
4573 * pDecRight [I] Value to add
4574 * pDecOut [O] Destination
4578 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4580 HRESULT WINAPI
VarDecAdd(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
4585 hRet
= VARIANT_DecScale(&pDecLeft
, &pDecRight
, scaled
);
4587 if (SUCCEEDED(hRet
))
4589 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4591 BYTE sign
= DECIMAL_POS
;
4594 /* Correct for the sign of the result */
4595 if (pDecLeft
->sign
&& pDecRight
->sign
)
4597 /* -x + -y : Negative */
4599 goto VarDecAdd_AsPositive
;
4601 else if (pDecLeft
->sign
&& !pDecRight
->sign
)
4603 cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4605 /* -x + y : Negative if x > y */
4609 VarDecAdd_AsNegative
:
4610 pDecOut
->Lo32
= VARIANT_Sub(pDecLeft
->Lo32
, pDecRight
->Lo32
, &overflow
);
4611 pDecOut
->Mid32
= VARIANT_Sub(pDecLeft
->Mid32
, pDecRight
->Mid32
, &overflow
);
4612 pDecOut
->Hi32
= VARIANT_Sub(pDecLeft
->Hi32
, pDecRight
->Hi32
, &overflow
);
4616 VarDecAdd_AsInvertedNegative
:
4617 pDecOut
->Lo32
= VARIANT_Sub(pDecRight
->Lo32
, pDecLeft
->Lo32
, &overflow
);
4618 pDecOut
->Mid32
= VARIANT_Sub(pDecRight
->Mid32
, pDecLeft
->Mid32
, &overflow
);
4619 pDecOut
->Hi32
= VARIANT_Sub(pDecRight
->Hi32
, pDecLeft
->Hi32
, &overflow
);
4622 else if (!pDecLeft
->sign
&& pDecRight
->sign
)
4624 cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4626 /* x + -y : Negative if x <= y */
4630 goto VarDecAdd_AsInvertedNegative
;
4632 goto VarDecAdd_AsNegative
;
4636 /* x + y : Positive */
4637 VarDecAdd_AsPositive
:
4638 pDecOut
->Lo32
= VARIANT_Add(pDecLeft
->Lo32
, pDecRight
->Lo32
, &overflow
);
4639 pDecOut
->Mid32
= VARIANT_Add(pDecLeft
->Mid32
, pDecRight
->Mid32
, &overflow
);
4640 pDecOut
->Hi32
= VARIANT_Add(pDecLeft
->Hi32
, pDecRight
->Hi32
, &overflow
);
4646 unsigned char remainder
;
4648 if (!pDecLeft
->scale
)
4649 return DISP_E_OVERFLOW
;
4651 pDecOut
->scale
= pDecLeft
->scale
- 1;
4652 pDecOut
->sign
= sign
;
4654 n
[0] = pDecOut
->Lo32
;
4655 n
[1] = pDecOut
->Mid32
;
4656 n
[2] = pDecOut
->Hi32
;
4659 remainder
= VARIANT_int_divbychar(n
,4,10);
4661 /* round up the result */
4664 for (remainder
= 1, i
= 0; i
< ARRAY_SIZE(n
) && remainder
; i
++)
4666 ULONGLONG digit
= n
[i
] + 1;
4667 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4668 n
[i
] = digit
& 0xFFFFFFFF;
4672 pDecOut
->Lo32
= n
[0] ;
4673 pDecOut
->Mid32
= n
[1];
4674 pDecOut
->Hi32
= n
[2];
4681 return DISP_E_OVERFLOW
; /* overflowed */
4683 pDecOut
->scale
= pDecLeft
->scale
;
4684 pDecOut
->sign
= sign
;
4689 /* translate from external DECIMAL format into an internal representation */
4690 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
)
4692 to
->scale
= from
->scale
;
4693 to
->sign
= from
->sign
? 1 : 0;
4695 to
->bitsnum
[0] = from
->Lo32
;
4696 to
->bitsnum
[1] = from
->Mid32
;
4697 to
->bitsnum
[2] = from
->Hi32
;
4700 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
)
4702 to
->sign
= from
->sign
? DECIMAL_NEG
: DECIMAL_POS
;
4703 to
->scale
= from
->scale
;
4704 to
->Lo32
= from
->bitsnum
[0];
4705 to
->Mid32
= from
->bitsnum
[1];
4706 to
->Hi32
= from
->bitsnum
[2];
4709 /* clear an internal representation of a DECIMAL */
4710 static void VARIANT_DI_clear(VARIANT_DI
* i
)
4712 memset(i
, 0, sizeof(VARIANT_DI
));
4715 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4716 size is supported. The value in p is replaced by the quotient of the division, and
4717 the remainder is returned as a result. This routine is most often used with a divisor
4718 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4720 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
)
4725 } else if (divisor
== 1) {
4726 /* dividend remains unchanged */
4729 unsigned char remainder
= 0;
4730 ULONGLONG iTempDividend
;
4733 for (i
= n
- 1; i
>= 0 && !p
[i
]; i
--); /* skip leading zeros */
4734 for (; i
>= 0; i
--) {
4735 iTempDividend
= ((ULONGLONG
)remainder
<< 32) + p
[i
];
4736 remainder
= iTempDividend
% divisor
;
4737 p
[i
] = iTempDividend
/ divisor
;
4744 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4745 static BOOL
VARIANT_int_iszero(const DWORD
* p
, unsigned int n
)
4747 for (; n
> 0; n
--) if (*p
++ != 0) return FALSE
;
4751 /* multiply two DECIMALS, without changing either one, and place result in third
4752 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4753 digits when scale > 0 in order to fit an overflowing result. Final overflow
4756 static int VARIANT_DI_mul(const VARIANT_DI
* a
, const VARIANT_DI
* b
, VARIANT_DI
* result
)
4758 BOOL r_overflow
= FALSE
;
4760 signed int mulstart
;
4762 VARIANT_DI_clear(result
);
4763 result
->sign
= (a
->sign
^ b
->sign
) ? 1 : 0;
4765 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4766 of the result is formed by adding the scales of the operands.
4768 result
->scale
= a
->scale
+ b
->scale
;
4769 memset(running
, 0, sizeof(running
));
4771 /* count number of leading zero-bytes in operand A */
4772 for (mulstart
= ARRAY_SIZE(a
->bitsnum
) - 1; mulstart
>= 0 && !a
->bitsnum
[mulstart
]; mulstart
--);
4774 /* result is 0, because operand A is 0 */
4778 unsigned char remainder
= 0;
4781 /* perform actual multiplication */
4782 for (iA
= 0; iA
<= mulstart
; iA
++) {
4786 for (iOverflowMul
= 0, iB
= 0; iB
< ARRAY_SIZE(b
->bitsnum
); iB
++) {
4790 iRV
= VARIANT_Mul(b
->bitsnum
[iB
], a
->bitsnum
[iA
], &iOverflowMul
);
4793 running
[iR
] = VARIANT_Add(running
[iR
], 0, &iRV
);
4799 /* Too bad - native oleaut does not do this, so we should not either */
4801 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4802 This operation should not lose significant digits, and gives an
4803 opportunity to reduce the possibility of overflows in future
4804 operations issued by the application.
4806 while (result
->scale
> 0) {
4807 memcpy(quotient
, running
, sizeof(quotient
));
4808 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4809 if (remainder
> 0) break;
4810 memcpy(running
, quotient
, sizeof(quotient
));
4814 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4815 This operation *will* lose significant digits of the result because
4816 all the factors of 10 were consumed by the previous operation.
4818 while (result
->scale
> 0 && !VARIANT_int_iszero(running
+ ARRAY_SIZE(result
->bitsnum
),
4819 ARRAY_SIZE(running
) - ARRAY_SIZE(result
->bitsnum
))) {
4821 remainder
= VARIANT_int_divbychar(running
, ARRAY_SIZE(running
), 10);
4822 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4826 /* round up the result - native oleaut32 does this */
4827 if (remainder
>= 5) {
4829 for (remainder
= 1, i
= 0; i
< ARRAY_SIZE(running
) && remainder
; i
++) {
4830 ULONGLONG digit
= running
[i
] + 1;
4831 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4832 running
[i
] = digit
& 0xFFFFFFFF;
4836 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4837 and copy result bits into result structure
4839 r_overflow
= !VARIANT_int_iszero(running
+ ARRAY_SIZE(result
->bitsnum
),
4840 ARRAY_SIZE(running
) - ARRAY_SIZE(result
->bitsnum
));
4841 memcpy(result
->bitsnum
, running
, sizeof(result
->bitsnum
));
4846 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4847 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4848 success, FALSE if insufficient space in output buffer.
4850 static BOOL
VARIANT_DI_tostringW(const VARIANT_DI
* a
, WCHAR
* s
, unsigned int n
)
4852 BOOL overflow
= FALSE
;
4854 unsigned char remainder
;
4857 /* place negative sign */
4858 if (!VARIANT_int_iszero(a
->bitsnum
, ARRAY_SIZE(a
->bitsnum
)) && a
->sign
) {
4863 else overflow
= TRUE
;
4866 /* prepare initial 0 */
4871 } else overflow
= TRUE
;
4875 memcpy(quotient
, a
->bitsnum
, sizeof(a
->bitsnum
));
4876 while (!overflow
&& !VARIANT_int_iszero(quotient
, ARRAY_SIZE(quotient
))) {
4877 remainder
= VARIANT_int_divbychar(quotient
, ARRAY_SIZE(quotient
), 10);
4881 s
[i
++] = '0' + remainder
;
4886 if (!overflow
&& !VARIANT_int_iszero(a
->bitsnum
, ARRAY_SIZE(a
->bitsnum
))) {
4888 /* reverse order of digits */
4889 WCHAR
* x
= s
; WCHAR
* y
= s
+ i
- 1;
4896 /* check for decimal point. "i" now has string length */
4897 if (i
<= a
->scale
) {
4898 unsigned int numzeroes
= a
->scale
+ 1 - i
;
4899 if (i
+ 1 + numzeroes
>= n
) {
4902 memmove(s
+ numzeroes
, s
, (i
+ 1) * sizeof(WCHAR
));
4904 while (numzeroes
> 0) {
4905 s
[--numzeroes
] = '0';
4910 /* place decimal point */
4912 unsigned int periodpos
= i
- a
->scale
;
4916 memmove(s
+ periodpos
+ 1, s
+ periodpos
, (i
+ 1 - periodpos
) * sizeof(WCHAR
));
4917 s
[periodpos
] = '.'; i
++;
4919 /* remove extra zeros at the end, if any */
4920 while (s
[i
- 1] == '0') s
[--i
] = '\0';
4921 if (s
[i
- 1] == '.') s
[--i
] = '\0';
4929 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4930 static void VARIANT_int_shiftleft(DWORD
* p
, unsigned int n
, unsigned int shift
)
4935 /* shift whole DWORDs to the left */
4938 memmove(p
+ 1, p
, (n
- 1) * sizeof(DWORD
));
4939 *p
= 0; shift
-= 32;
4942 /* shift remainder (1..31 bits) */
4944 if (shift
> 0) for (i
= 0; i
< n
; i
++)
4947 b
= p
[i
] >> (32 - shift
);
4948 p
[i
] = (p
[i
] << shift
) | shifted
;
4953 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4954 Value at v is incremented by the value at p. Any size is supported, provided
4955 that v is not shorter than p. Any unapplied carry is returned as a result.
4957 static unsigned char VARIANT_int_add(DWORD
* v
, unsigned int nv
, const DWORD
* p
,
4960 unsigned char carry
= 0;
4966 for (i
= 0; i
< np
; i
++) {
4967 sum
= (ULONGLONG
)v
[i
]
4970 v
[i
] = sum
& 0xffffffff;
4973 for (; i
< nv
&& carry
; i
++) {
4974 sum
= (ULONGLONG
)v
[i
]
4976 v
[i
] = sum
& 0xffffffff;
4983 /* perform integral division with operand p as dividend. Parameter n indicates
4984 number of available DWORDs in divisor p, but available space in p must be
4985 actually at least 2 * n DWORDs, because the remainder of the integral
4986 division is built in the next n DWORDs past the start of the quotient. This
4987 routine replaces the dividend in p with the quotient, and appends n
4988 additional DWORDs for the remainder.
4990 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4991 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4992 source code to the VLI (Very Large Integer) division operator. This algorithm
4993 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4994 variably-scaled integers such as the MS DECIMAL representation.
4996 static void VARIANT_int_div(DWORD
* p
, unsigned int n
, const DWORD
* divisor
,
5001 DWORD
* negdivisor
= tempsub
+ n
;
5003 /* build 2s-complement of divisor */
5004 for (i
= 0; i
< n
; i
++) negdivisor
[i
] = (i
< dn
) ? ~divisor
[i
] : 0xFFFFFFFF;
5006 VARIANT_int_add(negdivisor
, n
, p
+ n
, 1);
5007 memset(p
+ n
, 0, n
* sizeof(DWORD
));
5009 /* skip all leading zero DWORDs in quotient */
5010 for (i
= 0; i
< n
&& !p
[n
- 1]; i
++) VARIANT_int_shiftleft(p
, n
, 32);
5011 /* i is now number of DWORDs left to process */
5012 for (i
<<= 5; i
< (n
<< 5); i
++) {
5013 VARIANT_int_shiftleft(p
, n
<< 1, 1); /* shl quotient+remainder */
5015 /* trial subtraction */
5016 memcpy(tempsub
, p
+ n
, n
* sizeof(DWORD
));
5017 VARIANT_int_add(tempsub
, n
, negdivisor
, n
);
5019 /* check whether result of subtraction was negative */
5020 if ((tempsub
[n
- 1] & 0x80000000) == 0) {
5021 memcpy(p
+ n
, tempsub
, n
* sizeof(DWORD
));
5027 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
5028 static unsigned char VARIANT_int_mulbychar(DWORD
* p
, unsigned int n
, unsigned char m
)
5033 for (iOverflowMul
= 0, i
= 0; i
< n
; i
++)
5034 p
[i
] = VARIANT_Mul(p
[i
], m
, &iOverflowMul
);
5035 return (unsigned char)iOverflowMul
;
5038 /* increment value in A by the value indicated in B, with scale adjusting.
5039 Modifies parameters by adjusting scales. Returns 0 if addition was
5040 successful, nonzero if a parameter underflowed before it could be
5041 successfully used in the addition.
5043 static int VARIANT_int_addlossy(
5044 DWORD
* a
, int * ascale
, unsigned int an
,
5045 DWORD
* b
, int * bscale
, unsigned int bn
)
5049 if (VARIANT_int_iszero(a
, an
)) {
5050 /* if A is zero, copy B into A, after removing digits */
5051 while (bn
> an
&& !VARIANT_int_iszero(b
+ an
, bn
- an
)) {
5052 VARIANT_int_divbychar(b
, bn
, 10);
5055 memcpy(a
, b
, an
* sizeof(DWORD
));
5057 } else if (!VARIANT_int_iszero(b
, bn
)) {
5058 unsigned int tn
= an
+ 1;
5061 if (bn
+ 1 > tn
) tn
= bn
+ 1;
5062 if (*ascale
!= *bscale
) {
5063 /* first (optimistic) try - try to scale down the one with the bigger
5064 scale, while this number is divisible by 10 */
5065 DWORD
* digitchosen
;
5066 unsigned int nchosen
;
5070 if (*ascale
< *bscale
) {
5071 targetscale
= *ascale
;
5072 scalechosen
= bscale
;
5076 targetscale
= *bscale
;
5077 scalechosen
= ascale
;
5081 memset(t
, 0, tn
* sizeof(DWORD
));
5082 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5084 /* divide by 10 until target scale is reached */
5085 while (*scalechosen
> targetscale
) {
5086 unsigned char remainder
= VARIANT_int_divbychar(t
, tn
, 10);
5089 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5094 if (*ascale
!= *bscale
) {
5095 DWORD
* digitchosen
;
5096 unsigned int nchosen
;
5100 /* try to scale up the one with the smaller scale */
5101 if (*ascale
> *bscale
) {
5102 targetscale
= *ascale
;
5103 scalechosen
= bscale
;
5107 targetscale
= *bscale
;
5108 scalechosen
= ascale
;
5112 memset(t
, 0, tn
* sizeof(DWORD
));
5113 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5115 /* multiply by 10 until target scale is reached, or
5116 significant bytes overflow the number
5118 while (*scalechosen
< targetscale
&& t
[nchosen
] == 0) {
5119 VARIANT_int_mulbychar(t
, tn
, 10);
5120 if (t
[nchosen
] == 0) {
5121 /* still does not overflow */
5123 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5128 if (*ascale
!= *bscale
) {
5129 /* still different? try to scale down the one with the bigger scale
5130 (this *will* lose significant digits) */
5131 DWORD
* digitchosen
;
5132 unsigned int nchosen
;
5136 if (*ascale
< *bscale
) {
5137 targetscale
= *ascale
;
5138 scalechosen
= bscale
;
5142 targetscale
= *bscale
;
5143 scalechosen
= ascale
;
5147 memset(t
, 0, tn
* sizeof(DWORD
));
5148 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5150 /* divide by 10 until target scale is reached */
5151 while (*scalechosen
> targetscale
) {
5152 VARIANT_int_divbychar(t
, tn
, 10);
5154 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5158 /* check whether any of the operands still has significant digits
5161 if (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
)) {
5164 /* at this step, both numbers have the same scale and can be added
5165 as integers. However, the result might not fit in A, so further
5166 scaling down might be necessary.
5168 while (!underflow
) {
5169 memset(t
, 0, tn
* sizeof(DWORD
));
5170 memcpy(t
, a
, an
* sizeof(DWORD
));
5172 VARIANT_int_add(t
, tn
, b
, bn
);
5173 if (VARIANT_int_iszero(t
+ an
, tn
- an
)) {
5174 /* addition was successful */
5175 memcpy(a
, t
, an
* sizeof(DWORD
));
5178 /* addition overflowed - remove significant digits
5179 from both operands and try again */
5180 VARIANT_int_divbychar(a
, an
, 10); (*ascale
)--;
5181 VARIANT_int_divbychar(b
, bn
, 10); (*bscale
)--;
5182 /* check whether any operand keeps significant digits after
5183 scaledown (underflow case 2)
5185 underflow
= (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
));
5193 /* perform complete DECIMAL division in the internal representation. Returns
5194 0 if the division was completed (even if quotient is set to 0), or nonzero
5195 in case of quotient overflow.
5197 static HRESULT
VARIANT_DI_div(const VARIANT_DI
* dividend
, const VARIANT_DI
* divisor
,
5198 VARIANT_DI
* quotient
, BOOL round_remainder
)
5200 HRESULT r_overflow
= S_OK
;
5202 if (VARIANT_int_iszero(divisor
->bitsnum
, ARRAY_SIZE(divisor
->bitsnum
))) {
5204 r_overflow
= DISP_E_DIVBYZERO
;
5205 } else if (VARIANT_int_iszero(dividend
->bitsnum
, ARRAY_SIZE(dividend
->bitsnum
))) {
5206 VARIANT_DI_clear(quotient
);
5208 int quotientscale
, remainderscale
, tempquotientscale
;
5209 DWORD remainderplusquotient
[8];
5212 quotientscale
= remainderscale
= (int)dividend
->scale
- (int)divisor
->scale
;
5213 tempquotientscale
= quotientscale
;
5214 VARIANT_DI_clear(quotient
);
5215 quotient
->sign
= (dividend
->sign
^ divisor
->sign
) ? 1 : 0;
5217 /* The following strategy is used for division
5218 1) if there was a nonzero remainder from previous iteration, use it as
5219 dividend for this iteration, else (for first iteration) use intended
5221 2) perform integer division in temporary buffer, develop quotient in
5222 low-order part, remainder in high-order part
5223 3) add quotient from step 2 to final result, with possible loss of
5225 4) multiply integer part of remainder by 10, while incrementing the
5226 scale of the remainder. This operation preserves the intended value
5228 5) loop to step 1 until one of the following is true:
5229 a) remainder is zero (exact division achieved)
5230 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5232 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5233 memcpy(remainderplusquotient
, dividend
->bitsnum
, sizeof(dividend
->bitsnum
));
5235 VARIANT_int_div(remainderplusquotient
, 4, divisor
->bitsnum
, ARRAY_SIZE(divisor
->bitsnum
));
5236 underflow
= VARIANT_int_addlossy( quotient
->bitsnum
, "ientscale
,
5237 ARRAY_SIZE(quotient
->bitsnum
), remainderplusquotient
, &tempquotientscale
, 4);
5238 if (round_remainder
) {
5239 if(remainderplusquotient
[4] >= 5){
5241 unsigned char remainder
= 1;
5242 for (i
= 0; i
< ARRAY_SIZE(quotient
->bitsnum
) && remainder
; i
++) {
5243 ULONGLONG digit
= quotient
->bitsnum
[i
] + 1;
5244 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5245 quotient
->bitsnum
[i
] = digit
& 0xFFFFFFFF;
5248 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5250 VARIANT_int_mulbychar(remainderplusquotient
+ 4, 4, 10);
5251 memcpy(remainderplusquotient
, remainderplusquotient
+ 4, 4 * sizeof(DWORD
));
5253 tempquotientscale
= ++remainderscale
;
5254 } while (!underflow
&& !VARIANT_int_iszero(remainderplusquotient
+ 4, 4));
5256 /* quotient scale might now be negative (extremely big number). If, so, try
5257 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5258 until scale is 0. If this cannot be done, it is a real overflow.
5260 while (r_overflow
== S_OK
&& quotientscale
< 0) {
5261 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5262 memcpy(remainderplusquotient
, quotient
->bitsnum
, sizeof(quotient
->bitsnum
));
5263 VARIANT_int_mulbychar(remainderplusquotient
, ARRAY_SIZE(remainderplusquotient
), 10);
5264 if (VARIANT_int_iszero(remainderplusquotient
+ ARRAY_SIZE(quotient
->bitsnum
),
5265 ARRAY_SIZE(remainderplusquotient
) - ARRAY_SIZE(quotient
->bitsnum
))) {
5267 memcpy(quotient
->bitsnum
, remainderplusquotient
, sizeof(quotient
->bitsnum
));
5268 } else r_overflow
= DISP_E_OVERFLOW
;
5270 if (r_overflow
== S_OK
) {
5271 if (quotientscale
<= 255) quotient
->scale
= quotientscale
;
5272 else VARIANT_DI_clear(quotient
);
5278 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5279 with an undefined scale, which will be assigned to (if possible). It also
5280 receives an exponent of 2. This procedure will then manipulate the mantissa
5281 and calculate a corresponding scale, so that the exponent2 value is assimilated
5282 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5283 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5285 static HRESULT
VARIANT_DI_normalize(VARIANT_DI
* val
, int exponent2
, BOOL isDouble
)
5287 HRESULT hres
= S_OK
;
5288 int exponent5
, exponent10
;
5290 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5291 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5292 exponent10 might be used to set the VARIANT_DI scale directly. However,
5293 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5294 exponent5
= -exponent2
;
5295 exponent10
= exponent2
;
5297 /* Handle exponent5 > 0 */
5298 while (exponent5
> 0) {
5302 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5303 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5304 somehow the mantissa should be divided by 2. */
5305 if ((val
->bitsnum
[0] & 1) == 0) {
5306 /* The mantissa is divisible by 2. Therefore the division can be done
5307 without losing significant digits. */
5308 exponent10
++; exponent5
--;
5311 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5312 val
->bitsnum
[2] >>= 1;
5313 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5314 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5315 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5317 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5318 be multiplied by 5, unless the multiplication overflows. */
5319 DWORD temp_bitsnum
[3];
5323 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5324 if (0 == VARIANT_int_mulbychar(temp_bitsnum
, 3, 5)) {
5325 /* Multiplication succeeded without overflow, so copy result back
5327 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5329 /* Mask out 3 extraneous bits introduced by the multiply */
5331 /* Multiplication by 5 overflows. The mantissa should be divided
5332 by 2, and therefore will lose significant digits. */
5336 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5337 val
->bitsnum
[2] >>= 1;
5338 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5339 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5340 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5345 /* Handle exponent5 < 0 */
5346 while (exponent5
< 0) {
5347 /* In order to divide the value represented by the VARIANT_DI by 5, it
5348 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5349 and the mantissa should be multiplied by 2 */
5350 if ((val
->bitsnum
[2] & 0x80000000) == 0) {
5351 /* The mantissa can withstand a shift-left without overflowing */
5352 exponent10
--; exponent5
++;
5353 VARIANT_int_shiftleft(val
->bitsnum
, 3, 1);
5355 /* The mantissa would overflow if shifted. Therefore it should be
5356 directly divided by 5. This will lose significant digits, unless
5357 by chance the mantissa happens to be divisible by 5 */
5359 VARIANT_int_divbychar(val
->bitsnum
, 3, 5);
5363 /* At this point, the mantissa has assimilated the exponent5, but the
5364 exponent10 might not be suitable for assignment. The exponent10 must be
5365 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5366 down appropriately. */
5367 while (hres
== S_OK
&& exponent10
> 0) {
5368 /* In order to bring exponent10 down to 0, the mantissa should be
5369 multiplied by 10 to compensate. If the exponent10 is too big, this
5370 will cause the mantissa to overflow. */
5371 if (0 == VARIANT_int_mulbychar(val
->bitsnum
, 3, 10)) {
5374 hres
= DISP_E_OVERFLOW
;
5377 while (exponent10
< -DEC_MAX_SCALE
) {
5379 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5380 be divided by 10 to compensate. If the exponent10 is too small, this
5381 will cause the mantissa to underflow and become 0 */
5382 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5384 if (VARIANT_int_iszero(val
->bitsnum
, 3)) {
5385 /* Underflow, unable to keep dividing */
5387 } else if (rem10
>= 5) {
5389 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5392 /* This step is required in order to remove excess bits of precision from the
5393 end of the bit representation, down to the precision guaranteed by the
5394 floating point number. */
5396 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || (val
->bitsnum
[1] & 0xFFE00000) != 0)) {
5399 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5403 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5407 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || val
->bitsnum
[1] != 0 ||
5408 (val
->bitsnum
[2] == 0 && val
->bitsnum
[1] == 0 && (val
->bitsnum
[0] & 0xFF000000) != 0))) {
5411 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5415 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5419 /* Remove multiples of 10 from the representation */
5420 while (exponent10
< 0) {
5421 DWORD temp_bitsnum
[3];
5423 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5424 if (0 == VARIANT_int_divbychar(temp_bitsnum
, 3, 10)) {
5426 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5430 /* Scale assignment */
5431 if (hres
== S_OK
) val
->scale
= -exponent10
;
5440 unsigned int m
: 23;
5441 unsigned int exp_bias
: 8;
5442 unsigned int sign
: 1;
5447 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5448 intermediate string step. */
5449 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
)
5451 HRESULT hres
= S_OK
;
5456 /* Detect special cases */
5457 if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0) {
5458 /* Floating-point zero */
5459 VARIANT_DI_clear(dest
);
5460 } else if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0xFF) {
5461 /* Floating-point infinity */
5462 hres
= DISP_E_OVERFLOW
;
5463 } else if (fx
.i
.exp_bias
== 0xFF) {
5464 /* Floating-point NaN */
5465 hres
= DISP_E_BADVARTYPE
;
5468 VARIANT_DI_clear(dest
);
5470 exponent2
= fx
.i
.exp_bias
- 127; /* Get unbiased exponent */
5471 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5473 /* Copy significant bits to VARIANT_DI mantissa */
5474 dest
->bitsnum
[0] = fx
.i
.m
;
5475 dest
->bitsnum
[0] &= 0x007FFFFF;
5476 if (fx
.i
.exp_bias
== 0) {
5477 /* Denormalized number - correct exponent */
5480 /* Add hidden bit to mantissa */
5481 dest
->bitsnum
[0] |= 0x00800000;
5484 /* The act of copying a FP mantissa as integer bits is equivalent to
5485 shifting left the mantissa 23 bits. The exponent2 is reduced to
5489 hres
= VARIANT_DI_normalize(dest
, exponent2
, FALSE
);
5499 unsigned int m_lo
: 32; /* 52 bits of precision */
5500 unsigned int m_hi
: 20;
5501 unsigned int exp_bias
: 11; /* bias == 1023 */
5502 unsigned int sign
: 1;
5507 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5508 intermediate string step. */
5509 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
)
5511 HRESULT hres
= S_OK
;
5516 /* Detect special cases */
5517 if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0) {
5518 /* Floating-point zero */
5519 VARIANT_DI_clear(dest
);
5520 } else if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0x7FF) {
5521 /* Floating-point infinity */
5522 hres
= DISP_E_OVERFLOW
;
5523 } else if (fx
.i
.exp_bias
== 0x7FF) {
5524 /* Floating-point NaN */
5525 hres
= DISP_E_BADVARTYPE
;
5528 VARIANT_DI_clear(dest
);
5530 exponent2
= fx
.i
.exp_bias
- 1023; /* Get unbiased exponent */
5531 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5533 /* Copy significant bits to VARIANT_DI mantissa */
5534 dest
->bitsnum
[0] = fx
.i
.m_lo
;
5535 dest
->bitsnum
[1] = fx
.i
.m_hi
;
5536 dest
->bitsnum
[1] &= 0x000FFFFF;
5537 if (fx
.i
.exp_bias
== 0) {
5538 /* Denormalized number - correct exponent */
5541 /* Add hidden bit to mantissa */
5542 dest
->bitsnum
[1] |= 0x00100000;
5545 /* The act of copying a FP mantissa as integer bits is equivalent to
5546 shifting left the mantissa 52 bits. The exponent2 is reduced to
5550 hres
= VARIANT_DI_normalize(dest
, exponent2
, TRUE
);
5556 static HRESULT
VARIANT_do_division(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
, DECIMAL
*pDecOut
,
5559 HRESULT hRet
= S_OK
;
5560 VARIANT_DI di_left
, di_right
, di_result
;
5563 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5564 VARIANT_DIFromDec(pDecRight
, &di_right
);
5565 divresult
= VARIANT_DI_div(&di_left
, &di_right
, &di_result
, round
);
5566 if (divresult
!= S_OK
)
5568 /* division actually overflowed */
5575 if (di_result
.scale
> DEC_MAX_SCALE
)
5577 unsigned char remainder
= 0;
5579 /* division underflowed. In order to comply with the MSDN
5580 specifications for DECIMAL ranges, some significant digits
5583 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5585 while (di_result
.scale
> DEC_MAX_SCALE
&&
5586 !VARIANT_int_iszero(di_result
.bitsnum
, ARRAY_SIZE(di_result
.bitsnum
)))
5588 remainder
= VARIANT_int_divbychar(di_result
.bitsnum
, ARRAY_SIZE(di_result
.bitsnum
), 10);
5591 if (di_result
.scale
> DEC_MAX_SCALE
)
5593 WARN("result underflowed, setting to 0\n");
5594 di_result
.scale
= 0;
5597 else if (remainder
>= 5) /* round up result - native oleaut32 does this */
5600 for (remainder
= 1, i
= 0; i
< ARRAY_SIZE(di_result
.bitsnum
) && remainder
; i
++) {
5601 ULONGLONG digit
= di_result
.bitsnum
[i
] + 1;
5602 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5603 di_result
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
5607 VARIANT_DecFromDI(&di_result
, pDecOut
);
5612 /************************************************************************
5613 * VarDecDiv (OLEAUT32.178)
5615 * Divide one DECIMAL by another.
5618 * pDecLeft [I] Source
5619 * pDecRight [I] Value to divide by
5620 * pDecOut [O] Destination
5624 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5626 HRESULT WINAPI
VarDecDiv(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5628 if (!pDecLeft
|| !pDecRight
|| !pDecOut
) return E_INVALIDARG
;
5630 return VARIANT_do_division(pDecLeft
, pDecRight
, pDecOut
, FALSE
);
5633 /************************************************************************
5634 * VarDecMul (OLEAUT32.179)
5636 * Multiply one DECIMAL by another.
5639 * pDecLeft [I] Source
5640 * pDecRight [I] Value to multiply by
5641 * pDecOut [O] Destination
5645 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5647 HRESULT WINAPI
VarDecMul(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5649 HRESULT hRet
= S_OK
;
5650 VARIANT_DI di_left
, di_right
, di_result
;
5653 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5654 VARIANT_DIFromDec(pDecRight
, &di_right
);
5655 mulresult
= VARIANT_DI_mul(&di_left
, &di_right
, &di_result
);
5658 /* multiplication actually overflowed */
5659 hRet
= DISP_E_OVERFLOW
;
5663 if (di_result
.scale
> DEC_MAX_SCALE
)
5665 /* multiplication underflowed. In order to comply with the MSDN
5666 specifications for DECIMAL ranges, some significant digits
5669 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5671 while (di_result
.scale
> DEC_MAX_SCALE
&&
5672 !VARIANT_int_iszero(di_result
.bitsnum
, ARRAY_SIZE(di_result
.bitsnum
)))
5674 VARIANT_int_divbychar(di_result
.bitsnum
, ARRAY_SIZE(di_result
.bitsnum
), 10);
5677 if (di_result
.scale
> DEC_MAX_SCALE
)
5679 WARN("result underflowed, setting to 0\n");
5680 di_result
.scale
= 0;
5684 VARIANT_DecFromDI(&di_result
, pDecOut
);
5689 /************************************************************************
5690 * VarDecSub (OLEAUT32.181)
5692 * Subtract one DECIMAL from another.
5695 * pDecLeft [I] Source
5696 * pDecRight [I] DECIMAL to subtract from pDecLeft
5697 * pDecOut [O] Destination
5700 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5702 HRESULT WINAPI
VarDecSub(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5706 /* Implement as addition of the negative */
5707 VarDecNeg(pDecRight
, &decRight
);
5708 return VarDecAdd(pDecLeft
, &decRight
, pDecOut
);
5711 /************************************************************************
5712 * VarDecAbs (OLEAUT32.182)
5714 * Convert a DECIMAL into its absolute value.
5718 * pDecOut [O] Destination
5721 * S_OK. This function does not fail.
5723 HRESULT WINAPI
VarDecAbs(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5726 pDecOut
->sign
&= ~DECIMAL_NEG
;
5730 /************************************************************************
5731 * VarDecFix (OLEAUT32.187)
5733 * Return the integer portion of a DECIMAL.
5737 * pDecOut [O] Destination
5741 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5744 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5745 * negative numbers away from 0, while this function rounds them towards zero.
5747 HRESULT WINAPI
VarDecFix(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5752 if (pDecIn
->sign
& ~DECIMAL_NEG
)
5753 return E_INVALIDARG
;
5757 *pDecOut
= *pDecIn
; /* Already an integer */
5761 hr
= VarR8FromDec(pDecIn
, &dbl
);
5762 if (SUCCEEDED(hr
)) {
5763 LONGLONG rounded
= dbl
;
5765 hr
= VarDecFromI8(rounded
, pDecOut
);
5770 /************************************************************************
5771 * VarDecInt (OLEAUT32.188)
5773 * Return the integer portion of a DECIMAL.
5777 * pDecOut [O] Destination
5781 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5784 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5785 * negative numbers towards 0, while this function rounds them away from zero.
5787 HRESULT WINAPI
VarDecInt(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5792 if (pDecIn
->sign
& ~DECIMAL_NEG
)
5793 return E_INVALIDARG
;
5795 if (!(pDecIn
->sign
& DECIMAL_NEG
) || !pDecIn
->scale
)
5796 return VarDecFix(pDecIn
, pDecOut
); /* The same, if +ve or no fractionals */
5798 hr
= VarR8FromDec(pDecIn
, &dbl
);
5799 if (SUCCEEDED(hr
)) {
5800 LONGLONG rounded
= dbl
>= 0.0 ? dbl
+ 0.5 : dbl
- 0.5;
5802 hr
= VarDecFromI8(rounded
, pDecOut
);
5807 /************************************************************************
5808 * VarDecNeg (OLEAUT32.189)
5810 * Change the sign of a DECIMAL.
5814 * pDecOut [O] Destination
5817 * S_OK. This function does not fail.
5819 HRESULT WINAPI
VarDecNeg(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5822 pDecOut
->sign
^= DECIMAL_NEG
;
5826 /************************************************************************
5827 * VarDecRound (OLEAUT32.203)
5829 * Change the precision of a DECIMAL.
5833 * cDecimals [I] New number of decimals to keep
5834 * pDecOut [O] Destination
5837 * Success: S_OK. pDecOut contains the rounded value.
5838 * Failure: E_INVALIDARG if any argument is invalid.
5840 HRESULT WINAPI
VarDecRound(const DECIMAL
* pDecIn
, int cDecimals
, DECIMAL
* pDecOut
)
5842 DECIMAL divisor
, tmp
;
5846 if (cDecimals
< 0 || (pDecIn
->sign
& ~DECIMAL_NEG
) || pDecIn
->scale
> DEC_MAX_SCALE
)
5847 return E_INVALIDARG
;
5849 if (cDecimals
>= pDecIn
->scale
)
5851 *pDecOut
= *pDecIn
; /* More precision than we have */
5855 /* truncate significant digits and rescale */
5856 memset(&divisor
, 0, sizeof(divisor
));
5859 memset(&tmp
, 0, sizeof(tmp
));
5861 for (i
= 0; i
< pDecIn
->scale
- cDecimals
; ++i
)
5863 hr
= VarDecMul(&divisor
, &tmp
, &divisor
);
5868 hr
= VARIANT_do_division(pDecIn
, &divisor
, pDecOut
, TRUE
);
5872 pDecOut
->scale
= cDecimals
;
5877 /************************************************************************
5878 * VarDecCmp (OLEAUT32.204)
5880 * Compare two DECIMAL values.
5883 * pDecLeft [I] Source
5884 * pDecRight [I] Value to compare
5887 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5888 * is less than, equal to or greater than pDecRight respectively.
5889 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5891 HRESULT WINAPI
VarDecCmp(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
)
5896 if (!pDecLeft
|| !pDecRight
)
5899 if ((!(pDecLeft
->sign
& DECIMAL_NEG
)) && (pDecRight
->sign
& DECIMAL_NEG
) &&
5900 (pDecLeft
->Hi32
|| pDecLeft
->Lo64
))
5902 else if ((pDecLeft
->sign
& DECIMAL_NEG
) && (!(pDecRight
->sign
& DECIMAL_NEG
)) &&
5903 (pDecLeft
->Hi32
|| pDecLeft
->Lo64
))
5906 /* Subtract right from left, and compare the result to 0 */
5907 hRet
= VarDecSub(pDecLeft
, pDecRight
, &result
);
5909 if (SUCCEEDED(hRet
))
5911 int non_zero
= result
.Hi32
|| result
.Lo64
;
5913 if ((result
.sign
& DECIMAL_NEG
) && non_zero
)
5914 hRet
= (HRESULT
)VARCMP_LT
;
5916 hRet
= (HRESULT
)VARCMP_GT
;
5918 hRet
= (HRESULT
)VARCMP_EQ
;
5923 /************************************************************************
5924 * VarDecCmpR8 (OLEAUT32.298)
5926 * Compare a DECIMAL to a double
5929 * pDecLeft [I] DECIMAL Source
5930 * dblRight [I] double to compare to pDecLeft
5933 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5934 * is less than, equal to or greater than pDecLeft respectively.
5935 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5937 HRESULT WINAPI
VarDecCmpR8(const DECIMAL
* pDecLeft
, double dblRight
)
5942 hRet
= VarDecFromR8(dblRight
, &decRight
);
5944 if (SUCCEEDED(hRet
))
5945 hRet
= VarDecCmp(pDecLeft
, &decRight
);
5953 /************************************************************************
5954 * VarBoolFromUI1 (OLEAUT32.118)
5956 * Convert a VT_UI1 to a VT_BOOL.
5960 * pBoolOut [O] Destination
5965 HRESULT WINAPI
VarBoolFromUI1(BYTE bIn
, VARIANT_BOOL
*pBoolOut
)
5967 *pBoolOut
= bIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5971 /************************************************************************
5972 * VarBoolFromI2 (OLEAUT32.119)
5974 * Convert a VT_I2 to a VT_BOOL.
5978 * pBoolOut [O] Destination
5983 HRESULT WINAPI
VarBoolFromI2(SHORT sIn
, VARIANT_BOOL
*pBoolOut
)
5985 *pBoolOut
= sIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5989 /************************************************************************
5990 * VarBoolFromI4 (OLEAUT32.120)
5992 * Convert a VT_I4 to a VT_BOOL.
5996 * pBoolOut [O] Destination
6001 HRESULT WINAPI
VarBoolFromI4(LONG lIn
, VARIANT_BOOL
*pBoolOut
)
6003 *pBoolOut
= lIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6007 /************************************************************************
6008 * VarBoolFromR4 (OLEAUT32.121)
6010 * Convert a VT_R4 to a VT_BOOL.
6014 * pBoolOut [O] Destination
6019 HRESULT WINAPI
VarBoolFromR4(FLOAT fltIn
, VARIANT_BOOL
*pBoolOut
)
6021 *pBoolOut
= fltIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6025 /************************************************************************
6026 * VarBoolFromR8 (OLEAUT32.122)
6028 * Convert a VT_R8 to a VT_BOOL.
6032 * pBoolOut [O] Destination
6037 HRESULT WINAPI
VarBoolFromR8(double dblIn
, VARIANT_BOOL
*pBoolOut
)
6039 *pBoolOut
= dblIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6043 /************************************************************************
6044 * VarBoolFromDate (OLEAUT32.123)
6046 * Convert a VT_DATE to a VT_BOOL.
6050 * pBoolOut [O] Destination
6055 HRESULT WINAPI
VarBoolFromDate(DATE dateIn
, VARIANT_BOOL
*pBoolOut
)
6057 *pBoolOut
= dateIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6061 /************************************************************************
6062 * VarBoolFromCy (OLEAUT32.124)
6064 * Convert a VT_CY to a VT_BOOL.
6068 * pBoolOut [O] Destination
6073 HRESULT WINAPI
VarBoolFromCy(CY cyIn
, VARIANT_BOOL
*pBoolOut
)
6075 *pBoolOut
= cyIn
.int64
? VARIANT_TRUE
: VARIANT_FALSE
;
6079 /************************************************************************
6080 * VARIANT_GetLocalisedText [internal]
6082 * Get a localized string from the resources
6085 static BOOL
VARIANT_GetLocalisedText(LANGID langId
, DWORD dwId
, WCHAR
*lpszDest
)
6089 hrsrc
= FindResourceExW( hProxyDll
, (LPWSTR
)RT_STRING
,
6090 MAKEINTRESOURCEW((dwId
>> 4) + 1), langId
);
6093 HGLOBAL hmem
= LoadResource( hProxyDll
, hrsrc
);
6100 p
= LockResource( hmem
);
6101 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
6103 memcpy( lpszDest
, p
+ 1, *p
* sizeof(WCHAR
) );
6104 lpszDest
[*p
] = '\0';
6105 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest
), langId
);
6112 /************************************************************************
6113 * VarBoolFromStr (OLEAUT32.125)
6115 * Convert a VT_BSTR to a VT_BOOL.
6119 * lcid [I] LCID for the conversion
6120 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6121 * pBoolOut [O] Destination
6125 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6126 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6129 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6130 * it may contain (in any case mapping) the text "true" or "false".
6131 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6132 * localised text of "True" or "False" in the language specified by lcid.
6133 * - If none of these matches occur, the string is treated as a numeric string
6134 * and the boolean pBoolOut will be set according to whether the number is zero
6135 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6136 * - If the text is not numeric and does not match any of the above, then
6137 * DISP_E_TYPEMISMATCH is returned.
6139 HRESULT WINAPI
VarBoolFromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, VARIANT_BOOL
*pBoolOut
)
6142 LANGID langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6143 HRESULT hRes
= S_OK
;
6145 if (!strIn
|| !pBoolOut
)
6146 return DISP_E_TYPEMISMATCH
;
6148 /* Check if we should be comparing against localised text */
6149 if (dwFlags
& VAR_LOCALBOOL
)
6151 /* Convert our LCID into a usable value */
6152 lcid
= ConvertDefaultLocale(lcid
);
6154 langId
= LANGIDFROMLCID(lcid
);
6156 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6157 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6159 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6160 * I don't think this is needed unless any of the localised text strings
6161 * contain characters that can be so mapped. In the event that this is
6162 * true for a given language (possibly some Asian languages), then strIn
6163 * should be mapped here _only_ if langId is an Id for which this can occur.
6167 /* Note that if we are not comparing against localised strings, langId
6168 * will have its default value of LANG_ENGLISH. This allows us to mimic
6169 * the native behaviour of always checking against English strings even
6170 * after we've checked for localised ones.
6172 VarBoolFromStr_CheckLocalised
:
6173 if (VARIANT_GetLocalisedText(langId
, IDS_TRUE
, szBuff
))
6175 /* Compare against localised strings, ignoring case */
6176 if (!wcsicmp(strIn
, szBuff
))
6178 *pBoolOut
= VARIANT_TRUE
; /* Matched localised 'true' text */
6181 VARIANT_GetLocalisedText(langId
, IDS_FALSE
, szBuff
);
6182 if (!wcsicmp(strIn
, szBuff
))
6184 *pBoolOut
= VARIANT_FALSE
; /* Matched localised 'false' text */
6189 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6191 /* We have checked the localised text, now check English */
6192 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6193 goto VarBoolFromStr_CheckLocalised
;
6196 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6197 if (!wcscmp(strIn
, L
"#FALSE#"))
6198 *pBoolOut
= VARIANT_FALSE
;
6199 else if (!wcscmp(strIn
, L
"#TRUE#"))
6200 *pBoolOut
= VARIANT_TRUE
;
6205 /* If this string is a number, convert it as one */
6206 hRes
= VarR8FromStr(strIn
, lcid
, dwFlags
, &d
);
6207 if (SUCCEEDED(hRes
)) *pBoolOut
= d
? VARIANT_TRUE
: VARIANT_FALSE
;
6212 /************************************************************************
6213 * VarBoolFromDisp (OLEAUT32.126)
6215 * Convert a VT_DISPATCH to a VT_BOOL.
6218 * pdispIn [I] Source
6219 * lcid [I] LCID for conversion
6220 * pBoolOut [O] Destination
6224 * Failure: E_INVALIDARG, if the source value is invalid
6225 * DISP_E_OVERFLOW, if the value will not fit in the destination
6226 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6228 HRESULT WINAPI
VarBoolFromDisp(IDispatch
* pdispIn
, LCID lcid
, VARIANT_BOOL
*pBoolOut
)
6230 return VARIANT_FromDisp(pdispIn
, lcid
, pBoolOut
, VT_BOOL
, 0);
6233 /************************************************************************
6234 * VarBoolFromI1 (OLEAUT32.233)
6236 * Convert a VT_I1 to a VT_BOOL.
6240 * pBoolOut [O] Destination
6245 HRESULT WINAPI
VarBoolFromI1(signed char cIn
, VARIANT_BOOL
*pBoolOut
)
6247 *pBoolOut
= cIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6251 /************************************************************************
6252 * VarBoolFromUI2 (OLEAUT32.234)
6254 * Convert a VT_UI2 to a VT_BOOL.
6258 * pBoolOut [O] Destination
6263 HRESULT WINAPI
VarBoolFromUI2(USHORT usIn
, VARIANT_BOOL
*pBoolOut
)
6265 *pBoolOut
= usIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6269 /************************************************************************
6270 * VarBoolFromUI4 (OLEAUT32.235)
6272 * Convert a VT_UI4 to a VT_BOOL.
6276 * pBoolOut [O] Destination
6281 HRESULT WINAPI
VarBoolFromUI4(ULONG ulIn
, VARIANT_BOOL
*pBoolOut
)
6283 *pBoolOut
= ulIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6287 /************************************************************************
6288 * VarBoolFromDec (OLEAUT32.236)
6290 * Convert a VT_DECIMAL to a VT_BOOL.
6294 * pBoolOut [O] Destination
6298 * Failure: E_INVALIDARG, if pDecIn is invalid.
6300 HRESULT WINAPI
VarBoolFromDec(const DECIMAL
* pDecIn
, VARIANT_BOOL
*pBoolOut
)
6302 if (pDecIn
->scale
> DEC_MAX_SCALE
|| (pDecIn
->sign
& ~DECIMAL_NEG
))
6303 return E_INVALIDARG
;
6305 if (pDecIn
->Hi32
|| pDecIn
->Lo64
)
6306 *pBoolOut
= VARIANT_TRUE
;
6308 *pBoolOut
= VARIANT_FALSE
;
6312 /************************************************************************
6313 * VarBoolFromI8 (OLEAUT32.370)
6315 * Convert a VT_I8 to a VT_BOOL.
6319 * pBoolOut [O] Destination
6324 HRESULT WINAPI
VarBoolFromI8(LONG64 llIn
, VARIANT_BOOL
*pBoolOut
)
6326 *pBoolOut
= llIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6330 /************************************************************************
6331 * VarBoolFromUI8 (OLEAUT32.371)
6333 * Convert a VT_UI8 to a VT_BOOL.
6337 * pBoolOut [O] Destination
6342 HRESULT WINAPI
VarBoolFromUI8(ULONG64 ullIn
, VARIANT_BOOL
*pBoolOut
)
6344 *pBoolOut
= ullIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6351 /* Write a number from a UI8 and sign */
6352 static WCHAR
*VARIANT_WriteNumber(ULONG64 ulVal
, WCHAR
* szOut
)
6356 WCHAR ulNextDigit
= ulVal
% 10;
6358 *szOut
-- = '0' + ulNextDigit
;
6359 ulVal
= (ulVal
- ulNextDigit
) / 10;
6366 /* Create a (possibly localised) BSTR from a UI8 and sign */
6367 static BSTR
VARIANT_MakeBstr(LCID lcid
, DWORD dwFlags
, WCHAR
*szOut
)
6369 WCHAR szConverted
[256];
6371 if (dwFlags
& VAR_NEGATIVE
)
6374 if (dwFlags
& LOCALE_USE_NLS
)
6376 /* Format the number for the locale */
6377 szConverted
[0] = '\0';
6378 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6379 szOut
, NULL
, szConverted
, ARRAY_SIZE(szConverted
));
6380 szOut
= szConverted
;
6382 return SysAllocStringByteLen((LPCSTR
)szOut
, lstrlenW(szOut
) * sizeof(WCHAR
));
6385 /* Create a (possibly localised) BSTR from a UI8 and sign */
6386 static HRESULT
VARIANT_BstrFromUInt(ULONG64 ulVal
, LCID lcid
, DWORD dwFlags
, BSTR
*pbstrOut
)
6388 WCHAR szBuff
[64], *szOut
= szBuff
+ ARRAY_SIZE(szBuff
) - 1;
6391 return E_INVALIDARG
;
6393 /* Create the basic number string */
6395 szOut
= VARIANT_WriteNumber(ulVal
, szOut
);
6397 *pbstrOut
= VARIANT_MakeBstr(lcid
, dwFlags
, szOut
);
6398 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6399 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6402 /******************************************************************************
6403 * VarBstrFromUI1 (OLEAUT32.108)
6405 * Convert a VT_UI1 to a VT_BSTR.
6409 * lcid [I] LCID for the conversion
6410 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6411 * pbstrOut [O] Destination
6415 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6416 * E_OUTOFMEMORY, if memory allocation fails.
6418 HRESULT WINAPI
VarBstrFromUI1(BYTE bIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6420 return VARIANT_BstrFromUInt(bIn
, lcid
, dwFlags
, pbstrOut
);
6423 /******************************************************************************
6424 * VarBstrFromI2 (OLEAUT32.109)
6426 * Convert a VT_I2 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
VarBstrFromI2(short sIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6446 dwFlags
|= VAR_NEGATIVE
;
6448 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6451 /******************************************************************************
6452 * VarBstrFromI4 (OLEAUT32.110)
6454 * Convert a VT_I4 to a VT_BSTR.
6458 * lcid [I] LCID for the conversion
6459 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6460 * pbstrOut [O] Destination
6464 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6465 * E_OUTOFMEMORY, if memory allocation fails.
6467 HRESULT WINAPI
VarBstrFromI4(LONG lIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6473 ul64
= -(LONG64
)lIn
;
6474 dwFlags
|= VAR_NEGATIVE
;
6476 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6479 static BSTR
VARIANT_BstrReplaceDecimal(const WCHAR
* buff
, LCID lcid
, ULONG dwFlags
)
6482 WCHAR lpDecimalSep
[16];
6484 /* Native oleaut32 uses the locale-specific decimal separator even in the
6485 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6486 American locales will see "one thousand and one tenth" as "1000,1"
6487 instead of "1000.1" (notice the comma). The following code checks for
6488 the need to replace the decimal separator, and if so, will prepare an
6489 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6491 GetLocaleInfoW(lcid
, LOCALE_SDECIMAL
| (dwFlags
& LOCALE_NOUSEROVERRIDE
),
6492 lpDecimalSep
, ARRAY_SIZE(lpDecimalSep
));
6493 if (lpDecimalSep
[0] == '.' && lpDecimalSep
[1] == '\0')
6495 /* locale is compatible with English - return original string */
6496 bstrOut
= SysAllocString(buff
);
6502 WCHAR empty
[] = L
"";
6503 NUMBERFMTW minFormat
;
6505 minFormat
.NumDigits
= 0;
6506 minFormat
.Grouping
= 0;
6507 minFormat
.lpDecimalSep
= lpDecimalSep
;
6508 minFormat
.lpThousandSep
= empty
;
6509 minFormat
.NegativeOrder
= 1; /* NLS_NEG_LEFT */
6511 GetLocaleInfoW(lcid
, LOCALE_ILZERO
| LOCALE_RETURN_NUMBER
| (dwFlags
& LOCALE_NOUSEROVERRIDE
),
6512 (WCHAR
*)&minFormat
.LeadingZero
, sizeof(DWORD
)/sizeof(WCHAR
) );
6514 /* count number of decimal digits in string */
6515 p
= wcschr( buff
, '.' );
6516 if (p
) minFormat
.NumDigits
= lstrlenW(p
+ 1);
6519 if (!GetNumberFormatW(lcid
, 0, buff
, &minFormat
, numbuff
, ARRAY_SIZE(numbuff
)))
6521 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6522 bstrOut
= SysAllocString(buff
);
6526 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff
));
6527 bstrOut
= SysAllocString(numbuff
);
6533 static HRESULT
VARIANT_BstrFromReal(DOUBLE dblIn
, LCID lcid
, ULONG dwFlags
,
6534 BSTR
* pbstrOut
, LPCWSTR lpszFormat
)
6540 return E_INVALIDARG
;
6542 if (!(locale
= _create_locale(LC_ALL
, "C"))) return E_OUTOFMEMORY
;
6543 _swprintf_l(buff
, ARRAY_SIZE(buff
), lpszFormat
, locale
, dblIn
);
6544 _free_locale(locale
);
6546 /* Negative zeroes are disallowed (some applications depend on this).
6547 If buff starts with a minus, and then nothing follows but zeroes
6548 and/or a period, it is a negative zero and is replaced with a
6549 canonical zero. This duplicates native oleaut32 behavior.
6553 if (lstrlenW(buff
+ 1) == wcsspn(buff
+ 1, L
"0."))
6554 { buff
[0] = '0'; buff
[1] = '\0'; }
6557 TRACE("created string %s\n", debugstr_w(buff
));
6558 if (dwFlags
& LOCALE_USE_NLS
)
6562 /* Format the number for the locale */
6564 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6565 buff
, NULL
, numbuff
, ARRAY_SIZE(numbuff
));
6566 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
6567 *pbstrOut
= SysAllocString(numbuff
);
6571 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
6573 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6576 /******************************************************************************
6577 * VarBstrFromR4 (OLEAUT32.111)
6579 * Convert a VT_R4 to a VT_BSTR.
6583 * lcid [I] LCID for the conversion
6584 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6585 * pbstrOut [O] Destination
6589 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6590 * E_OUTOFMEMORY, if memory allocation fails.
6592 HRESULT WINAPI
VarBstrFromR4(FLOAT fltIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6594 return VARIANT_BstrFromReal(fltIn
, lcid
, dwFlags
, pbstrOut
, L
"%.7G");
6597 /******************************************************************************
6598 * VarBstrFromR8 (OLEAUT32.112)
6600 * Convert a VT_R8 to a VT_BSTR.
6604 * lcid [I] LCID for the conversion
6605 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6606 * pbstrOut [O] Destination
6610 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6611 * E_OUTOFMEMORY, if memory allocation fails.
6613 HRESULT WINAPI
VarBstrFromR8(double dblIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6615 return VARIANT_BstrFromReal(dblIn
, lcid
, dwFlags
, pbstrOut
, L
"%.15G");
6618 /******************************************************************************
6619 * VarBstrFromCy [OLEAUT32.113]
6621 * Convert a VT_CY to a VT_BSTR.
6625 * lcid [I] LCID for the conversion
6626 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6627 * pbstrOut [O] Destination
6631 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6632 * E_OUTOFMEMORY, if memory allocation fails.
6634 HRESULT WINAPI
VarBstrFromCy(CY cyIn
, LCID lcid
, ULONG dwFlags
, BSTR
*pbstrOut
)
6640 return E_INVALIDARG
;
6644 decVal
.bitsnum
[0] = cyIn
.Lo
;
6645 decVal
.bitsnum
[1] = cyIn
.Hi
;
6646 if (cyIn
.Hi
& 0x80000000UL
) {
6649 /* Negative number! */
6651 decVal
.bitsnum
[0] = ~decVal
.bitsnum
[0];
6652 decVal
.bitsnum
[1] = ~decVal
.bitsnum
[1];
6653 VARIANT_int_add(decVal
.bitsnum
, 3, &one
, 1);
6655 decVal
.bitsnum
[2] = 0;
6656 VARIANT_DI_tostringW(&decVal
, buff
, ARRAY_SIZE(buff
));
6658 if (dwFlags
& LOCALE_USE_NLS
)
6662 /* Format the currency for the locale */
6664 GetCurrencyFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6665 buff
, NULL
, cybuff
, ARRAY_SIZE(cybuff
));
6666 *pbstrOut
= SysAllocString(cybuff
);
6669 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
,lcid
,dwFlags
);
6671 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6674 static inline int output_int_len(int o
, int min_len
, WCHAR
*date
, int date_len
)
6678 if(min_len
>= date_len
)
6681 for(len
=0, tmp
=o
; tmp
; tmp
/=10) len
++;
6686 for(tmp
=min_len
-len
; tmp
>0; tmp
--)
6688 for(tmp
=len
; tmp
>0; tmp
--, o
/=10)
6689 date
[tmp
-1] = '0' + o
%10;
6690 return min_len
>len
? min_len
: len
;
6693 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6694 BOOL
get_date_format(LCID lcid
, DWORD flags
, const SYSTEMTIME
*st
,
6695 const WCHAR
*fmt
, WCHAR
*date
, int date_len
)
6697 static const LCTYPE dayname
[] = {
6698 LOCALE_SDAYNAME7
, LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
,
6699 LOCALE_SDAYNAME4
, LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
6701 static const LCTYPE sdayname
[] = {
6702 LOCALE_SABBREVDAYNAME7
, LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
,
6703 LOCALE_SABBREVDAYNAME3
, LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
,
6704 LOCALE_SABBREVDAYNAME6
6706 static const LCTYPE monthname
[] = {
6707 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
6708 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
6709 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
6711 static const LCTYPE smonthname
[] = {
6712 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
6713 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
6714 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
6715 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
6718 if(flags
& ~(LOCALE_NOUSEROVERRIDE
|VAR_DATEVALUEONLY
))
6719 FIXME("ignoring flags %lx\n", flags
);
6720 flags
&= LOCALE_NOUSEROVERRIDE
;
6722 while(*fmt
&& date_len
) {
6730 while(*fmt
== *(fmt
+count
))
6738 count
= GetLocaleInfoW(lcid
, dayname
[st
->wDayOfWeek
] | flags
, date
, date_len
)-1;
6740 count
= GetLocaleInfoW(lcid
, sdayname
[st
->wDayOfWeek
] | flags
, date
, date_len
)-1;
6742 count
= output_int_len(st
->wDay
, count
, date
, date_len
);
6746 count
= GetLocaleInfoW(lcid
, monthname
[st
->wMonth
-1] | flags
, date
, date_len
)-1;
6748 count
= GetLocaleInfoW(lcid
, smonthname
[st
->wMonth
-1] | flags
, date
, date_len
)-1;
6750 count
= output_int_len(st
->wMonth
, count
, date
, date_len
);
6754 count
= output_int_len(st
->wYear
, 0, date
, date_len
);
6756 count
= output_int_len(st
->wYear
%100, count
, date
, date_len
);
6760 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6788 /******************************************************************************
6789 * VarBstrFromDate [OLEAUT32.114]
6791 * Convert a VT_DATE to a VT_BSTR.
6795 * lcid [I] LCID for the conversion
6796 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6797 * pbstrOut [O] Destination
6801 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6802 * E_OUTOFMEMORY, if memory allocation fails.
6804 HRESULT WINAPI
VarBstrFromDate(DATE dateIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6807 DWORD dwFormatFlags
= dwFlags
& LOCALE_NOUSEROVERRIDE
;
6808 WCHAR date
[128], fmt_buff
[80], *time
;
6810 TRACE("%g, %#lx, %#lx, %p.\n", dateIn
, lcid
, dwFlags
, pbstrOut
);
6812 if (!pbstrOut
|| !VariantTimeToSystemTime(dateIn
, &st
))
6813 return E_INVALIDARG
;
6817 if (dwFlags
& VAR_CALENDAR_THAI
)
6818 st
.wYear
+= 553; /* Use the Thai buddhist calendar year */
6819 else if (dwFlags
& (VAR_CALENDAR_HIJRI
|VAR_CALENDAR_GREGORIAN
))
6820 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6822 if (dwFlags
& LOCALE_USE_NLS
)
6823 dwFlags
&= ~(VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
);
6826 double whole
= dateIn
< 0 ? ceil(dateIn
) : floor(dateIn
);
6827 double partial
= dateIn
- whole
;
6830 dwFlags
|= VAR_TIMEVALUEONLY
;
6831 else if (partial
> -1e-12 && partial
< 1e-12)
6832 dwFlags
|= VAR_DATEVALUEONLY
;
6835 if (dwFlags
& VAR_TIMEVALUEONLY
)
6838 if (!GetLocaleInfoW(lcid
, LOCALE_SSHORTDATE
, fmt_buff
, ARRAY_SIZE(fmt_buff
)) ||
6839 !get_date_format(lcid
, dwFlags
, &st
, fmt_buff
, date
, ARRAY_SIZE(date
)))
6840 return E_INVALIDARG
;
6842 if (!(dwFlags
& VAR_DATEVALUEONLY
))
6844 time
= date
+ lstrlenW(date
);
6847 if (!GetTimeFormatW(lcid
, dwFormatFlags
, &st
, NULL
, time
, ARRAY_SIZE(date
)-(time
-date
)))
6848 return E_INVALIDARG
;
6851 *pbstrOut
= SysAllocString(date
);
6853 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6854 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6857 /******************************************************************************
6858 * VarBstrFromBool (OLEAUT32.116)
6860 * Convert a VT_BOOL to a VT_BSTR.
6864 * lcid [I] LCID for the conversion
6865 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6866 * pbstrOut [O] Destination
6870 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6871 * E_OUTOFMEMORY, if memory allocation fails.
6874 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6875 * localised text of "True" or "False". To convert a bool into a
6876 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6878 HRESULT WINAPI
VarBstrFromBool(VARIANT_BOOL boolIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6881 DWORD dwResId
= IDS_TRUE
;
6884 TRACE("%d, %#lx, %#lx, %p.\n", boolIn
, lcid
, dwFlags
, pbstrOut
);
6887 return E_INVALIDARG
;
6889 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6890 * for variant formatting */
6891 switch (dwFlags
& (VAR_LOCALBOOL
|VAR_BOOLONOFF
|VAR_BOOLYESNO
))
6902 lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
),SORT_DEFAULT
);
6905 lcid
= ConvertDefaultLocale(lcid
);
6906 langId
= LANGIDFROMLCID(lcid
);
6907 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6908 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6910 if (boolIn
== VARIANT_FALSE
)
6911 dwResId
++; /* Use negative form */
6913 VarBstrFromBool_GetLocalised
:
6914 if (VARIANT_GetLocalisedText(langId
, dwResId
, szBuff
))
6916 *pbstrOut
= SysAllocString(szBuff
);
6917 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6920 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6922 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6923 goto VarBstrFromBool_GetLocalised
;
6926 /* Should never get here */
6927 WARN("Failed to load bool text!\n");
6928 return E_OUTOFMEMORY
;
6931 /******************************************************************************
6932 * VarBstrFromI1 (OLEAUT32.229)
6934 * Convert a VT_I1 to a VT_BSTR.
6938 * lcid [I] LCID for the conversion
6939 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6940 * pbstrOut [O] Destination
6944 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6945 * E_OUTOFMEMORY, if memory allocation fails.
6947 HRESULT WINAPI
VarBstrFromI1(signed char cIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6954 dwFlags
|= VAR_NEGATIVE
;
6956 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6959 /******************************************************************************
6960 * VarBstrFromUI2 (OLEAUT32.230)
6962 * Convert a VT_UI2 to a VT_BSTR.
6966 * lcid [I] LCID for the conversion
6967 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6968 * pbstrOut [O] Destination
6972 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6973 * E_OUTOFMEMORY, if memory allocation fails.
6975 HRESULT WINAPI
VarBstrFromUI2(USHORT usIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6977 return VARIANT_BstrFromUInt(usIn
, lcid
, dwFlags
, pbstrOut
);
6980 /******************************************************************************
6981 * VarBstrFromUI4 (OLEAUT32.231)
6983 * Convert a VT_UI4 to a VT_BSTR.
6987 * lcid [I] LCID for the conversion
6988 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6989 * pbstrOut [O] Destination
6993 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6994 * E_OUTOFMEMORY, if memory allocation fails.
6996 HRESULT WINAPI
VarBstrFromUI4(ULONG ulIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6998 return VARIANT_BstrFromUInt(ulIn
, lcid
, dwFlags
, pbstrOut
);
7001 /******************************************************************************
7002 * VarBstrFromDec (OLEAUT32.232)
7004 * Convert a VT_DECIMAL to a VT_BSTR.
7008 * lcid [I] LCID for the conversion
7009 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7010 * pbstrOut [O] Destination
7014 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7015 * E_OUTOFMEMORY, if memory allocation fails.
7017 HRESULT WINAPI
VarBstrFromDec(const DECIMAL
* pDecIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7023 return E_INVALIDARG
;
7025 VARIANT_DIFromDec(pDecIn
, &temp
);
7026 VARIANT_DI_tostringW(&temp
, buff
, 256);
7028 if (dwFlags
& LOCALE_USE_NLS
)
7032 /* Format the number for the locale */
7034 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
7035 buff
, NULL
, numbuff
, ARRAY_SIZE(numbuff
));
7036 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
7037 *pbstrOut
= SysAllocString(numbuff
);
7041 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
7044 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
7045 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
7048 /************************************************************************
7049 * VarBstrFromI8 (OLEAUT32.370)
7051 * Convert a VT_I8 to a VT_BSTR.
7055 * lcid [I] LCID for the conversion
7056 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7057 * pbstrOut [O] Destination
7061 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7062 * E_OUTOFMEMORY, if memory allocation fails.
7064 HRESULT WINAPI
VarBstrFromI8(LONG64 llIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7066 ULONG64 ul64
= llIn
;
7071 dwFlags
|= VAR_NEGATIVE
;
7073 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
7076 /************************************************************************
7077 * VarBstrFromUI8 (OLEAUT32.371)
7079 * Convert a VT_UI8 to a VT_BSTR.
7083 * lcid [I] LCID for the conversion
7084 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7085 * pbstrOut [O] Destination
7089 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7090 * E_OUTOFMEMORY, if memory allocation fails.
7092 HRESULT WINAPI
VarBstrFromUI8(ULONG64 ullIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7094 return VARIANT_BstrFromUInt(ullIn
, lcid
, dwFlags
, pbstrOut
);
7097 /************************************************************************
7098 * VarBstrFromDisp (OLEAUT32.115)
7100 * Convert a VT_DISPATCH to a BSTR.
7103 * pdispIn [I] Source
7104 * lcid [I] LCID for conversion
7105 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7106 * pbstrOut [O] Destination
7110 * Failure: E_INVALIDARG, if the source value is invalid
7111 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7113 HRESULT WINAPI
VarBstrFromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7115 return VARIANT_FromDisp(pdispIn
, lcid
, pbstrOut
, VT_BSTR
, dwFlags
);
7118 /**********************************************************************
7119 * VarBstrCat (OLEAUT32.313)
7121 * Concatenate two BSTR values.
7124 * pbstrLeft [I] Source
7125 * pbstrRight [I] Value to concatenate
7126 * pbstrOut [O] Destination
7130 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7131 * E_OUTOFMEMORY, if memory allocation fails.
7133 HRESULT WINAPI
VarBstrCat(BSTR pbstrLeft
, BSTR pbstrRight
, BSTR
*pbstrOut
)
7135 unsigned int lenLeft
, lenRight
;
7138 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
7139 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), pbstrOut
);
7142 return E_INVALIDARG
;
7144 /* use byte length here to properly handle ansi-allocated BSTRs */
7145 lenLeft
= pbstrLeft
? SysStringByteLen(pbstrLeft
) : 0;
7146 lenRight
= pbstrRight
? SysStringByteLen(pbstrRight
) : 0;
7148 *pbstrOut
= SysAllocStringByteLen(NULL
, lenLeft
+ lenRight
);
7150 return E_OUTOFMEMORY
;
7152 (*pbstrOut
)[0] = '\0';
7155 memcpy(*pbstrOut
, pbstrLeft
, lenLeft
);
7158 memcpy((CHAR
*)*pbstrOut
+ lenLeft
, pbstrRight
, lenRight
);
7160 TRACE("%s\n", debugstr_wn(*pbstrOut
, SysStringLen(*pbstrOut
)));
7164 /**********************************************************************
7165 * VarBstrCmp (OLEAUT32.314)
7167 * Compare two BSTR values.
7170 * pbstrLeft [I] Source
7171 * pbstrRight [I] Value to compare
7172 * lcid [I] LCID for the comparison
7173 * dwFlags [I] Flags to pass directly to CompareStringW().
7176 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7177 * than, equal to or greater than pbstrRight respectively.
7180 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7181 * states. A NULL BSTR pointer is equivalent to an empty string.
7182 * If LCID is equal to 0, a byte by byte comparison is performed.
7184 HRESULT WINAPI
VarBstrCmp(BSTR pbstrLeft
, BSTR pbstrRight
, LCID lcid
, DWORD dwFlags
)
7189 TRACE("%s, %s, %#lx, %#lx.\n",
7190 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
7191 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), lcid
, dwFlags
);
7193 if (!pbstrLeft
|| !*pbstrLeft
)
7195 if (pbstrRight
&& *pbstrRight
)
7198 else if (!pbstrRight
|| !*pbstrRight
)
7203 unsigned int lenLeft
= SysStringByteLen(pbstrLeft
);
7204 unsigned int lenRight
= SysStringByteLen(pbstrRight
);
7205 ret
= memcmp(pbstrLeft
, pbstrRight
, min(lenLeft
, lenRight
));
7210 if (lenLeft
< lenRight
)
7212 if (lenLeft
> lenRight
)
7218 unsigned int lenLeft
= SysStringLen(pbstrLeft
);
7219 unsigned int lenRight
= SysStringLen(pbstrRight
);
7221 if (lenLeft
== 0 || lenRight
== 0)
7223 if (lenLeft
== 0 && lenRight
== 0) return VARCMP_EQ
;
7224 return lenLeft
< lenRight
? VARCMP_LT
: VARCMP_GT
;
7227 hres
= CompareStringW(lcid
, dwFlags
, pbstrLeft
, lenLeft
,
7228 pbstrRight
, lenRight
) - CSTR_LESS_THAN
;
7229 TRACE("%ld\n", hres
);
7238 /******************************************************************************
7239 * VarDateFromUI1 (OLEAUT32.88)
7241 * Convert a VT_UI1 to a VT_DATE.
7245 * pdateOut [O] Destination
7250 HRESULT WINAPI
VarDateFromUI1(BYTE bIn
, DATE
* pdateOut
)
7252 return VarR8FromUI1(bIn
, pdateOut
);
7255 /******************************************************************************
7256 * VarDateFromI2 (OLEAUT32.89)
7258 * Convert a VT_I2 to a VT_DATE.
7262 * pdateOut [O] Destination
7267 HRESULT WINAPI
VarDateFromI2(short sIn
, DATE
* pdateOut
)
7269 return VarR8FromI2(sIn
, pdateOut
);
7272 /******************************************************************************
7273 * VarDateFromI4 (OLEAUT32.90)
7275 * Convert a VT_I4 to a VT_DATE.
7279 * pdateOut [O] Destination
7284 HRESULT WINAPI
VarDateFromI4(LONG lIn
, DATE
* pdateOut
)
7286 return VarDateFromR8(lIn
, pdateOut
);
7289 /******************************************************************************
7290 * VarDateFromR4 (OLEAUT32.91)
7292 * Convert a VT_R4 to a VT_DATE.
7296 * pdateOut [O] Destination
7301 HRESULT WINAPI
VarDateFromR4(FLOAT fltIn
, DATE
* pdateOut
)
7303 return VarR8FromR4(fltIn
, pdateOut
);
7306 /******************************************************************************
7307 * VarDateFromR8 (OLEAUT32.92)
7309 * Convert a VT_R8 to a VT_DATE.
7313 * pdateOut [O] Destination
7318 HRESULT WINAPI
VarDateFromR8(double dblIn
, DATE
* pdateOut
)
7320 if (dblIn
<= (DATE_MIN
- 1.0) || dblIn
>= (DATE_MAX
+ 1.0)) return DISP_E_OVERFLOW
;
7321 *pdateOut
= (DATE
)dblIn
;
7325 /**********************************************************************
7326 * VarDateFromDisp (OLEAUT32.95)
7328 * Convert a VT_DISPATCH to a VT_DATE.
7331 * pdispIn [I] Source
7332 * lcid [I] LCID for conversion
7333 * pdateOut [O] Destination
7337 * Failure: E_INVALIDARG, if the source value is invalid
7338 * DISP_E_OVERFLOW, if the value will not fit in the destination
7339 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7341 HRESULT WINAPI
VarDateFromDisp(IDispatch
* pdispIn
, LCID lcid
, DATE
* pdateOut
)
7343 return VARIANT_FromDisp(pdispIn
, lcid
, pdateOut
, VT_DATE
, 0);
7346 /******************************************************************************
7347 * VarDateFromBool (OLEAUT32.96)
7349 * Convert a VT_BOOL to a VT_DATE.
7353 * pdateOut [O] Destination
7358 HRESULT WINAPI
VarDateFromBool(VARIANT_BOOL boolIn
, DATE
* pdateOut
)
7360 return VarR8FromBool(boolIn
, pdateOut
);
7363 /**********************************************************************
7364 * VarDateFromCy (OLEAUT32.93)
7366 * Convert a VT_CY to a VT_DATE.
7370 * pdateOut [O] Destination
7375 HRESULT WINAPI
VarDateFromCy(CY cyIn
, DATE
* pdateOut
)
7377 return VarR8FromCy(cyIn
, pdateOut
);
7380 /* Date string parsing */
7381 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7382 #define DP_DATESEP 0x02 /* Date separator */
7383 #define DP_MONTH 0x04 /* Month name */
7384 #define DP_AM 0x08 /* AM */
7385 #define DP_PM 0x10 /* PM */
7387 typedef struct tagDATEPARSE
7389 DWORD dwCount
; /* Number of fields found so far (maximum 6) */
7390 DWORD dwParseFlags
; /* Global parse flags (DP_ Flags above) */
7391 DWORD dwFlags
[6]; /* Flags for each field */
7392 DWORD dwValues
[6]; /* Value of each field */
7395 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7397 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7399 /* Determine if a day is valid in a given month of a given year */
7400 static BOOL
VARIANT_IsValidMonthDay(DWORD day
, DWORD month
, DWORD year
)
7402 static const BYTE days
[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7404 if (day
&& month
&& month
< 13)
7406 if (day
<= days
[month
] || (month
== 2 && day
== 29 && IsLeapYear(year
)))
7412 /* Possible orders for 3 numbers making up a date */
7413 #define ORDER_MDY 0x01
7414 #define ORDER_YMD 0x02
7415 #define ORDER_YDM 0x04
7416 #define ORDER_DMY 0x08
7417 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7419 /* Determine a date for a particular locale, from 3 numbers */
7420 static inline HRESULT
VARIANT_MakeDate(DATEPARSE
*dp
, DWORD iDate
,
7421 DWORD offset
, SYSTEMTIME
*st
)
7423 DWORD dwAllOrders
, dwTry
, dwCount
= 0, v1
, v2
, v3
;
7427 v1
= 30; /* Default to (Variant) 0 date part */
7430 goto VARIANT_MakeDate_OK
;
7433 v1
= dp
->dwValues
[offset
+ 0];
7434 v2
= dp
->dwValues
[offset
+ 1];
7435 if (dp
->dwCount
== 2)
7438 GetSystemTime(¤t
);
7442 v3
= dp
->dwValues
[offset
+ 2];
7444 TRACE("%ld, %ld, %ld, %ld, %ld.\n", v1
, v2
, v3
, iDate
, offset
);
7446 /* If one number must be a month (Because a month name was given), then only
7447 * consider orders with the month in that position.
7448 * If we took the current year as 'v3', then only allow a year in that position.
7450 if (dp
->dwFlags
[offset
+ 0] & DP_MONTH
)
7452 dwAllOrders
= ORDER_MDY
;
7454 else if (dp
->dwFlags
[offset
+ 1] & DP_MONTH
)
7456 dwAllOrders
= ORDER_DMY
;
7457 if (dp
->dwCount
> 2)
7458 dwAllOrders
|= ORDER_YMD
;
7460 else if (dp
->dwCount
> 2 && dp
->dwFlags
[offset
+ 2] & DP_MONTH
)
7462 dwAllOrders
= ORDER_YDM
;
7466 dwAllOrders
= ORDER_MDY
|ORDER_DMY
;
7467 if (dp
->dwCount
> 2)
7468 dwAllOrders
|= (ORDER_YMD
|ORDER_YDM
);
7471 VARIANT_MakeDate_Start
:
7472 TRACE("dwAllOrders is %#lx\n", dwAllOrders
);
7480 /* First: Try the order given by iDate */
7483 case 0: dwTry
= dwAllOrders
& ORDER_MDY
; break;
7484 case 1: dwTry
= dwAllOrders
& ORDER_DMY
; break;
7485 default: dwTry
= dwAllOrders
& ORDER_YMD
; break;
7488 else if (dwCount
== 1)
7490 /* Second: Try all the orders compatible with iDate */
7493 case 0: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7494 case 1: dwTry
= dwAllOrders
& ~(ORDER_MDY
|ORDER_YDM
|ORDER_MYD
); break;
7495 default: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7500 /* Finally: Try any remaining orders */
7501 dwTry
= dwAllOrders
;
7504 TRACE("Attempt %ld, dwTry is %#lx\n", dwCount
, dwTry
);
7510 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7512 if (dwTry
& ORDER_MDY
)
7514 if (VARIANT_IsValidMonthDay(v2
,v1
,v3
))
7517 goto VARIANT_MakeDate_OK
;
7519 dwAllOrders
&= ~ORDER_MDY
;
7521 if (dwTry
& ORDER_YMD
)
7523 if (VARIANT_IsValidMonthDay(v3
,v2
,v1
))
7526 goto VARIANT_MakeDate_OK
;
7528 dwAllOrders
&= ~ORDER_YMD
;
7530 if (dwTry
& ORDER_YDM
)
7532 if (VARIANT_IsValidMonthDay(v2
,v3
,v1
))
7536 goto VARIANT_MakeDate_OK
;
7538 dwAllOrders
&= ~ORDER_YDM
;
7540 if (dwTry
& ORDER_DMY
)
7542 if (VARIANT_IsValidMonthDay(v1
,v2
,v3
))
7543 goto VARIANT_MakeDate_OK
;
7544 dwAllOrders
&= ~ORDER_DMY
;
7546 if (dwTry
& ORDER_MYD
)
7548 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7549 if (VARIANT_IsValidMonthDay(v3
,v1
,v2
))
7553 goto VARIANT_MakeDate_OK
;
7555 dwAllOrders
&= ~ORDER_MYD
;
7559 if (dp
->dwCount
== 2)
7561 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7562 v3
= 1; /* 1st of the month */
7563 dwAllOrders
= ORDER_YMD
|ORDER_MYD
;
7564 dp
->dwCount
= 0; /* Don't return to this code path again */
7566 goto VARIANT_MakeDate_Start
;
7569 /* No valid dates were able to be constructed */
7570 return DISP_E_TYPEMISMATCH
;
7572 VARIANT_MakeDate_OK
:
7574 /* Check that the time part is ok */
7575 if (st
->wHour
> 23 || st
->wMinute
> 59 || st
->wSecond
> 59)
7576 return DISP_E_TYPEMISMATCH
;
7578 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7579 if (st
->wHour
< 12 && (dp
->dwParseFlags
& DP_PM
))
7581 else if (st
->wHour
== 12 && (dp
->dwParseFlags
& DP_AM
))
7583 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7587 /* FIXME: For 2 digit dates old versions of Windows used 29 but
7588 * Windows 10 1903 and greater use 49. This cutoff may also be modified by
7589 * setting the value as a string for the relevant calendar id in the
7592 * For instance to emulate old Windows versions:
7593 * [HKCU\Control Panel\International\Calendars\TwoDigitYearMax]
7595 * (also 2, 9, 10, 11 and 12 for the other Gregorian calendars)
7597 * But Wine doesn't have/use that key at the time of writing.
7599 st
->wYear
= v3
<= 49 ? 2000 + v3
: v3
<= 99 ? 1900 + v3
: v3
;
7600 TRACE("Returning date %ld/%ld/%d\n", v1
, v2
, st
->wYear
);
7604 /******************************************************************************
7605 * VarDateFromStr [OLEAUT32.94]
7607 * Convert a VT_BSTR to at VT_DATE.
7610 * strIn [I] String to convert
7611 * lcid [I] Locale identifier for the conversion
7612 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7613 * pdateOut [O] Destination for the converted value
7616 * Success: S_OK. pdateOut contains the converted value.
7617 * FAILURE: An HRESULT error code indicating the problem.
7620 * Any date format that can be created using the date formats from lcid
7621 * (Either from kernel Nls functions, variant conversion or formatting) is a
7622 * valid input to this function. In addition, a few more esoteric formats are
7623 * also supported for compatibility with the native version. The date is
7624 * interpreted according to the date settings in the control panel, unless
7625 * the date is invalid in that format, in which the most compatible format
7626 * that produces a valid date will be used.
7628 HRESULT WINAPI
VarDateFromStr(const OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DATE
* pdateOut
)
7630 static const USHORT ParseDateTokens
[] =
7632 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
7633 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
7634 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
,
7635 LOCALE_SMONTHNAME13
,
7636 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
7637 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
7638 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
7639 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
,
7640 LOCALE_SABBREVMONTHNAME13
,
7641 LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
, LOCALE_SDAYNAME4
,
7642 LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
, LOCALE_SDAYNAME7
,
7643 LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
, LOCALE_SABBREVDAYNAME3
,
7644 LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
, LOCALE_SABBREVDAYNAME6
,
7645 LOCALE_SABBREVDAYNAME7
,
7646 LOCALE_S1159
, LOCALE_S2359
,
7649 static const BYTE ParseDateMonths
[] =
7651 1,2,3,4,5,6,7,8,9,10,11,12,13,
7652 1,2,3,4,5,6,7,8,9,10,11,12,13
7655 BSTR tokens
[ARRAY_SIZE(ParseDateTokens
)];
7657 DWORD dwDateSeps
= 0, iDate
= 0;
7658 HRESULT hRet
= S_OK
;
7660 if ((dwFlags
& (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
)) ==
7661 (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
))
7662 return E_INVALIDARG
;
7665 return DISP_E_TYPEMISMATCH
;
7669 TRACE("%s, %#lx, %#lx, %p.\n", debugstr_w(strIn
), lcid
, dwFlags
, pdateOut
);
7671 memset(&dp
, 0, sizeof(dp
));
7673 GetLocaleInfoW(lcid
, LOCALE_IDATE
|LOCALE_RETURN_NUMBER
|(dwFlags
& LOCALE_NOUSEROVERRIDE
),
7674 (LPWSTR
)&iDate
, sizeof(iDate
)/sizeof(WCHAR
));
7675 TRACE("iDate is %ld\n", iDate
);
7677 /* Get the month/day/am/pm tokens for this locale */
7678 for (i
= 0; i
< ARRAY_SIZE(tokens
); i
++)
7681 LCTYPE lctype
= ParseDateTokens
[i
] | (dwFlags
& LOCALE_NOUSEROVERRIDE
);
7683 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7684 * GetAltMonthNames(). We should really cache these strings too.
7687 GetLocaleInfoW(lcid
, lctype
, buff
, ARRAY_SIZE(buff
));
7688 tokens
[i
] = SysAllocString(buff
);
7689 TRACE("token %d is %s\n", i
, debugstr_w(tokens
[i
]));
7692 /* Parse the string into our structure */
7695 if ('0' <= *strIn
&& *strIn
<= '9')
7698 if (dp
.dwCount
>= 6)
7700 hRet
= DISP_E_TYPEMISMATCH
;
7703 dp
.dwValues
[dp
.dwCount
] = wcstoul(strIn
, &end
, 10);
7707 else if (iswalpha(*strIn
))
7709 BOOL bFound
= FALSE
;
7711 for (i
= 0; i
< ARRAY_SIZE(tokens
); i
++)
7713 DWORD dwLen
= lstrlenW(tokens
[i
]);
7714 if (dwLen
&& !wcsnicmp(strIn
, tokens
[i
], dwLen
))
7718 if (dp
.dwCount
>= 6)
7719 hRet
= DISP_E_TYPEMISMATCH
;
7722 dp
.dwValues
[dp
.dwCount
] = ParseDateMonths
[i
];
7723 dp
.dwFlags
[dp
.dwCount
] |= (DP_MONTH
|DP_DATESEP
);
7727 else if (i
> 39 && i
< 42)
7729 if (!dp
.dwCount
|| dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7730 hRet
= DISP_E_TYPEMISMATCH
;
7733 dp
.dwFlags
[dp
.dwCount
- 1] |= (i
== 40 ? DP_AM
: DP_PM
);
7734 dp
.dwParseFlags
|= (i
== 40 ? DP_AM
: DP_PM
);
7737 strIn
+= (dwLen
- 1);
7745 if ((*strIn
== 'a' || *strIn
== 'A' || *strIn
== 'p' || *strIn
== 'P') &&
7746 (dp
.dwCount
&& !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7748 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7749 if (*strIn
== 'a' || *strIn
== 'A')
7751 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_AM
;
7752 dp
.dwParseFlags
|= DP_AM
;
7756 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_PM
;
7757 dp
.dwParseFlags
|= DP_PM
;
7763 TRACE("No matching token for %s\n", debugstr_w(strIn
));
7764 hRet
= DISP_E_TYPEMISMATCH
;
7769 else if (*strIn
== ':' || *strIn
== '.')
7771 if (!dp
.dwCount
|| !strIn
[1])
7772 hRet
= DISP_E_TYPEMISMATCH
;
7774 if (tokens
[42][0] == *strIn
)
7778 hRet
= DISP_E_TYPEMISMATCH
;
7780 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7783 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_TIMESEP
;
7785 else if (*strIn
== '-' || *strIn
== '/')
7788 if (dwDateSeps
> 2 || !dp
.dwCount
|| !strIn
[1])
7789 hRet
= DISP_E_TYPEMISMATCH
;
7791 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7793 else if (*strIn
== ',' || iswspace(*strIn
))
7795 if (*strIn
== ',' && !strIn
[1])
7796 hRet
= DISP_E_TYPEMISMATCH
;
7800 hRet
= DISP_E_TYPEMISMATCH
;
7805 if (!dp
.dwCount
|| dp
.dwCount
> 6 ||
7806 (dp
.dwCount
== 1 && !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7807 hRet
= DISP_E_TYPEMISMATCH
;
7809 if (SUCCEEDED(hRet
))
7812 DWORD dwOffset
= 0; /* Start of date fields in dp.dwValues */
7814 st
.wDayOfWeek
= st
.wHour
= st
.wMinute
= st
.wSecond
= st
.wMilliseconds
= 0;
7816 /* Figure out which numbers correspond to which fields.
7818 * This switch statement works based on the fact that native interprets any
7819 * fields that are not joined with a time separator ('.' or ':') as date
7820 * fields. Thus we construct a value from 0-32 where each set bit indicates
7821 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7822 * For valid permutations, we set dwOffset to point to the first date field
7823 * and shorten dp.dwCount by the number of time fields found. The real
7824 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7825 * each date number must represent in the context of iDate.
7827 TRACE("%#lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7829 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7831 case 0x1: /* TT TTDD TTDDD */
7832 if (dp
.dwCount
> 3 &&
7833 ((dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) ||
7834 (dp
.dwFlags
[4] & (DP_AM
|DP_PM
))))
7835 hRet
= DISP_E_TYPEMISMATCH
;
7836 else if (dp
.dwCount
!= 2 && dp
.dwCount
!= 4 && dp
.dwCount
!= 5)
7837 hRet
= DISP_E_TYPEMISMATCH
;
7838 st
.wHour
= dp
.dwValues
[0];
7839 st
.wMinute
= dp
.dwValues
[1];
7844 case 0x3: /* TTT TTTDD TTTDDD */
7845 if (dp
.dwCount
> 4 &&
7846 ((dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[4] & (DP_AM
|DP_PM
)) ||
7847 (dp
.dwFlags
[5] & (DP_AM
|DP_PM
))))
7848 hRet
= DISP_E_TYPEMISMATCH
;
7849 else if (dp
.dwCount
!= 3 && dp
.dwCount
!= 5 && dp
.dwCount
!= 6)
7850 hRet
= DISP_E_TYPEMISMATCH
;
7851 st
.wHour
= dp
.dwValues
[0];
7852 st
.wMinute
= dp
.dwValues
[1];
7853 st
.wSecond
= dp
.dwValues
[2];
7858 case 0x4: /* DDTT */
7859 if (dp
.dwCount
!= 4 ||
7860 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7861 hRet
= DISP_E_TYPEMISMATCH
;
7863 st
.wHour
= dp
.dwValues
[2];
7864 st
.wMinute
= dp
.dwValues
[3];
7868 case 0x0: /* T DD DDD TDDD TDDD */
7869 if (dp
.dwCount
== 1 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7871 st
.wHour
= dp
.dwValues
[0]; /* T */
7875 else if (dp
.dwCount
> 4 || (dp
.dwCount
< 3 && dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7877 hRet
= DISP_E_TYPEMISMATCH
;
7879 else if (dp
.dwCount
== 3)
7881 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDD */
7884 st
.wHour
= dp
.dwValues
[0];
7888 if (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) /* DDT */
7891 st
.wHour
= dp
.dwValues
[2];
7894 else if (dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7895 hRet
= DISP_E_TYPEMISMATCH
;
7897 else if (dp
.dwCount
== 4)
7900 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDDD */
7902 st
.wHour
= dp
.dwValues
[0];
7905 else if (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) /* DDDT */
7907 st
.wHour
= dp
.dwValues
[3];
7910 hRet
= DISP_E_TYPEMISMATCH
;
7913 /* .. fall through .. */
7915 case 0x8: /* DDDTT */
7916 if ((dp
.dwCount
== 2 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
))) ||
7917 (dp
.dwCount
== 5 && ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) ||
7918 (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))) ||
7919 dp
.dwCount
== 4 || dp
.dwCount
== 6)
7920 hRet
= DISP_E_TYPEMISMATCH
;
7921 st
.wHour
= dp
.dwValues
[3];
7922 st
.wMinute
= dp
.dwValues
[4];
7923 if (dp
.dwCount
== 5)
7927 case 0xC: /* DDTTT */
7928 if (dp
.dwCount
!= 5 ||
7929 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7930 hRet
= DISP_E_TYPEMISMATCH
;
7931 st
.wHour
= dp
.dwValues
[2];
7932 st
.wMinute
= dp
.dwValues
[3];
7933 st
.wSecond
= dp
.dwValues
[4];
7937 case 0x18: /* DDDTTT */
7938 if ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) ||
7939 (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))
7940 hRet
= DISP_E_TYPEMISMATCH
;
7941 st
.wHour
= dp
.dwValues
[3];
7942 st
.wMinute
= dp
.dwValues
[4];
7943 st
.wSecond
= dp
.dwValues
[5];
7948 hRet
= DISP_E_TYPEMISMATCH
;
7952 if (SUCCEEDED(hRet
))
7954 hRet
= VARIANT_MakeDate(&dp
, iDate
, dwOffset
, &st
);
7956 if (dwFlags
& VAR_TIMEVALUEONLY
)
7962 else if (dwFlags
& VAR_DATEVALUEONLY
)
7963 st
.wHour
= st
.wMinute
= st
.wSecond
= 0;
7965 /* Finally, convert the value to a VT_DATE */
7966 if (SUCCEEDED(hRet
))
7967 hRet
= SystemTimeToVariantTime(&st
, pdateOut
) ? S_OK
: DISP_E_TYPEMISMATCH
;
7971 for (i
= 0; i
< ARRAY_SIZE(tokens
); i
++)
7972 SysFreeString(tokens
[i
]);
7976 /******************************************************************************
7977 * VarDateFromI1 (OLEAUT32.221)
7979 * Convert a VT_I1 to a VT_DATE.
7983 * pdateOut [O] Destination
7988 HRESULT WINAPI
VarDateFromI1(signed char cIn
, DATE
* pdateOut
)
7990 return VarR8FromI1(cIn
, pdateOut
);
7993 /******************************************************************************
7994 * VarDateFromUI2 (OLEAUT32.222)
7996 * Convert a VT_UI2 to a VT_DATE.
8000 * pdateOut [O] Destination
8005 HRESULT WINAPI
VarDateFromUI2(USHORT uiIn
, DATE
* pdateOut
)
8007 return VarR8FromUI2(uiIn
, pdateOut
);
8010 /******************************************************************************
8011 * VarDateFromUI4 (OLEAUT32.223)
8013 * Convert a VT_UI4 to a VT_DATE.
8017 * pdateOut [O] Destination
8022 HRESULT WINAPI
VarDateFromUI4(ULONG ulIn
, DATE
* pdateOut
)
8024 return VarDateFromR8(ulIn
, pdateOut
);
8027 /**********************************************************************
8028 * VarDateFromDec (OLEAUT32.224)
8030 * Convert a VT_DECIMAL to a VT_DATE.
8034 * pdateOut [O] Destination
8039 HRESULT WINAPI
VarDateFromDec(const DECIMAL
*pdecIn
, DATE
* pdateOut
)
8041 return VarR8FromDec(pdecIn
, pdateOut
);
8044 /******************************************************************************
8045 * VarDateFromI8 (OLEAUT32.364)
8047 * Convert a VT_I8 to a VT_DATE.
8051 * pdateOut [O] Destination
8055 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8057 HRESULT WINAPI
VarDateFromI8(LONG64 llIn
, DATE
* pdateOut
)
8059 if (llIn
< DATE_MIN
|| llIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
8060 *pdateOut
= (DATE
)llIn
;
8064 /******************************************************************************
8065 * VarDateFromUI8 (OLEAUT32.365)
8067 * Convert a VT_UI8 to a VT_DATE.
8071 * pdateOut [O] Destination
8075 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8077 HRESULT WINAPI
VarDateFromUI8(ULONG64 ullIn
, DATE
* pdateOut
)
8079 if (ullIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
8080 *pdateOut
= (DATE
)ullIn
;