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
23 WINE_DEFAULT_DEBUG_CHANNEL(variant
);
25 extern HMODULE hProxyDll DECLSPEC_HIDDEN
;
27 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
28 #define CY_MULTIPLIER_F 10000.0
29 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
30 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
32 static const WCHAR szFloatFormatW
[] = { '%','.','7','G','\0' };
33 static const WCHAR szDoubleFormatW
[] = { '%','.','1','5','G','\0' };
35 /* Copy data from one variant to another. */
36 static inline void VARIANT_CopyData(const VARIANT
*srcVar
, VARTYPE vt
, void *pOut
)
41 case VT_UI1
: memcpy(pOut
, &V_UI1(srcVar
), sizeof(BYTE
)); break;
44 case VT_UI2
: memcpy(pOut
, &V_UI2(srcVar
), sizeof(SHORT
)); break;
49 case VT_UI4
: memcpy(pOut
, &V_UI4(srcVar
), sizeof (LONG
)); break;
54 case VT_UI8
: memcpy(pOut
, &V_UI8(srcVar
), sizeof (LONG64
)); break;
55 case VT_INT_PTR
: memcpy(pOut
, &V_INT_PTR(srcVar
), sizeof (INT_PTR
)); break;
56 case VT_DECIMAL
: memcpy(pOut
, &V_DECIMAL(srcVar
), sizeof (DECIMAL
)); break;
57 case VT_BSTR
: memcpy(pOut
, &V_BSTR(srcVar
), sizeof(BSTR
)); break;
59 FIXME("VT_ type %d unhandled, please report!\n", vt
);
63 /* Macro to inline conversion from a float or double to any integer type,
64 * rounding according to the 'dutch' convention.
66 #define VARIANT_DutchRound(typ, value, res) do { \
67 double whole = value < 0 ? ceil(value) : floor(value); \
68 double fract = value - whole; \
69 if (fract > 0.5) res = (typ)whole + (typ)1; \
70 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
71 else if (fract >= 0.0) res = (typ)whole; \
72 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
73 else if (fract > -0.5) res = (typ)whole; \
74 else res = (typ)whole - (typ)1; \
78 /* Coerce VT_BSTR to a numeric type */
79 static HRESULT
VARIANT_NumberFromBstr(OLECHAR
* pStrIn
, LCID lcid
, ULONG ulFlags
,
80 void* pOut
, VARTYPE vt
)
87 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
88 np
.cDig
= sizeof(rgb
) / sizeof(BYTE
);
89 np
.dwInFlags
= NUMPRS_STD
;
91 hRet
= VarParseNumFromStr(pStrIn
, lcid
, ulFlags
, &np
, rgb
);
95 /* 1 << vt gives us the VTBIT constant for the destination number type */
96 hRet
= VarNumFromParseNum(&np
, rgb
, 1 << vt
, &dstVar
);
98 VARIANT_CopyData(&dstVar
, vt
, pOut
);
103 /* Coerce VT_DISPATCH to another type */
104 static HRESULT
VARIANT_FromDisp(IDispatch
* pdispIn
, LCID lcid
, void* pOut
,
105 VARTYPE vt
, DWORD dwFlags
)
107 static DISPPARAMS emptyParams
= { NULL
, NULL
, 0, 0 };
108 VARIANTARG srcVar
, dstVar
;
112 return DISP_E_BADVARTYPE
;
114 /* Get the default 'value' property from the IDispatch */
115 VariantInit(&srcVar
);
116 hRet
= IDispatch_Invoke(pdispIn
, DISPID_VALUE
, &IID_NULL
, lcid
, DISPATCH_PROPERTYGET
,
117 &emptyParams
, &srcVar
, NULL
, NULL
);
121 /* Convert the property to the requested type */
122 VariantInit(&dstVar
);
123 hRet
= VariantChangeTypeEx(&dstVar
, &srcVar
, lcid
, dwFlags
, vt
);
124 VariantClear(&srcVar
);
127 VARIANT_CopyData(&dstVar
, vt
, pOut
);
130 hRet
= DISP_E_TYPEMISMATCH
;
134 /* Inline return type */
135 #define RETTYP static inline HRESULT
138 /* Simple compiler cast from one type to another */
139 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
140 *out = in; return S_OK; }
142 /* Compiler cast where input cannot be negative */
143 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
144 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
146 /* Compiler cast where input cannot be > some number */
147 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
148 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
150 /* Compiler cast where input cannot be < some number or >= some other number */
151 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
152 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
155 POSTST(signed char, BYTE
, VarI1FromUI1
, I1_MAX
)
156 BOTHTST(signed char, SHORT
, VarI1FromI2
, I1_MIN
, I1_MAX
)
157 BOTHTST(signed char, LONG
, VarI1FromI4
, I1_MIN
, I1_MAX
)
158 SIMPLE(signed char, VARIANT_BOOL
, VarI1FromBool
)
159 POSTST(signed char, USHORT
, VarI1FromUI2
, I1_MAX
)
160 POSTST(signed char, ULONG
, VarI1FromUI4
, I1_MAX
)
161 BOTHTST(signed char, LONG64
, VarI1FromI8
, I1_MIN
, I1_MAX
)
162 POSTST(signed char, ULONG64
, VarI1FromUI8
, I1_MAX
)
165 BOTHTST(BYTE
, SHORT
, VarUI1FromI2
, UI1_MIN
, UI1_MAX
)
166 SIMPLE(BYTE
, VARIANT_BOOL
, VarUI1FromBool
)
167 NEGTST(BYTE
, signed char, VarUI1FromI1
)
168 POSTST(BYTE
, USHORT
, VarUI1FromUI2
, UI1_MAX
)
169 BOTHTST(BYTE
, LONG
, VarUI1FromI4
, UI1_MIN
, UI1_MAX
)
170 POSTST(BYTE
, ULONG
, VarUI1FromUI4
, UI1_MAX
)
171 BOTHTST(BYTE
, LONG64
, VarUI1FromI8
, UI1_MIN
, UI1_MAX
)
172 POSTST(BYTE
, ULONG64
, VarUI1FromUI8
, UI1_MAX
)
175 SIMPLE(SHORT
, BYTE
, VarI2FromUI1
)
176 BOTHTST(SHORT
, LONG
, VarI2FromI4
, I2_MIN
, I2_MAX
)
177 SIMPLE(SHORT
, VARIANT_BOOL
, VarI2FromBool
)
178 SIMPLE(SHORT
, signed char, VarI2FromI1
)
179 POSTST(SHORT
, USHORT
, VarI2FromUI2
, I2_MAX
)
180 POSTST(SHORT
, ULONG
, VarI2FromUI4
, I2_MAX
)
181 BOTHTST(SHORT
, LONG64
, VarI2FromI8
, I2_MIN
, I2_MAX
)
182 POSTST(SHORT
, ULONG64
, VarI2FromUI8
, I2_MAX
)
185 SIMPLE(USHORT
, BYTE
, VarUI2FromUI1
)
186 NEGTST(USHORT
, SHORT
, VarUI2FromI2
)
187 BOTHTST(USHORT
, LONG
, VarUI2FromI4
, UI2_MIN
, UI2_MAX
)
188 SIMPLE(USHORT
, VARIANT_BOOL
, VarUI2FromBool
)
189 NEGTST(USHORT
, signed char, VarUI2FromI1
)
190 POSTST(USHORT
, ULONG
, VarUI2FromUI4
, UI2_MAX
)
191 BOTHTST(USHORT
, LONG64
, VarUI2FromI8
, UI2_MIN
, UI2_MAX
)
192 POSTST(USHORT
, ULONG64
, VarUI2FromUI8
, UI2_MAX
)
195 SIMPLE(LONG
, BYTE
, VarI4FromUI1
)
196 SIMPLE(LONG
, SHORT
, VarI4FromI2
)
197 SIMPLE(LONG
, VARIANT_BOOL
, VarI4FromBool
)
198 SIMPLE(LONG
, signed char, VarI4FromI1
)
199 SIMPLE(LONG
, USHORT
, VarI4FromUI2
)
200 POSTST(LONG
, ULONG
, VarI4FromUI4
, I4_MAX
)
201 BOTHTST(LONG
, LONG64
, VarI4FromI8
, I4_MIN
, I4_MAX
)
202 POSTST(LONG
, ULONG64
, VarI4FromUI8
, I4_MAX
)
205 SIMPLE(ULONG
, BYTE
, VarUI4FromUI1
)
206 NEGTST(ULONG
, SHORT
, VarUI4FromI2
)
207 NEGTST(ULONG
, LONG
, VarUI4FromI4
)
208 SIMPLE(ULONG
, VARIANT_BOOL
, VarUI4FromBool
)
209 NEGTST(ULONG
, signed char, VarUI4FromI1
)
210 SIMPLE(ULONG
, USHORT
, VarUI4FromUI2
)
211 BOTHTST(ULONG
, LONG64
, VarUI4FromI8
, UI4_MIN
, UI4_MAX
)
212 POSTST(ULONG
, ULONG64
, VarUI4FromUI8
, UI4_MAX
)
215 SIMPLE(LONG64
, BYTE
, VarI8FromUI1
)
216 SIMPLE(LONG64
, SHORT
, VarI8FromI2
)
217 SIMPLE(LONG64
, signed char, VarI8FromI1
)
218 SIMPLE(LONG64
, USHORT
, VarI8FromUI2
)
219 SIMPLE(LONG64
, ULONG
, VarI8FromUI4
)
220 POSTST(LONG64
, ULONG64
, VarI8FromUI8
, I8_MAX
)
223 SIMPLE(ULONG64
, BYTE
, VarUI8FromUI1
)
224 NEGTST(ULONG64
, SHORT
, VarUI8FromI2
)
225 NEGTST(ULONG64
, signed char, VarUI8FromI1
)
226 SIMPLE(ULONG64
, USHORT
, VarUI8FromUI2
)
227 SIMPLE(ULONG64
, ULONG
, VarUI8FromUI4
)
228 NEGTST(ULONG64
, LONG64
, VarUI8FromI8
)
231 SIMPLE(float, BYTE
, VarR4FromUI1
)
232 SIMPLE(float, SHORT
, VarR4FromI2
)
233 SIMPLE(float, signed char, VarR4FromI1
)
234 SIMPLE(float, USHORT
, VarR4FromUI2
)
235 SIMPLE(float, LONG
, VarR4FromI4
)
236 SIMPLE(float, ULONG
, VarR4FromUI4
)
237 SIMPLE(float, LONG64
, VarR4FromI8
)
238 SIMPLE(float, ULONG64
, VarR4FromUI8
)
241 SIMPLE(double, BYTE
, VarR8FromUI1
)
242 SIMPLE(double, SHORT
, VarR8FromI2
)
243 SIMPLE(double, float, VarR8FromR4
)
244 RETTYP
_VarR8FromCy(CY i
, double* o
) { *o
= (double)i
.int64
/ CY_MULTIPLIER_F
; return S_OK
; }
245 SIMPLE(double, DATE
, VarR8FromDate
)
246 SIMPLE(double, signed char, VarR8FromI1
)
247 SIMPLE(double, USHORT
, VarR8FromUI2
)
248 SIMPLE(double, LONG
, VarR8FromI4
)
249 SIMPLE(double, ULONG
, VarR8FromUI4
)
250 SIMPLE(double, LONG64
, VarR8FromI8
)
251 SIMPLE(double, ULONG64
, VarR8FromUI8
)
257 /************************************************************************
258 * VarI1FromUI1 (OLEAUT32.244)
260 * Convert a VT_UI1 to a VT_I1.
264 * pcOut [O] Destination
268 * Failure: E_INVALIDARG, if the source value is invalid
269 * DISP_E_OVERFLOW, if the value will not fit in the destination
271 HRESULT WINAPI
VarI1FromUI1(BYTE bIn
, signed char* pcOut
)
273 return _VarI1FromUI1(bIn
, pcOut
);
276 /************************************************************************
277 * VarI1FromI2 (OLEAUT32.245)
279 * Convert a VT_I2 to a VT_I1.
283 * pcOut [O] Destination
287 * Failure: E_INVALIDARG, if the source value is invalid
288 * DISP_E_OVERFLOW, if the value will not fit in the destination
290 HRESULT WINAPI
VarI1FromI2(SHORT sIn
, signed char* pcOut
)
292 return _VarI1FromI2(sIn
, pcOut
);
295 /************************************************************************
296 * VarI1FromI4 (OLEAUT32.246)
298 * Convert a VT_I4 to a VT_I1.
302 * pcOut [O] Destination
306 * Failure: E_INVALIDARG, if the source value is invalid
307 * DISP_E_OVERFLOW, if the value will not fit in the destination
309 HRESULT WINAPI
VarI1FromI4(LONG iIn
, signed char* pcOut
)
311 return _VarI1FromI4(iIn
, pcOut
);
314 /************************************************************************
315 * VarI1FromR4 (OLEAUT32.247)
317 * Convert a VT_R4 to a VT_I1.
321 * pcOut [O] Destination
325 * Failure: E_INVALIDARG, if the source value is invalid
326 * DISP_E_OVERFLOW, if the value will not fit in the destination
328 HRESULT WINAPI
VarI1FromR4(FLOAT fltIn
, signed char* pcOut
)
330 return VarI1FromR8(fltIn
, pcOut
);
333 /************************************************************************
334 * VarI1FromR8 (OLEAUT32.248)
336 * Convert a VT_R8 to a VT_I1.
340 * pcOut [O] Destination
344 * Failure: E_INVALIDARG, if the source value is invalid
345 * DISP_E_OVERFLOW, if the value will not fit in the destination
348 * See VarI8FromR8() for details concerning rounding.
350 HRESULT WINAPI
VarI1FromR8(double dblIn
, signed char* pcOut
)
352 if (dblIn
< I1_MIN
- 0.5 || dblIn
>= I1_MAX
+ 0.5)
353 return DISP_E_OVERFLOW
;
354 VARIANT_DutchRound(CHAR
, dblIn
, *pcOut
);
358 /************************************************************************
359 * VarI1FromDate (OLEAUT32.249)
361 * Convert a VT_DATE to a VT_I1.
365 * pcOut [O] Destination
369 * Failure: E_INVALIDARG, if the source value is invalid
370 * DISP_E_OVERFLOW, if the value will not fit in the destination
372 HRESULT WINAPI
VarI1FromDate(DATE dateIn
, signed char* pcOut
)
374 return VarI1FromR8(dateIn
, pcOut
);
377 /************************************************************************
378 * VarI1FromCy (OLEAUT32.250)
380 * Convert a VT_CY to a VT_I1.
384 * pcOut [O] Destination
388 * Failure: E_INVALIDARG, if the source value is invalid
389 * DISP_E_OVERFLOW, if the value will not fit in the destination
391 HRESULT WINAPI
VarI1FromCy(CY cyIn
, signed char* pcOut
)
395 VarI4FromCy(cyIn
, &i
);
396 return _VarI1FromI4(i
, pcOut
);
399 /************************************************************************
400 * VarI1FromStr (OLEAUT32.251)
402 * Convert a VT_BSTR to a VT_I1.
406 * lcid [I] LCID for the conversion
407 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
408 * pcOut [O] Destination
412 * Failure: E_INVALIDARG, if the source value is invalid
413 * DISP_E_OVERFLOW, if the value will not fit in the destination
414 * DISP_E_TYPEMISMATCH, if the type cannot be converted
416 HRESULT WINAPI
VarI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, signed char* pcOut
)
418 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pcOut
, VT_I1
);
421 /************************************************************************
422 * VarI1FromDisp (OLEAUT32.252)
424 * Convert a VT_DISPATCH to a VT_I1.
428 * lcid [I] LCID for conversion
429 * pcOut [O] Destination
433 * Failure: E_INVALIDARG, if the source value is invalid
434 * DISP_E_OVERFLOW, if the value will not fit in the destination
435 * DISP_E_TYPEMISMATCH, if the type cannot be converted
437 HRESULT WINAPI
VarI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, signed char* pcOut
)
439 return VARIANT_FromDisp(pdispIn
, lcid
, pcOut
, VT_I1
, 0);
442 /************************************************************************
443 * VarI1FromBool (OLEAUT32.253)
445 * Convert a VT_BOOL to a VT_I1.
449 * pcOut [O] Destination
454 HRESULT WINAPI
VarI1FromBool(VARIANT_BOOL boolIn
, signed char* pcOut
)
456 return _VarI1FromBool(boolIn
, pcOut
);
459 /************************************************************************
460 * VarI1FromUI2 (OLEAUT32.254)
462 * Convert a VT_UI2 to a VT_I1.
466 * pcOut [O] Destination
470 * Failure: E_INVALIDARG, if the source value is invalid
471 * DISP_E_OVERFLOW, if the value will not fit in the destination
473 HRESULT WINAPI
VarI1FromUI2(USHORT usIn
, signed char* pcOut
)
475 return _VarI1FromUI2(usIn
, pcOut
);
478 /************************************************************************
479 * VarI1FromUI4 (OLEAUT32.255)
481 * Convert a VT_UI4 to a VT_I1.
485 * pcOut [O] Destination
489 * Failure: E_INVALIDARG, if the source value is invalid
490 * DISP_E_OVERFLOW, if the value will not fit in the destination
491 * DISP_E_TYPEMISMATCH, if the type cannot be converted
493 HRESULT WINAPI
VarI1FromUI4(ULONG ulIn
, signed char* pcOut
)
495 return _VarI1FromUI4(ulIn
, pcOut
);
498 /************************************************************************
499 * VarI1FromDec (OLEAUT32.256)
501 * Convert a VT_DECIMAL to a VT_I1.
505 * pcOut [O] Destination
509 * Failure: E_INVALIDARG, if the source value is invalid
510 * DISP_E_OVERFLOW, if the value will not fit in the destination
512 HRESULT WINAPI
VarI1FromDec(DECIMAL
*pdecIn
, signed char* pcOut
)
517 hRet
= VarI8FromDec(pdecIn
, &i64
);
520 hRet
= _VarI1FromI8(i64
, pcOut
);
524 /************************************************************************
525 * VarI1FromI8 (OLEAUT32.376)
527 * Convert a VT_I8 to a VT_I1.
531 * pcOut [O] Destination
535 * Failure: E_INVALIDARG, if the source value is invalid
536 * DISP_E_OVERFLOW, if the value will not fit in the destination
538 HRESULT WINAPI
VarI1FromI8(LONG64 llIn
, signed char* pcOut
)
540 return _VarI1FromI8(llIn
, pcOut
);
543 /************************************************************************
544 * VarI1FromUI8 (OLEAUT32.377)
546 * Convert a VT_UI8 to a VT_I1.
550 * pcOut [O] Destination
554 * Failure: E_INVALIDARG, if the source value is invalid
555 * DISP_E_OVERFLOW, if the value will not fit in the destination
557 HRESULT WINAPI
VarI1FromUI8(ULONG64 ullIn
, signed char* pcOut
)
559 return _VarI1FromUI8(ullIn
, pcOut
);
565 /************************************************************************
566 * VarUI1FromI2 (OLEAUT32.130)
568 * Convert a VT_I2 to a VT_UI1.
572 * pbOut [O] Destination
576 * Failure: E_INVALIDARG, if the source value is invalid
577 * DISP_E_OVERFLOW, if the value will not fit in the destination
579 HRESULT WINAPI
VarUI1FromI2(SHORT sIn
, BYTE
* pbOut
)
581 return _VarUI1FromI2(sIn
, pbOut
);
584 /************************************************************************
585 * VarUI1FromI4 (OLEAUT32.131)
587 * Convert a VT_I4 to a VT_UI1.
591 * pbOut [O] Destination
595 * Failure: E_INVALIDARG, if the source value is invalid
596 * DISP_E_OVERFLOW, if the value will not fit in the destination
598 HRESULT WINAPI
VarUI1FromI4(LONG iIn
, BYTE
* pbOut
)
600 return _VarUI1FromI4(iIn
, pbOut
);
603 /************************************************************************
604 * VarUI1FromR4 (OLEAUT32.132)
606 * Convert a VT_R4 to a VT_UI1.
610 * pbOut [O] Destination
614 * Failure: E_INVALIDARG, if the source value is invalid
615 * DISP_E_OVERFLOW, if the value will not fit in the destination
616 * DISP_E_TYPEMISMATCH, if the type cannot be converted
618 HRESULT WINAPI
VarUI1FromR4(FLOAT fltIn
, BYTE
* pbOut
)
620 return VarUI1FromR8(fltIn
, pbOut
);
623 /************************************************************************
624 * VarUI1FromR8 (OLEAUT32.133)
626 * Convert a VT_R8 to a VT_UI1.
630 * pbOut [O] Destination
634 * Failure: E_INVALIDARG, if the source value is invalid
635 * DISP_E_OVERFLOW, if the value will not fit in the destination
638 * See VarI8FromR8() for details concerning rounding.
640 HRESULT WINAPI
VarUI1FromR8(double dblIn
, BYTE
* pbOut
)
642 if (dblIn
< -0.5 || dblIn
>= UI1_MAX
+ 0.5)
643 return DISP_E_OVERFLOW
;
644 VARIANT_DutchRound(BYTE
, dblIn
, *pbOut
);
648 /************************************************************************
649 * VarUI1FromCy (OLEAUT32.134)
651 * Convert a VT_CY to a VT_UI1.
655 * pbOut [O] Destination
659 * Failure: E_INVALIDARG, if the source value is invalid
660 * DISP_E_OVERFLOW, if the value will not fit in the destination
663 * Negative values >= -5000 will be converted to 0.
665 HRESULT WINAPI
VarUI1FromCy(CY cyIn
, BYTE
* pbOut
)
667 ULONG i
= UI1_MAX
+ 1;
669 VarUI4FromCy(cyIn
, &i
);
670 return _VarUI1FromUI4(i
, pbOut
);
673 /************************************************************************
674 * VarUI1FromDate (OLEAUT32.135)
676 * Convert a VT_DATE to a VT_UI1.
680 * pbOut [O] Destination
684 * Failure: E_INVALIDARG, if the source value is invalid
685 * DISP_E_OVERFLOW, if the value will not fit in the destination
687 HRESULT WINAPI
VarUI1FromDate(DATE dateIn
, BYTE
* pbOut
)
689 return VarUI1FromR8(dateIn
, pbOut
);
692 /************************************************************************
693 * VarUI1FromStr (OLEAUT32.136)
695 * Convert a VT_BSTR to a VT_UI1.
699 * lcid [I] LCID for the conversion
700 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
701 * pbOut [O] Destination
705 * Failure: E_INVALIDARG, if the source value is invalid
706 * DISP_E_OVERFLOW, if the value will not fit in the destination
707 * DISP_E_TYPEMISMATCH, if the type cannot be converted
709 HRESULT WINAPI
VarUI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, BYTE
* pbOut
)
711 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pbOut
, VT_UI1
);
714 /************************************************************************
715 * VarUI1FromDisp (OLEAUT32.137)
717 * Convert a VT_DISPATCH to a VT_UI1.
721 * lcid [I] LCID for conversion
722 * pbOut [O] Destination
726 * Failure: E_INVALIDARG, if the source value is invalid
727 * DISP_E_OVERFLOW, if the value will not fit in the destination
728 * DISP_E_TYPEMISMATCH, if the type cannot be converted
730 HRESULT WINAPI
VarUI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, BYTE
* pbOut
)
732 return VARIANT_FromDisp(pdispIn
, lcid
, pbOut
, VT_UI1
, 0);
735 /************************************************************************
736 * VarUI1FromBool (OLEAUT32.138)
738 * Convert a VT_BOOL to a VT_UI1.
742 * pbOut [O] Destination
747 HRESULT WINAPI
VarUI1FromBool(VARIANT_BOOL boolIn
, BYTE
* pbOut
)
749 return _VarUI1FromBool(boolIn
, pbOut
);
752 /************************************************************************
753 * VarUI1FromI1 (OLEAUT32.237)
755 * Convert a VT_I1 to a VT_UI1.
759 * pbOut [O] Destination
763 * Failure: E_INVALIDARG, if the source value is invalid
764 * DISP_E_OVERFLOW, if the value will not fit in the destination
766 HRESULT WINAPI
VarUI1FromI1(signed char cIn
, BYTE
* pbOut
)
768 return _VarUI1FromI1(cIn
, pbOut
);
771 /************************************************************************
772 * VarUI1FromUI2 (OLEAUT32.238)
774 * Convert a VT_UI2 to a VT_UI1.
778 * pbOut [O] Destination
782 * Failure: E_INVALIDARG, if the source value is invalid
783 * DISP_E_OVERFLOW, if the value will not fit in the destination
785 HRESULT WINAPI
VarUI1FromUI2(USHORT usIn
, BYTE
* pbOut
)
787 return _VarUI1FromUI2(usIn
, pbOut
);
790 /************************************************************************
791 * VarUI1FromUI4 (OLEAUT32.239)
793 * Convert a VT_UI4 to a VT_UI1.
797 * pbOut [O] Destination
801 * Failure: E_INVALIDARG, if the source value is invalid
802 * DISP_E_OVERFLOW, if the value will not fit in the destination
804 HRESULT WINAPI
VarUI1FromUI4(ULONG ulIn
, BYTE
* pbOut
)
806 return _VarUI1FromUI4(ulIn
, pbOut
);
809 /************************************************************************
810 * VarUI1FromDec (OLEAUT32.240)
812 * Convert a VT_DECIMAL to a VT_UI1.
816 * pbOut [O] Destination
820 * Failure: E_INVALIDARG, if the source value is invalid
821 * DISP_E_OVERFLOW, if the value will not fit in the destination
823 HRESULT WINAPI
VarUI1FromDec(DECIMAL
*pdecIn
, BYTE
* pbOut
)
828 hRet
= VarI8FromDec(pdecIn
, &i64
);
831 hRet
= _VarUI1FromI8(i64
, pbOut
);
835 /************************************************************************
836 * VarUI1FromI8 (OLEAUT32.372)
838 * Convert a VT_I8 to a VT_UI1.
842 * pbOut [O] Destination
846 * Failure: E_INVALIDARG, if the source value is invalid
847 * DISP_E_OVERFLOW, if the value will not fit in the destination
849 HRESULT WINAPI
VarUI1FromI8(LONG64 llIn
, BYTE
* pbOut
)
851 return _VarUI1FromI8(llIn
, pbOut
);
854 /************************************************************************
855 * VarUI1FromUI8 (OLEAUT32.373)
857 * Convert a VT_UI8 to a VT_UI1.
861 * pbOut [O] Destination
865 * Failure: E_INVALIDARG, if the source value is invalid
866 * DISP_E_OVERFLOW, if the value will not fit in the destination
868 HRESULT WINAPI
VarUI1FromUI8(ULONG64 ullIn
, BYTE
* pbOut
)
870 return _VarUI1FromUI8(ullIn
, pbOut
);
877 /************************************************************************
878 * VarI2FromUI1 (OLEAUT32.48)
880 * Convert a VT_UI2 to a VT_I2.
884 * psOut [O] Destination
889 HRESULT WINAPI
VarI2FromUI1(BYTE bIn
, SHORT
* psOut
)
891 return _VarI2FromUI1(bIn
, psOut
);
894 /************************************************************************
895 * VarI2FromI4 (OLEAUT32.49)
897 * Convert a VT_I4 to a VT_I2.
901 * psOut [O] Destination
905 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
907 HRESULT WINAPI
VarI2FromI4(LONG iIn
, SHORT
* psOut
)
909 return _VarI2FromI4(iIn
, psOut
);
912 /************************************************************************
913 * VarI2FromR4 (OLEAUT32.50)
915 * Convert a VT_R4 to a VT_I2.
919 * psOut [O] Destination
923 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
925 HRESULT WINAPI
VarI2FromR4(FLOAT fltIn
, SHORT
* psOut
)
927 return VarI2FromR8(fltIn
, psOut
);
930 /************************************************************************
931 * VarI2FromR8 (OLEAUT32.51)
933 * Convert a VT_R8 to a VT_I2.
937 * psOut [O] Destination
941 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
944 * See VarI8FromR8() for details concerning rounding.
946 HRESULT WINAPI
VarI2FromR8(double dblIn
, SHORT
* psOut
)
948 if (dblIn
< I2_MIN
- 0.5 || dblIn
>= I2_MAX
+ 0.5)
949 return DISP_E_OVERFLOW
;
950 VARIANT_DutchRound(SHORT
, dblIn
, *psOut
);
954 /************************************************************************
955 * VarI2FromCy (OLEAUT32.52)
957 * Convert a VT_CY to a VT_I2.
961 * psOut [O] Destination
965 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
967 HRESULT WINAPI
VarI2FromCy(CY cyIn
, SHORT
* psOut
)
971 VarI4FromCy(cyIn
, &i
);
972 return _VarI2FromI4(i
, psOut
);
975 /************************************************************************
976 * VarI2FromDate (OLEAUT32.53)
978 * Convert a VT_DATE to a VT_I2.
982 * psOut [O] Destination
986 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
988 HRESULT WINAPI
VarI2FromDate(DATE dateIn
, SHORT
* psOut
)
990 return VarI2FromR8(dateIn
, psOut
);
993 /************************************************************************
994 * VarI2FromStr (OLEAUT32.54)
996 * Convert a VT_BSTR to a VT_I2.
1000 * lcid [I] LCID for the conversion
1001 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1002 * psOut [O] Destination
1006 * Failure: E_INVALIDARG, if any parameter is invalid
1007 * DISP_E_OVERFLOW, if the value will not fit in the destination
1008 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1010 HRESULT WINAPI
VarI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, SHORT
* psOut
)
1012 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, psOut
, VT_I2
);
1015 /************************************************************************
1016 * VarI2FromDisp (OLEAUT32.55)
1018 * Convert a VT_DISPATCH to a VT_I2.
1021 * pdispIn [I] Source
1022 * lcid [I] LCID for conversion
1023 * psOut [O] Destination
1027 * Failure: E_INVALIDARG, if pdispIn is invalid,
1028 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1029 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1031 HRESULT WINAPI
VarI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, SHORT
* psOut
)
1033 return VARIANT_FromDisp(pdispIn
, lcid
, psOut
, VT_I2
, 0);
1036 /************************************************************************
1037 * VarI2FromBool (OLEAUT32.56)
1039 * Convert a VT_BOOL to a VT_I2.
1043 * psOut [O] Destination
1048 HRESULT WINAPI
VarI2FromBool(VARIANT_BOOL boolIn
, SHORT
* psOut
)
1050 return _VarI2FromBool(boolIn
, psOut
);
1053 /************************************************************************
1054 * VarI2FromI1 (OLEAUT32.205)
1056 * Convert a VT_I1 to a VT_I2.
1060 * psOut [O] Destination
1065 HRESULT WINAPI
VarI2FromI1(signed char cIn
, SHORT
* psOut
)
1067 return _VarI2FromI1(cIn
, psOut
);
1070 /************************************************************************
1071 * VarI2FromUI2 (OLEAUT32.206)
1073 * Convert a VT_UI2 to a VT_I2.
1077 * psOut [O] Destination
1081 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1083 HRESULT WINAPI
VarI2FromUI2(USHORT usIn
, SHORT
* psOut
)
1085 return _VarI2FromUI2(usIn
, psOut
);
1088 /************************************************************************
1089 * VarI2FromUI4 (OLEAUT32.207)
1091 * Convert a VT_UI4 to a VT_I2.
1095 * psOut [O] Destination
1099 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1101 HRESULT WINAPI
VarI2FromUI4(ULONG ulIn
, SHORT
* psOut
)
1103 return _VarI2FromUI4(ulIn
, psOut
);
1106 /************************************************************************
1107 * VarI2FromDec (OLEAUT32.208)
1109 * Convert a VT_DECIMAL to a VT_I2.
1113 * psOut [O] Destination
1117 * Failure: E_INVALIDARG, if the source value is invalid
1118 * DISP_E_OVERFLOW, if the value will not fit in the destination
1120 HRESULT WINAPI
VarI2FromDec(DECIMAL
*pdecIn
, SHORT
* psOut
)
1125 hRet
= VarI8FromDec(pdecIn
, &i64
);
1127 if (SUCCEEDED(hRet
))
1128 hRet
= _VarI2FromI8(i64
, psOut
);
1132 /************************************************************************
1133 * VarI2FromI8 (OLEAUT32.346)
1135 * Convert a VT_I8 to a VT_I2.
1139 * psOut [O] Destination
1143 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1145 HRESULT WINAPI
VarI2FromI8(LONG64 llIn
, SHORT
* psOut
)
1147 return _VarI2FromI8(llIn
, psOut
);
1150 /************************************************************************
1151 * VarI2FromUI8 (OLEAUT32.347)
1153 * Convert a VT_UI8 to a VT_I2.
1157 * psOut [O] Destination
1161 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1163 HRESULT WINAPI
VarI2FromUI8(ULONG64 ullIn
, SHORT
* psOut
)
1165 return _VarI2FromUI8(ullIn
, psOut
);
1171 /************************************************************************
1172 * VarUI2FromUI1 (OLEAUT32.257)
1174 * Convert a VT_UI1 to a VT_UI2.
1178 * pusOut [O] Destination
1183 HRESULT WINAPI
VarUI2FromUI1(BYTE bIn
, USHORT
* pusOut
)
1185 return _VarUI2FromUI1(bIn
, pusOut
);
1188 /************************************************************************
1189 * VarUI2FromI2 (OLEAUT32.258)
1191 * Convert a VT_I2 to a VT_UI2.
1195 * pusOut [O] Destination
1199 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1201 HRESULT WINAPI
VarUI2FromI2(SHORT sIn
, USHORT
* pusOut
)
1203 return _VarUI2FromI2(sIn
, pusOut
);
1206 /************************************************************************
1207 * VarUI2FromI4 (OLEAUT32.259)
1209 * Convert a VT_I4 to a VT_UI2.
1213 * pusOut [O] Destination
1217 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1219 HRESULT WINAPI
VarUI2FromI4(LONG iIn
, USHORT
* pusOut
)
1221 return _VarUI2FromI4(iIn
, pusOut
);
1224 /************************************************************************
1225 * VarUI2FromR4 (OLEAUT32.260)
1227 * Convert a VT_R4 to a VT_UI2.
1231 * pusOut [O] Destination
1235 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1237 HRESULT WINAPI
VarUI2FromR4(FLOAT fltIn
, USHORT
* pusOut
)
1239 return VarUI2FromR8(fltIn
, pusOut
);
1242 /************************************************************************
1243 * VarUI2FromR8 (OLEAUT32.261)
1245 * Convert a VT_R8 to a VT_UI2.
1249 * pusOut [O] Destination
1253 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1256 * See VarI8FromR8() for details concerning rounding.
1258 HRESULT WINAPI
VarUI2FromR8(double dblIn
, USHORT
* pusOut
)
1260 if (dblIn
< -0.5 || dblIn
>= UI2_MAX
+ 0.5)
1261 return DISP_E_OVERFLOW
;
1262 VARIANT_DutchRound(USHORT
, dblIn
, *pusOut
);
1266 /************************************************************************
1267 * VarUI2FromDate (OLEAUT32.262)
1269 * Convert a VT_DATE to a VT_UI2.
1273 * pusOut [O] Destination
1277 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1279 HRESULT WINAPI
VarUI2FromDate(DATE dateIn
, USHORT
* pusOut
)
1281 return VarUI2FromR8(dateIn
, pusOut
);
1284 /************************************************************************
1285 * VarUI2FromCy (OLEAUT32.263)
1287 * Convert a VT_CY to a VT_UI2.
1291 * pusOut [O] Destination
1295 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1298 * Negative values >= -5000 will be converted to 0.
1300 HRESULT WINAPI
VarUI2FromCy(CY cyIn
, USHORT
* pusOut
)
1302 ULONG i
= UI2_MAX
+ 1;
1304 VarUI4FromCy(cyIn
, &i
);
1305 return _VarUI2FromUI4(i
, pusOut
);
1308 /************************************************************************
1309 * VarUI2FromStr (OLEAUT32.264)
1311 * Convert a VT_BSTR to a VT_UI2.
1315 * lcid [I] LCID for the conversion
1316 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1317 * pusOut [O] Destination
1321 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1322 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1324 HRESULT WINAPI
VarUI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, USHORT
* pusOut
)
1326 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pusOut
, VT_UI2
);
1329 /************************************************************************
1330 * VarUI2FromDisp (OLEAUT32.265)
1332 * Convert a VT_DISPATCH to a VT_UI2.
1335 * pdispIn [I] Source
1336 * lcid [I] LCID for conversion
1337 * pusOut [O] Destination
1341 * Failure: E_INVALIDARG, if the source value is invalid
1342 * DISP_E_OVERFLOW, if the value will not fit in the destination
1343 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1345 HRESULT WINAPI
VarUI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, USHORT
* pusOut
)
1347 return VARIANT_FromDisp(pdispIn
, lcid
, pusOut
, VT_UI2
, 0);
1350 /************************************************************************
1351 * VarUI2FromBool (OLEAUT32.266)
1353 * Convert a VT_BOOL to a VT_UI2.
1357 * pusOut [O] Destination
1362 HRESULT WINAPI
VarUI2FromBool(VARIANT_BOOL boolIn
, USHORT
* pusOut
)
1364 return _VarUI2FromBool(boolIn
, pusOut
);
1367 /************************************************************************
1368 * VarUI2FromI1 (OLEAUT32.267)
1370 * Convert a VT_I1 to a VT_UI2.
1374 * pusOut [O] Destination
1378 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1380 HRESULT WINAPI
VarUI2FromI1(signed char cIn
, USHORT
* pusOut
)
1382 return _VarUI2FromI1(cIn
, pusOut
);
1385 /************************************************************************
1386 * VarUI2FromUI4 (OLEAUT32.268)
1388 * Convert a VT_UI4 to a VT_UI2.
1392 * pusOut [O] Destination
1396 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1398 HRESULT WINAPI
VarUI2FromUI4(ULONG ulIn
, USHORT
* pusOut
)
1400 return _VarUI2FromUI4(ulIn
, pusOut
);
1403 /************************************************************************
1404 * VarUI2FromDec (OLEAUT32.269)
1406 * Convert a VT_DECIMAL to a VT_UI2.
1410 * pusOut [O] Destination
1414 * Failure: E_INVALIDARG, if the source value is invalid
1415 * DISP_E_OVERFLOW, if the value will not fit in the destination
1417 HRESULT WINAPI
VarUI2FromDec(DECIMAL
*pdecIn
, USHORT
* pusOut
)
1422 hRet
= VarI8FromDec(pdecIn
, &i64
);
1424 if (SUCCEEDED(hRet
))
1425 hRet
= _VarUI2FromI8(i64
, pusOut
);
1429 /************************************************************************
1430 * VarUI2FromI8 (OLEAUT32.378)
1432 * Convert a VT_I8 to a VT_UI2.
1436 * pusOut [O] Destination
1440 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1442 HRESULT WINAPI
VarUI2FromI8(LONG64 llIn
, USHORT
* pusOut
)
1444 return _VarUI2FromI8(llIn
, pusOut
);
1447 /************************************************************************
1448 * VarUI2FromUI8 (OLEAUT32.379)
1450 * Convert a VT_UI8 to a VT_UI2.
1454 * pusOut [O] Destination
1458 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1460 HRESULT WINAPI
VarUI2FromUI8(ULONG64 ullIn
, USHORT
* pusOut
)
1462 return _VarUI2FromUI8(ullIn
, pusOut
);
1468 /************************************************************************
1469 * VarI4FromUI1 (OLEAUT32.58)
1471 * Convert a VT_UI1 to a VT_I4.
1475 * piOut [O] Destination
1480 HRESULT WINAPI
VarI4FromUI1(BYTE bIn
, LONG
*piOut
)
1482 return _VarI4FromUI1(bIn
, piOut
);
1485 /************************************************************************
1486 * VarI4FromI2 (OLEAUT32.59)
1488 * Convert a VT_I2 to a VT_I4.
1492 * piOut [O] Destination
1496 * Failure: E_INVALIDARG, if the source value is invalid
1497 * DISP_E_OVERFLOW, if the value will not fit in the destination
1499 HRESULT WINAPI
VarI4FromI2(SHORT sIn
, LONG
*piOut
)
1501 return _VarI4FromI2(sIn
, piOut
);
1504 /************************************************************************
1505 * VarI4FromR4 (OLEAUT32.60)
1507 * Convert a VT_R4 to a VT_I4.
1511 * piOut [O] Destination
1515 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1517 HRESULT WINAPI
VarI4FromR4(FLOAT fltIn
, LONG
*piOut
)
1519 return VarI4FromR8(fltIn
, piOut
);
1522 /************************************************************************
1523 * VarI4FromR8 (OLEAUT32.61)
1525 * Convert a VT_R8 to a VT_I4.
1529 * piOut [O] Destination
1533 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1536 * See VarI8FromR8() for details concerning rounding.
1538 HRESULT WINAPI
VarI4FromR8(double dblIn
, LONG
*piOut
)
1540 if (dblIn
< I4_MIN
- 0.5 || dblIn
>= I4_MAX
+ 0.5)
1541 return DISP_E_OVERFLOW
;
1542 VARIANT_DutchRound(LONG
, dblIn
, *piOut
);
1546 /************************************************************************
1547 * VarI4FromCy (OLEAUT32.62)
1549 * Convert a VT_CY to a VT_I4.
1553 * piOut [O] Destination
1557 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1559 HRESULT WINAPI
VarI4FromCy(CY cyIn
, LONG
*piOut
)
1561 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1562 return VarI4FromR8(d
, piOut
);
1565 /************************************************************************
1566 * VarI4FromDate (OLEAUT32.63)
1568 * Convert a VT_DATE to a VT_I4.
1572 * piOut [O] Destination
1576 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1578 HRESULT WINAPI
VarI4FromDate(DATE dateIn
, LONG
*piOut
)
1580 return VarI4FromR8(dateIn
, piOut
);
1583 /************************************************************************
1584 * VarI4FromStr (OLEAUT32.64)
1586 * Convert a VT_BSTR to a VT_I4.
1590 * lcid [I] LCID for the conversion
1591 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1592 * piOut [O] Destination
1596 * Failure: E_INVALIDARG, if any parameter is invalid
1597 * DISP_E_OVERFLOW, if the value will not fit in the destination
1598 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1600 HRESULT WINAPI
VarI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG
*piOut
)
1602 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, piOut
, VT_I4
);
1605 /************************************************************************
1606 * VarI4FromDisp (OLEAUT32.65)
1608 * Convert a VT_DISPATCH to a VT_I4.
1611 * pdispIn [I] Source
1612 * lcid [I] LCID for conversion
1613 * piOut [O] Destination
1617 * Failure: E_INVALIDARG, if the source value is invalid
1618 * DISP_E_OVERFLOW, if the value will not fit in the destination
1619 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1621 HRESULT WINAPI
VarI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG
*piOut
)
1623 return VARIANT_FromDisp(pdispIn
, lcid
, piOut
, VT_I4
, 0);
1626 /************************************************************************
1627 * VarI4FromBool (OLEAUT32.66)
1629 * Convert a VT_BOOL to a VT_I4.
1633 * piOut [O] Destination
1638 HRESULT WINAPI
VarI4FromBool(VARIANT_BOOL boolIn
, LONG
*piOut
)
1640 return _VarI4FromBool(boolIn
, piOut
);
1643 /************************************************************************
1644 * VarI4FromI1 (OLEAUT32.209)
1646 * Convert a VT_I1 to a VT_I4.
1650 * piOut [O] Destination
1655 HRESULT WINAPI
VarI4FromI1(signed char cIn
, LONG
*piOut
)
1657 return _VarI4FromI1(cIn
, piOut
);
1660 /************************************************************************
1661 * VarI4FromUI2 (OLEAUT32.210)
1663 * Convert a VT_UI2 to a VT_I4.
1667 * piOut [O] Destination
1672 HRESULT WINAPI
VarI4FromUI2(USHORT usIn
, LONG
*piOut
)
1674 return _VarI4FromUI2(usIn
, piOut
);
1677 /************************************************************************
1678 * VarI4FromUI4 (OLEAUT32.211)
1680 * Convert a VT_UI4 to a VT_I4.
1684 * piOut [O] Destination
1688 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1690 HRESULT WINAPI
VarI4FromUI4(ULONG ulIn
, LONG
*piOut
)
1692 return _VarI4FromUI4(ulIn
, piOut
);
1695 /************************************************************************
1696 * VarI4FromDec (OLEAUT32.212)
1698 * Convert a VT_DECIMAL to a VT_I4.
1702 * piOut [O] Destination
1706 * Failure: E_INVALIDARG, if pdecIn is invalid
1707 * DISP_E_OVERFLOW, if the value will not fit in the destination
1709 HRESULT WINAPI
VarI4FromDec(DECIMAL
*pdecIn
, LONG
*piOut
)
1714 hRet
= VarI8FromDec(pdecIn
, &i64
);
1716 if (SUCCEEDED(hRet
))
1717 hRet
= _VarI4FromI8(i64
, piOut
);
1721 /************************************************************************
1722 * VarI4FromI8 (OLEAUT32.348)
1724 * Convert a VT_I8 to a VT_I4.
1728 * piOut [O] Destination
1732 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1734 HRESULT WINAPI
VarI4FromI8(LONG64 llIn
, LONG
*piOut
)
1736 return _VarI4FromI8(llIn
, piOut
);
1739 /************************************************************************
1740 * VarI4FromUI8 (OLEAUT32.349)
1742 * Convert a VT_UI8 to a VT_I4.
1746 * piOut [O] Destination
1750 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1752 HRESULT WINAPI
VarI4FromUI8(ULONG64 ullIn
, LONG
*piOut
)
1754 return _VarI4FromUI8(ullIn
, piOut
);
1760 /************************************************************************
1761 * VarUI4FromUI1 (OLEAUT32.270)
1763 * Convert a VT_UI1 to a VT_UI4.
1767 * pulOut [O] Destination
1772 HRESULT WINAPI
VarUI4FromUI1(BYTE bIn
, ULONG
*pulOut
)
1774 return _VarUI4FromUI1(bIn
, pulOut
);
1777 /************************************************************************
1778 * VarUI4FromI2 (OLEAUT32.271)
1780 * Convert a VT_I2 to a VT_UI4.
1784 * pulOut [O] Destination
1788 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1790 HRESULT WINAPI
VarUI4FromI2(SHORT sIn
, ULONG
*pulOut
)
1792 return _VarUI4FromI2(sIn
, pulOut
);
1795 /************************************************************************
1796 * VarUI4FromI4 (OLEAUT32.272)
1798 * Convert a VT_I4 to a VT_UI4.
1802 * pulOut [O] Destination
1806 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1808 HRESULT WINAPI
VarUI4FromI4(LONG iIn
, ULONG
*pulOut
)
1810 return _VarUI4FromI4(iIn
, pulOut
);
1813 /************************************************************************
1814 * VarUI4FromR4 (OLEAUT32.273)
1816 * Convert a VT_R4 to a VT_UI4.
1820 * pulOut [O] Destination
1824 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1826 HRESULT WINAPI
VarUI4FromR4(FLOAT fltIn
, ULONG
*pulOut
)
1828 return VarUI4FromR8(fltIn
, pulOut
);
1831 /************************************************************************
1832 * VarUI4FromR8 (OLEAUT32.274)
1834 * Convert a VT_R8 to a VT_UI4.
1838 * pulOut [O] Destination
1842 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1845 * See VarI8FromR8() for details concerning rounding.
1847 HRESULT WINAPI
VarUI4FromR8(double dblIn
, ULONG
*pulOut
)
1849 if (dblIn
< -0.5 || dblIn
>= UI4_MAX
+ 0.5)
1850 return DISP_E_OVERFLOW
;
1851 VARIANT_DutchRound(ULONG
, dblIn
, *pulOut
);
1855 /************************************************************************
1856 * VarUI4FromDate (OLEAUT32.275)
1858 * Convert a VT_DATE to a VT_UI4.
1862 * pulOut [O] Destination
1866 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1868 HRESULT WINAPI
VarUI4FromDate(DATE dateIn
, ULONG
*pulOut
)
1870 return VarUI4FromR8(dateIn
, pulOut
);
1873 /************************************************************************
1874 * VarUI4FromCy (OLEAUT32.276)
1876 * Convert a VT_CY to a VT_UI4.
1880 * pulOut [O] Destination
1884 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1886 HRESULT WINAPI
VarUI4FromCy(CY cyIn
, ULONG
*pulOut
)
1888 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1889 return VarUI4FromR8(d
, pulOut
);
1892 /************************************************************************
1893 * VarUI4FromStr (OLEAUT32.277)
1895 * Convert a VT_BSTR to a VT_UI4.
1899 * lcid [I] LCID for the conversion
1900 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1901 * pulOut [O] Destination
1905 * Failure: E_INVALIDARG, if any parameter is invalid
1906 * DISP_E_OVERFLOW, if the value will not fit in the destination
1907 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1909 HRESULT WINAPI
VarUI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG
*pulOut
)
1911 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pulOut
, VT_UI4
);
1914 /************************************************************************
1915 * VarUI4FromDisp (OLEAUT32.278)
1917 * Convert a VT_DISPATCH to a VT_UI4.
1920 * pdispIn [I] Source
1921 * lcid [I] LCID for conversion
1922 * pulOut [O] Destination
1926 * Failure: E_INVALIDARG, if the source value is invalid
1927 * DISP_E_OVERFLOW, if the value will not fit in the destination
1928 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1930 HRESULT WINAPI
VarUI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG
*pulOut
)
1932 return VARIANT_FromDisp(pdispIn
, lcid
, pulOut
, VT_UI4
, 0);
1935 /************************************************************************
1936 * VarUI4FromBool (OLEAUT32.279)
1938 * Convert a VT_BOOL to a VT_UI4.
1942 * pulOut [O] Destination
1947 HRESULT WINAPI
VarUI4FromBool(VARIANT_BOOL boolIn
, ULONG
*pulOut
)
1949 return _VarUI4FromBool(boolIn
, pulOut
);
1952 /************************************************************************
1953 * VarUI4FromI1 (OLEAUT32.280)
1955 * Convert a VT_I1 to a VT_UI4.
1959 * pulOut [O] Destination
1963 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1965 HRESULT WINAPI
VarUI4FromI1(signed char cIn
, ULONG
*pulOut
)
1967 return _VarUI4FromI1(cIn
, pulOut
);
1970 /************************************************************************
1971 * VarUI4FromUI2 (OLEAUT32.281)
1973 * Convert a VT_UI2 to a VT_UI4.
1977 * pulOut [O] Destination
1982 HRESULT WINAPI
VarUI4FromUI2(USHORT usIn
, ULONG
*pulOut
)
1984 return _VarUI4FromUI2(usIn
, pulOut
);
1987 /************************************************************************
1988 * VarUI4FromDec (OLEAUT32.282)
1990 * Convert a VT_DECIMAL to a VT_UI4.
1994 * pulOut [O] Destination
1998 * Failure: E_INVALIDARG, if pdecIn is invalid
1999 * DISP_E_OVERFLOW, if the value will not fit in the destination
2001 HRESULT WINAPI
VarUI4FromDec(DECIMAL
*pdecIn
, ULONG
*pulOut
)
2006 hRet
= VarI8FromDec(pdecIn
, &i64
);
2008 if (SUCCEEDED(hRet
))
2009 hRet
= _VarUI4FromI8(i64
, pulOut
);
2013 /************************************************************************
2014 * VarUI4FromI8 (OLEAUT32.425)
2016 * Convert a VT_I8 to a VT_UI4.
2020 * pulOut [O] Destination
2024 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2026 HRESULT WINAPI
VarUI4FromI8(LONG64 llIn
, ULONG
*pulOut
)
2028 return _VarUI4FromI8(llIn
, pulOut
);
2031 /************************************************************************
2032 * VarUI4FromUI8 (OLEAUT32.426)
2034 * Convert a VT_UI8 to a VT_UI4.
2038 * pulOut [O] Destination
2042 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2044 HRESULT WINAPI
VarUI4FromUI8(ULONG64 ullIn
, ULONG
*pulOut
)
2046 return _VarUI4FromUI8(ullIn
, pulOut
);
2052 /************************************************************************
2053 * VarI8FromUI1 (OLEAUT32.333)
2055 * Convert a VT_UI1 to a VT_I8.
2059 * pi64Out [O] Destination
2064 HRESULT WINAPI
VarI8FromUI1(BYTE bIn
, LONG64
* pi64Out
)
2066 return _VarI8FromUI1(bIn
, pi64Out
);
2070 /************************************************************************
2071 * VarI8FromI2 (OLEAUT32.334)
2073 * Convert a VT_I2 to a VT_I8.
2077 * pi64Out [O] Destination
2082 HRESULT WINAPI
VarI8FromI2(SHORT sIn
, LONG64
* pi64Out
)
2084 return _VarI8FromI2(sIn
, pi64Out
);
2087 /************************************************************************
2088 * VarI8FromR4 (OLEAUT32.335)
2090 * Convert a VT_R4 to a VT_I8.
2094 * pi64Out [O] Destination
2098 * Failure: E_INVALIDARG, if the source value is invalid
2099 * DISP_E_OVERFLOW, if the value will not fit in the destination
2101 HRESULT WINAPI
VarI8FromR4(FLOAT fltIn
, LONG64
* pi64Out
)
2103 return VarI8FromR8(fltIn
, pi64Out
);
2106 /************************************************************************
2107 * VarI8FromR8 (OLEAUT32.336)
2109 * Convert a VT_R8 to a VT_I8.
2113 * pi64Out [O] Destination
2117 * Failure: E_INVALIDARG, if the source value is invalid
2118 * DISP_E_OVERFLOW, if the value will not fit in the destination
2121 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2122 * very high or low values will not be accurately converted.
2124 * Numbers are rounded using Dutch rounding, as follows:
2126 *| Fractional Part Sign Direction Example
2127 *| --------------- ---- --------- -------
2128 *| < 0.5 + Down 0.4 -> 0.0
2129 *| < 0.5 - Up -0.4 -> 0.0
2130 *| > 0.5 + Up 0.6 -> 1.0
2131 *| < 0.5 - Up -0.6 -> -1.0
2132 *| = 0.5 + Up/Down Down if even, Up if odd
2133 *| = 0.5 - Up/Down Up if even, Down if odd
2135 * This system is often used in supermarkets.
2137 HRESULT WINAPI
VarI8FromR8(double dblIn
, LONG64
* pi64Out
)
2139 if ( dblIn
< -4611686018427387904.0 || dblIn
>= 4611686018427387904.0)
2140 return DISP_E_OVERFLOW
;
2141 VARIANT_DutchRound(LONG64
, dblIn
, *pi64Out
);
2145 /************************************************************************
2146 * VarI8FromCy (OLEAUT32.337)
2148 * Convert a VT_CY to a VT_I8.
2152 * pi64Out [O] Destination
2158 * All negative numbers are rounded down by 1, including those that are
2159 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2160 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2163 HRESULT WINAPI
VarI8FromCy(CY cyIn
, LONG64
* pi64Out
)
2165 *pi64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2168 (*pi64Out
)--; /* Mimic Win32 bug */
2171 cyIn
.int64
-= *pi64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2173 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pi64Out
& 0x1)))
2179 /************************************************************************
2180 * VarI8FromDate (OLEAUT32.338)
2182 * Convert a VT_DATE to a VT_I8.
2186 * pi64Out [O] Destination
2190 * Failure: E_INVALIDARG, if the source value is invalid
2191 * DISP_E_OVERFLOW, if the value will not fit in the destination
2192 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2194 HRESULT WINAPI
VarI8FromDate(DATE dateIn
, LONG64
* pi64Out
)
2196 return VarI8FromR8(dateIn
, pi64Out
);
2199 /************************************************************************
2200 * VarI8FromStr (OLEAUT32.339)
2202 * Convert a VT_BSTR to a VT_I8.
2206 * lcid [I] LCID for the conversion
2207 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2208 * pi64Out [O] Destination
2212 * Failure: E_INVALIDARG, if the source value is invalid
2213 * DISP_E_OVERFLOW, if the value will not fit in the destination
2214 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2216 HRESULT WINAPI
VarI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG64
* pi64Out
)
2218 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pi64Out
, VT_I8
);
2221 /************************************************************************
2222 * VarI8FromDisp (OLEAUT32.340)
2224 * Convert a VT_DISPATCH to a VT_I8.
2227 * pdispIn [I] Source
2228 * lcid [I] LCID for conversion
2229 * pi64Out [O] Destination
2233 * Failure: E_INVALIDARG, if the source value is invalid
2234 * DISP_E_OVERFLOW, if the value will not fit in the destination
2235 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2237 HRESULT WINAPI
VarI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG64
* pi64Out
)
2239 return VARIANT_FromDisp(pdispIn
, lcid
, pi64Out
, VT_I8
, 0);
2242 /************************************************************************
2243 * VarI8FromBool (OLEAUT32.341)
2245 * Convert a VT_BOOL to a VT_I8.
2249 * pi64Out [O] Destination
2254 HRESULT WINAPI
VarI8FromBool(VARIANT_BOOL boolIn
, LONG64
* pi64Out
)
2256 return VarI8FromI2(boolIn
, pi64Out
);
2259 /************************************************************************
2260 * VarI8FromI1 (OLEAUT32.342)
2262 * Convert a VT_I1 to a VT_I8.
2266 * pi64Out [O] Destination
2271 HRESULT WINAPI
VarI8FromI1(signed char cIn
, LONG64
* pi64Out
)
2273 return _VarI8FromI1(cIn
, pi64Out
);
2276 /************************************************************************
2277 * VarI8FromUI2 (OLEAUT32.343)
2279 * Convert a VT_UI2 to a VT_I8.
2283 * pi64Out [O] Destination
2288 HRESULT WINAPI
VarI8FromUI2(USHORT usIn
, LONG64
* pi64Out
)
2290 return _VarI8FromUI2(usIn
, pi64Out
);
2293 /************************************************************************
2294 * VarI8FromUI4 (OLEAUT32.344)
2296 * Convert a VT_UI4 to a VT_I8.
2300 * pi64Out [O] Destination
2305 HRESULT WINAPI
VarI8FromUI4(ULONG ulIn
, LONG64
* pi64Out
)
2307 return _VarI8FromUI4(ulIn
, pi64Out
);
2310 /************************************************************************
2311 * VarI8FromDec (OLEAUT32.345)
2313 * Convert a VT_DECIMAL to a VT_I8.
2317 * pi64Out [O] Destination
2321 * Failure: E_INVALIDARG, if the source value is invalid
2322 * DISP_E_OVERFLOW, if the value will not fit in the destination
2324 HRESULT WINAPI
VarI8FromDec(DECIMAL
*pdecIn
, LONG64
* pi64Out
)
2326 if (!DEC_SCALE(pdecIn
))
2328 /* This decimal is just a 96 bit integer */
2329 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2330 return E_INVALIDARG
;
2332 if (DEC_HI32(pdecIn
) || DEC_MID32(pdecIn
) & 0x80000000)
2333 return DISP_E_OVERFLOW
;
2335 if (DEC_SIGN(pdecIn
))
2336 *pi64Out
= -DEC_LO64(pdecIn
);
2338 *pi64Out
= DEC_LO64(pdecIn
);
2343 /* Decimal contains a floating point number */
2347 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2348 if (SUCCEEDED(hRet
))
2349 hRet
= VarI8FromR8(dbl
, pi64Out
);
2354 /************************************************************************
2355 * VarI8FromUI8 (OLEAUT32.427)
2357 * Convert a VT_UI8 to a VT_I8.
2361 * pi64Out [O] Destination
2365 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2367 HRESULT WINAPI
VarI8FromUI8(ULONG64 ullIn
, LONG64
* pi64Out
)
2369 return _VarI8FromUI8(ullIn
, pi64Out
);
2375 /************************************************************************
2376 * VarUI8FromI8 (OLEAUT32.428)
2378 * Convert a VT_I8 to a VT_UI8.
2382 * pui64Out [O] Destination
2386 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2388 HRESULT WINAPI
VarUI8FromI8(LONG64 llIn
, ULONG64
* pui64Out
)
2390 return _VarUI8FromI8(llIn
, pui64Out
);
2393 /************************************************************************
2394 * VarUI8FromUI1 (OLEAUT32.429)
2396 * Convert a VT_UI1 to a VT_UI8.
2400 * pui64Out [O] Destination
2405 HRESULT WINAPI
VarUI8FromUI1(BYTE bIn
, ULONG64
* pui64Out
)
2407 return _VarUI8FromUI1(bIn
, pui64Out
);
2410 /************************************************************************
2411 * VarUI8FromI2 (OLEAUT32.430)
2413 * Convert a VT_I2 to a VT_UI8.
2417 * pui64Out [O] Destination
2422 HRESULT WINAPI
VarUI8FromI2(SHORT sIn
, ULONG64
* pui64Out
)
2424 return _VarUI8FromI2(sIn
, pui64Out
);
2427 /************************************************************************
2428 * VarUI8FromR4 (OLEAUT32.431)
2430 * Convert a VT_R4 to a VT_UI8.
2434 * pui64Out [O] Destination
2438 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2440 HRESULT WINAPI
VarUI8FromR4(FLOAT fltIn
, ULONG64
* pui64Out
)
2442 return VarUI8FromR8(fltIn
, pui64Out
);
2445 /************************************************************************
2446 * VarUI8FromR8 (OLEAUT32.432)
2448 * Convert a VT_R8 to a VT_UI8.
2452 * pui64Out [O] Destination
2456 * Failure: E_INVALIDARG, if the source value is invalid
2457 * DISP_E_OVERFLOW, if the value will not fit in the destination
2460 * See VarI8FromR8() for details concerning rounding.
2462 HRESULT WINAPI
VarUI8FromR8(double dblIn
, ULONG64
* pui64Out
)
2464 if (dblIn
< -0.5 || dblIn
> 1.844674407370955e19
)
2465 return DISP_E_OVERFLOW
;
2466 VARIANT_DutchRound(ULONG64
, dblIn
, *pui64Out
);
2470 /************************************************************************
2471 * VarUI8FromCy (OLEAUT32.433)
2473 * Convert a VT_CY to a VT_UI8.
2477 * pui64Out [O] Destination
2481 * Failure: E_INVALIDARG, if the source value is invalid
2482 * DISP_E_OVERFLOW, if the value will not fit in the destination
2485 * Negative values >= -5000 will be converted to 0.
2487 HRESULT WINAPI
VarUI8FromCy(CY cyIn
, ULONG64
* pui64Out
)
2491 if (cyIn
.int64
< -CY_HALF
)
2492 return DISP_E_OVERFLOW
;
2497 *pui64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2499 cyIn
.int64
-= *pui64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2501 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pui64Out
& 0x1)))
2507 /************************************************************************
2508 * VarUI8FromDate (OLEAUT32.434)
2510 * Convert a VT_DATE to a VT_UI8.
2514 * pui64Out [O] Destination
2518 * Failure: E_INVALIDARG, if the source value is invalid
2519 * DISP_E_OVERFLOW, if the value will not fit in the destination
2520 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2522 HRESULT WINAPI
VarUI8FromDate(DATE dateIn
, ULONG64
* pui64Out
)
2524 return VarUI8FromR8(dateIn
, pui64Out
);
2527 /************************************************************************
2528 * VarUI8FromStr (OLEAUT32.435)
2530 * Convert a VT_BSTR to a VT_UI8.
2534 * lcid [I] LCID for the conversion
2535 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2536 * pui64Out [O] Destination
2540 * Failure: E_INVALIDARG, if the source value is invalid
2541 * DISP_E_OVERFLOW, if the value will not fit in the destination
2542 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2544 HRESULT WINAPI
VarUI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG64
* pui64Out
)
2546 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pui64Out
, VT_UI8
);
2549 /************************************************************************
2550 * VarUI8FromDisp (OLEAUT32.436)
2552 * Convert a VT_DISPATCH to a VT_UI8.
2555 * pdispIn [I] Source
2556 * lcid [I] LCID for conversion
2557 * pui64Out [O] Destination
2561 * Failure: E_INVALIDARG, if the source value is invalid
2562 * DISP_E_OVERFLOW, if the value will not fit in the destination
2563 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2565 HRESULT WINAPI
VarUI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG64
* pui64Out
)
2567 return VARIANT_FromDisp(pdispIn
, lcid
, pui64Out
, VT_UI8
, 0);
2570 /************************************************************************
2571 * VarUI8FromBool (OLEAUT32.437)
2573 * Convert a VT_BOOL to a VT_UI8.
2577 * pui64Out [O] Destination
2581 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2583 HRESULT WINAPI
VarUI8FromBool(VARIANT_BOOL boolIn
, ULONG64
* pui64Out
)
2585 return VarI8FromI2(boolIn
, (LONG64
*)pui64Out
);
2587 /************************************************************************
2588 * VarUI8FromI1 (OLEAUT32.438)
2590 * Convert a VT_I1 to a VT_UI8.
2594 * pui64Out [O] Destination
2598 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2600 HRESULT WINAPI
VarUI8FromI1(signed char cIn
, ULONG64
* pui64Out
)
2602 return _VarUI8FromI1(cIn
, pui64Out
);
2605 /************************************************************************
2606 * VarUI8FromUI2 (OLEAUT32.439)
2608 * Convert a VT_UI2 to a VT_UI8.
2612 * pui64Out [O] Destination
2617 HRESULT WINAPI
VarUI8FromUI2(USHORT usIn
, ULONG64
* pui64Out
)
2619 return _VarUI8FromUI2(usIn
, pui64Out
);
2622 /************************************************************************
2623 * VarUI8FromUI4 (OLEAUT32.440)
2625 * Convert a VT_UI4 to a VT_UI8.
2629 * pui64Out [O] Destination
2634 HRESULT WINAPI
VarUI8FromUI4(ULONG ulIn
, ULONG64
* pui64Out
)
2636 return _VarUI8FromUI4(ulIn
, pui64Out
);
2639 /************************************************************************
2640 * VarUI8FromDec (OLEAUT32.441)
2642 * Convert a VT_DECIMAL to a VT_UI8.
2646 * pui64Out [O] Destination
2650 * Failure: E_INVALIDARG, if the source value is invalid
2651 * DISP_E_OVERFLOW, if the value will not fit in the destination
2654 * Under native Win32, if the source value has a scale of 0, its sign is
2655 * ignored, i.e. this function takes the absolute value rather than fail
2656 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2657 * (use VarAbs() on pDecIn first if you really want this behaviour).
2659 HRESULT WINAPI
VarUI8FromDec(DECIMAL
*pdecIn
, ULONG64
* pui64Out
)
2661 if (!DEC_SCALE(pdecIn
))
2663 /* This decimal is just a 96 bit integer */
2664 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2665 return E_INVALIDARG
;
2667 if (DEC_HI32(pdecIn
))
2668 return DISP_E_OVERFLOW
;
2670 if (DEC_SIGN(pdecIn
))
2672 WARN("Sign would be ignored under Win32!\n");
2673 return DISP_E_OVERFLOW
;
2676 *pui64Out
= DEC_LO64(pdecIn
);
2681 /* Decimal contains a floating point number */
2685 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2686 if (SUCCEEDED(hRet
))
2687 hRet
= VarUI8FromR8(dbl
, pui64Out
);
2695 /************************************************************************
2696 * VarR4FromUI1 (OLEAUT32.68)
2698 * Convert a VT_UI1 to a VT_R4.
2702 * pFltOut [O] Destination
2707 HRESULT WINAPI
VarR4FromUI1(BYTE bIn
, float *pFltOut
)
2709 return _VarR4FromUI1(bIn
, pFltOut
);
2712 /************************************************************************
2713 * VarR4FromI2 (OLEAUT32.69)
2715 * Convert a VT_I2 to a VT_R4.
2719 * pFltOut [O] Destination
2724 HRESULT WINAPI
VarR4FromI2(SHORT sIn
, float *pFltOut
)
2726 return _VarR4FromI2(sIn
, pFltOut
);
2729 /************************************************************************
2730 * VarR4FromI4 (OLEAUT32.70)
2732 * Convert a VT_I4 to a VT_R4.
2736 * pFltOut [O] Destination
2741 HRESULT WINAPI
VarR4FromI4(LONG lIn
, float *pFltOut
)
2743 return _VarR4FromI4(lIn
, pFltOut
);
2746 /************************************************************************
2747 * VarR4FromR8 (OLEAUT32.71)
2749 * Convert a VT_R8 to a VT_R4.
2753 * pFltOut [O] Destination
2757 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2759 HRESULT WINAPI
VarR4FromR8(double dblIn
, float *pFltOut
)
2761 double d
= dblIn
< 0.0 ? -dblIn
: dblIn
;
2762 if (d
> R4_MAX
) return DISP_E_OVERFLOW
;
2767 /************************************************************************
2768 * VarR4FromCy (OLEAUT32.72)
2770 * Convert a VT_CY to a VT_R4.
2774 * pFltOut [O] Destination
2779 HRESULT WINAPI
VarR4FromCy(CY cyIn
, float *pFltOut
)
2781 *pFltOut
= (double)cyIn
.int64
/ CY_MULTIPLIER_F
;
2785 /************************************************************************
2786 * VarR4FromDate (OLEAUT32.73)
2788 * Convert a VT_DATE to a VT_R4.
2792 * pFltOut [O] Destination
2796 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2798 HRESULT WINAPI
VarR4FromDate(DATE dateIn
, float *pFltOut
)
2800 return VarR4FromR8(dateIn
, pFltOut
);
2803 /************************************************************************
2804 * VarR4FromStr (OLEAUT32.74)
2806 * Convert a VT_BSTR to a VT_R4.
2810 * lcid [I] LCID for the conversion
2811 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2812 * pFltOut [O] Destination
2816 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2817 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2819 HRESULT WINAPI
VarR4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, float *pFltOut
)
2821 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pFltOut
, VT_R4
);
2824 /************************************************************************
2825 * VarR4FromDisp (OLEAUT32.75)
2827 * Convert a VT_DISPATCH to a VT_R4.
2830 * pdispIn [I] Source
2831 * lcid [I] LCID for conversion
2832 * pFltOut [O] Destination
2836 * Failure: E_INVALIDARG, if the source value is invalid
2837 * DISP_E_OVERFLOW, if the value will not fit in the destination
2838 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2840 HRESULT WINAPI
VarR4FromDisp(IDispatch
* pdispIn
, LCID lcid
, float *pFltOut
)
2842 return VARIANT_FromDisp(pdispIn
, lcid
, pFltOut
, VT_R4
, 0);
2845 /************************************************************************
2846 * VarR4FromBool (OLEAUT32.76)
2848 * Convert a VT_BOOL to a VT_R4.
2852 * pFltOut [O] Destination
2857 HRESULT WINAPI
VarR4FromBool(VARIANT_BOOL boolIn
, float *pFltOut
)
2859 return VarR4FromI2(boolIn
, pFltOut
);
2862 /************************************************************************
2863 * VarR4FromI1 (OLEAUT32.213)
2865 * Convert a VT_I1 to a VT_R4.
2869 * pFltOut [O] Destination
2873 * Failure: E_INVALIDARG, if the source value is invalid
2874 * DISP_E_OVERFLOW, if the value will not fit in the destination
2875 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2877 HRESULT WINAPI
VarR4FromI1(signed char cIn
, float *pFltOut
)
2879 return _VarR4FromI1(cIn
, pFltOut
);
2882 /************************************************************************
2883 * VarR4FromUI2 (OLEAUT32.214)
2885 * Convert a VT_UI2 to a VT_R4.
2889 * pFltOut [O] Destination
2893 * Failure: E_INVALIDARG, if the source value is invalid
2894 * DISP_E_OVERFLOW, if the value will not fit in the destination
2895 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2897 HRESULT WINAPI
VarR4FromUI2(USHORT usIn
, float *pFltOut
)
2899 return _VarR4FromUI2(usIn
, pFltOut
);
2902 /************************************************************************
2903 * VarR4FromUI4 (OLEAUT32.215)
2905 * Convert a VT_UI4 to a VT_R4.
2909 * pFltOut [O] Destination
2913 * Failure: E_INVALIDARG, if the source value is invalid
2914 * DISP_E_OVERFLOW, if the value will not fit in the destination
2915 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2917 HRESULT WINAPI
VarR4FromUI4(ULONG ulIn
, float *pFltOut
)
2919 return _VarR4FromUI4(ulIn
, pFltOut
);
2922 /************************************************************************
2923 * VarR4FromDec (OLEAUT32.216)
2925 * Convert a VT_DECIMAL to a VT_R4.
2929 * pFltOut [O] Destination
2933 * Failure: E_INVALIDARG, if the source value is invalid.
2935 HRESULT WINAPI
VarR4FromDec(DECIMAL
* pDecIn
, float *pFltOut
)
2937 BYTE scale
= DEC_SCALE(pDecIn
);
2938 double divisor
= 1.0;
2941 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
2942 return E_INVALIDARG
;
2947 if (DEC_SIGN(pDecIn
))
2950 if (DEC_HI32(pDecIn
))
2952 highPart
= (double)DEC_HI32(pDecIn
) / divisor
;
2953 highPart
*= 4294967296.0F
;
2954 highPart
*= 4294967296.0F
;
2959 *pFltOut
= (double)DEC_LO64(pDecIn
) / divisor
+ highPart
;
2963 /************************************************************************
2964 * VarR4FromI8 (OLEAUT32.360)
2966 * Convert a VT_I8 to a VT_R4.
2970 * pFltOut [O] Destination
2975 HRESULT WINAPI
VarR4FromI8(LONG64 llIn
, float *pFltOut
)
2977 return _VarR4FromI8(llIn
, pFltOut
);
2980 /************************************************************************
2981 * VarR4FromUI8 (OLEAUT32.361)
2983 * Convert a VT_UI8 to a VT_R4.
2987 * pFltOut [O] Destination
2992 HRESULT WINAPI
VarR4FromUI8(ULONG64 ullIn
, float *pFltOut
)
2994 return _VarR4FromUI8(ullIn
, pFltOut
);
2997 /************************************************************************
2998 * VarR4CmpR8 (OLEAUT32.316)
3000 * Compare a VT_R4 to a VT_R8.
3003 * fltLeft [I] Source
3004 * dblRight [I] Value to compare
3007 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3008 * equal to or greater than dblRight respectively.
3010 HRESULT WINAPI
VarR4CmpR8(float fltLeft
, double dblRight
)
3012 if (fltLeft
< dblRight
)
3014 else if (fltLeft
> dblRight
)
3022 /************************************************************************
3023 * VarR8FromUI1 (OLEAUT32.78)
3025 * Convert a VT_UI1 to a VT_R8.
3029 * pDblOut [O] Destination
3034 HRESULT WINAPI
VarR8FromUI1(BYTE bIn
, double *pDblOut
)
3036 return _VarR8FromUI1(bIn
, pDblOut
);
3039 /************************************************************************
3040 * VarR8FromI2 (OLEAUT32.79)
3042 * Convert a VT_I2 to a VT_R8.
3046 * pDblOut [O] Destination
3051 HRESULT WINAPI
VarR8FromI2(SHORT sIn
, double *pDblOut
)
3053 return _VarR8FromI2(sIn
, pDblOut
);
3056 /************************************************************************
3057 * VarR8FromI4 (OLEAUT32.80)
3059 * Convert a VT_I4 to a VT_R8.
3063 * pDblOut [O] Destination
3068 HRESULT WINAPI
VarR8FromI4(LONG lIn
, double *pDblOut
)
3070 return _VarR8FromI4(lIn
, pDblOut
);
3073 /************************************************************************
3074 * VarR8FromR4 (OLEAUT32.81)
3076 * Convert a VT_R4 to a VT_R8.
3080 * pDblOut [O] Destination
3085 HRESULT WINAPI
VarR8FromR4(FLOAT fltIn
, double *pDblOut
)
3087 return _VarR8FromR4(fltIn
, pDblOut
);
3090 /************************************************************************
3091 * VarR8FromCy (OLEAUT32.82)
3093 * Convert a VT_CY to a VT_R8.
3097 * pDblOut [O] Destination
3102 HRESULT WINAPI
VarR8FromCy(CY cyIn
, double *pDblOut
)
3104 return _VarR8FromCy(cyIn
, pDblOut
);
3107 /************************************************************************
3108 * VarR8FromDate (OLEAUT32.83)
3110 * Convert a VT_DATE to a VT_R8.
3114 * pDblOut [O] Destination
3119 HRESULT WINAPI
VarR8FromDate(DATE dateIn
, double *pDblOut
)
3121 return _VarR8FromDate(dateIn
, pDblOut
);
3124 /************************************************************************
3125 * VarR8FromStr (OLEAUT32.84)
3127 * Convert a VT_BSTR to a VT_R8.
3131 * lcid [I] LCID for the conversion
3132 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3133 * pDblOut [O] Destination
3137 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3138 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3140 HRESULT WINAPI
VarR8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, double *pDblOut
)
3142 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDblOut
, VT_R8
);
3145 /************************************************************************
3146 * VarR8FromDisp (OLEAUT32.85)
3148 * Convert a VT_DISPATCH to a VT_R8.
3151 * pdispIn [I] Source
3152 * lcid [I] LCID for conversion
3153 * pDblOut [O] Destination
3157 * Failure: E_INVALIDARG, if the source value is invalid
3158 * DISP_E_OVERFLOW, if the value will not fit in the destination
3159 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3161 HRESULT WINAPI
VarR8FromDisp(IDispatch
* pdispIn
, LCID lcid
, double *pDblOut
)
3163 return VARIANT_FromDisp(pdispIn
, lcid
, pDblOut
, VT_R8
, 0);
3166 /************************************************************************
3167 * VarR8FromBool (OLEAUT32.86)
3169 * Convert a VT_BOOL to a VT_R8.
3173 * pDblOut [O] Destination
3178 HRESULT WINAPI
VarR8FromBool(VARIANT_BOOL boolIn
, double *pDblOut
)
3180 return VarR8FromI2(boolIn
, pDblOut
);
3183 /************************************************************************
3184 * VarR8FromI1 (OLEAUT32.217)
3186 * Convert a VT_I1 to a VT_R8.
3190 * pDblOut [O] Destination
3194 * Failure: E_INVALIDARG, if the source value is invalid
3195 * DISP_E_OVERFLOW, if the value will not fit in the destination
3196 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3198 HRESULT WINAPI
VarR8FromI1(signed char cIn
, double *pDblOut
)
3200 return _VarR8FromI1(cIn
, pDblOut
);
3203 /************************************************************************
3204 * VarR8FromUI2 (OLEAUT32.218)
3206 * Convert a VT_UI2 to a VT_R8.
3210 * pDblOut [O] Destination
3214 * Failure: E_INVALIDARG, if the source value is invalid
3215 * DISP_E_OVERFLOW, if the value will not fit in the destination
3216 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3218 HRESULT WINAPI
VarR8FromUI2(USHORT usIn
, double *pDblOut
)
3220 return _VarR8FromUI2(usIn
, pDblOut
);
3223 /************************************************************************
3224 * VarR8FromUI4 (OLEAUT32.219)
3226 * Convert a VT_UI4 to a VT_R8.
3230 * pDblOut [O] Destination
3234 * Failure: E_INVALIDARG, if the source value is invalid
3235 * DISP_E_OVERFLOW, if the value will not fit in the destination
3236 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3238 HRESULT WINAPI
VarR8FromUI4(ULONG ulIn
, double *pDblOut
)
3240 return _VarR8FromUI4(ulIn
, pDblOut
);
3243 /************************************************************************
3244 * VarR8FromDec (OLEAUT32.220)
3246 * Convert a VT_DECIMAL to a VT_R8.
3250 * pDblOut [O] Destination
3254 * Failure: E_INVALIDARG, if the source value is invalid.
3256 HRESULT WINAPI
VarR8FromDec(const DECIMAL
* pDecIn
, double *pDblOut
)
3258 BYTE scale
= DEC_SCALE(pDecIn
);
3259 double divisor
= 1.0, highPart
;
3261 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
3262 return E_INVALIDARG
;
3267 if (DEC_SIGN(pDecIn
))
3270 if (DEC_HI32(pDecIn
))
3272 highPart
= (double)DEC_HI32(pDecIn
) / divisor
;
3273 highPart
*= 4294967296.0F
;
3274 highPart
*= 4294967296.0F
;
3279 *pDblOut
= (double)DEC_LO64(pDecIn
) / divisor
+ highPart
;
3283 /************************************************************************
3284 * VarR8FromI8 (OLEAUT32.362)
3286 * Convert a VT_I8 to a VT_R8.
3290 * pDblOut [O] Destination
3295 HRESULT WINAPI
VarR8FromI8(LONG64 llIn
, double *pDblOut
)
3297 return _VarR8FromI8(llIn
, pDblOut
);
3300 /************************************************************************
3301 * VarR8FromUI8 (OLEAUT32.363)
3303 * Convert a VT_UI8 to a VT_R8.
3307 * pDblOut [O] Destination
3312 HRESULT WINAPI
VarR8FromUI8(ULONG64 ullIn
, double *pDblOut
)
3314 return _VarR8FromUI8(ullIn
, pDblOut
);
3317 /************************************************************************
3318 * VarR8Pow (OLEAUT32.315)
3320 * Raise a VT_R8 to a power.
3323 * dblLeft [I] Source
3324 * dblPow [I] Power to raise dblLeft by
3325 * pDblOut [O] Destination
3328 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3330 HRESULT WINAPI
VarR8Pow(double dblLeft
, double dblPow
, double *pDblOut
)
3332 *pDblOut
= pow(dblLeft
, dblPow
);
3336 /************************************************************************
3337 * VarR8Round (OLEAUT32.317)
3339 * Round a VT_R8 to a given number of decimal points.
3343 * nDig [I] Number of decimal points to round to
3344 * pDblOut [O] Destination for rounded number
3347 * Success: S_OK. pDblOut is rounded to nDig digits.
3348 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3351 * The native version of this function rounds using the internal
3352 * binary representation of the number. Wine uses the dutch rounding
3353 * convention, so therefore small differences can occur in the value returned.
3354 * MSDN says that you should use your own rounding function if you want
3355 * rounding to be predictable in your application.
3357 HRESULT WINAPI
VarR8Round(double dblIn
, int nDig
, double *pDblOut
)
3359 double scale
, whole
, fract
;
3362 return E_INVALIDARG
;
3364 scale
= pow(10.0, nDig
);
3367 whole
= dblIn
< 0 ? ceil(dblIn
) : floor(dblIn
);
3368 fract
= dblIn
- whole
;
3371 dblIn
= whole
+ 1.0;
3372 else if (fract
== 0.5)
3373 dblIn
= whole
+ fmod(whole
, 2.0);
3374 else if (fract
>= 0.0)
3376 else if (fract
== -0.5)
3377 dblIn
= whole
- fmod(whole
, 2.0);
3378 else if (fract
> -0.5)
3381 dblIn
= whole
- 1.0;
3383 *pDblOut
= dblIn
/ scale
;
3390 /* Powers of 10 from 0..4 D.P. */
3391 static const int CY_Divisors
[5] = { CY_MULTIPLIER
/10000, CY_MULTIPLIER
/1000,
3392 CY_MULTIPLIER
/100, CY_MULTIPLIER
/10, CY_MULTIPLIER
};
3394 /************************************************************************
3395 * VarCyFromUI1 (OLEAUT32.98)
3397 * Convert a VT_UI1 to a VT_CY.
3401 * pCyOut [O] Destination
3405 * Failure: E_INVALIDARG, if the source value is invalid
3406 * DISP_E_OVERFLOW, if the value will not fit in the destination
3407 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3409 HRESULT WINAPI
VarCyFromUI1(BYTE bIn
, CY
* pCyOut
)
3411 pCyOut
->int64
= (ULONG64
)bIn
* CY_MULTIPLIER
;
3415 /************************************************************************
3416 * VarCyFromI2 (OLEAUT32.99)
3418 * Convert a VT_I2 to a VT_CY.
3422 * pCyOut [O] Destination
3426 * Failure: E_INVALIDARG, if the source value is invalid
3427 * DISP_E_OVERFLOW, if the value will not fit in the destination
3428 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3430 HRESULT WINAPI
VarCyFromI2(SHORT sIn
, CY
* pCyOut
)
3432 pCyOut
->int64
= (LONG64
)sIn
* CY_MULTIPLIER
;
3436 /************************************************************************
3437 * VarCyFromI4 (OLEAUT32.100)
3439 * Convert a VT_I4 to a VT_CY.
3443 * pCyOut [O] Destination
3447 * Failure: E_INVALIDARG, if the source value is invalid
3448 * DISP_E_OVERFLOW, if the value will not fit in the destination
3449 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3451 HRESULT WINAPI
VarCyFromI4(LONG lIn
, CY
* pCyOut
)
3453 pCyOut
->int64
= (LONG64
)lIn
* CY_MULTIPLIER
;
3457 /************************************************************************
3458 * VarCyFromR4 (OLEAUT32.101)
3460 * Convert a VT_R4 to a VT_CY.
3464 * pCyOut [O] Destination
3468 * Failure: E_INVALIDARG, if the source value is invalid
3469 * DISP_E_OVERFLOW, if the value will not fit in the destination
3470 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3472 HRESULT WINAPI
VarCyFromR4(FLOAT fltIn
, CY
* pCyOut
)
3474 return VarCyFromR8(fltIn
, pCyOut
);
3477 /************************************************************************
3478 * VarCyFromR8 (OLEAUT32.102)
3480 * Convert a VT_R8 to a VT_CY.
3484 * pCyOut [O] Destination
3488 * Failure: E_INVALIDARG, if the source value is invalid
3489 * DISP_E_OVERFLOW, if the value will not fit in the destination
3490 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3492 HRESULT WINAPI
VarCyFromR8(double dblIn
, CY
* pCyOut
)
3494 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3495 /* This code gives identical results to Win32 on Intel.
3496 * Here we use fp exceptions to catch overflows when storing the value.
3498 static const unsigned short r8_fpcontrol
= 0x137f;
3499 static const double r8_multiplier
= CY_MULTIPLIER_F
;
3500 unsigned short old_fpcontrol
, result_fpstatus
;
3502 /* Clear exceptions, save the old fp state and load the new state */
3503 __asm__
__volatile__( "fnclex" );
3504 __asm__
__volatile__( "fstcw %0" : "=m" (old_fpcontrol
) : );
3505 __asm__
__volatile__( "fldcw %0" : : "m" (r8_fpcontrol
) );
3506 /* Perform the conversion. */
3507 __asm__
__volatile__( "fldl %0" : : "m" (dblIn
) );
3508 __asm__
__volatile__( "fmull %0" : : "m" (r8_multiplier
) );
3509 __asm__
__volatile__( "fistpll %0" : : "m" (*pCyOut
) );
3510 /* Save the resulting fp state, load the old state and clear exceptions */
3511 __asm__
__volatile__( "fstsw %0" : "=m" (result_fpstatus
) : );
3512 __asm__
__volatile__( "fnclex" );
3513 __asm__
__volatile__( "fldcw %0" : : "m" (old_fpcontrol
) );
3515 if (result_fpstatus
& 0x9) /* Overflow | Invalid */
3516 return DISP_E_OVERFLOW
;
3518 /* This version produces slightly different results for boundary cases */
3519 if (dblIn
< -922337203685477.5807 || dblIn
>= 922337203685477.5807)
3520 return DISP_E_OVERFLOW
;
3521 dblIn
*= CY_MULTIPLIER_F
;
3522 VARIANT_DutchRound(LONG64
, dblIn
, pCyOut
->int64
);
3527 /************************************************************************
3528 * VarCyFromDate (OLEAUT32.103)
3530 * Convert a VT_DATE to a VT_CY.
3534 * pCyOut [O] Destination
3538 * Failure: E_INVALIDARG, if the source value is invalid
3539 * DISP_E_OVERFLOW, if the value will not fit in the destination
3540 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3542 HRESULT WINAPI
VarCyFromDate(DATE dateIn
, CY
* pCyOut
)
3544 return VarCyFromR8(dateIn
, pCyOut
);
3547 /************************************************************************
3548 * VarCyFromStr (OLEAUT32.104)
3550 * Convert a VT_BSTR to a VT_CY.
3554 * lcid [I] LCID for the conversion
3555 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3556 * pCyOut [O] Destination
3560 * Failure: E_INVALIDARG, if the source value is invalid
3561 * DISP_E_OVERFLOW, if the value will not fit in the destination
3562 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3564 HRESULT WINAPI
VarCyFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, CY
* pCyOut
)
3566 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pCyOut
, VT_CY
);
3569 /************************************************************************
3570 * VarCyFromDisp (OLEAUT32.105)
3572 * Convert a VT_DISPATCH to a VT_CY.
3575 * pdispIn [I] Source
3576 * lcid [I] LCID for conversion
3577 * pCyOut [O] Destination
3581 * Failure: E_INVALIDARG, if the source value is invalid
3582 * DISP_E_OVERFLOW, if the value will not fit in the destination
3583 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3585 HRESULT WINAPI
VarCyFromDisp(IDispatch
* pdispIn
, LCID lcid
, CY
* pCyOut
)
3587 return VARIANT_FromDisp(pdispIn
, lcid
, pCyOut
, VT_CY
, 0);
3590 /************************************************************************
3591 * VarCyFromBool (OLEAUT32.106)
3593 * Convert a VT_BOOL to a VT_CY.
3597 * pCyOut [O] Destination
3601 * Failure: E_INVALIDARG, if the source value is invalid
3602 * DISP_E_OVERFLOW, if the value will not fit in the destination
3603 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3606 * While the sign of the boolean is stored in the currency, the value is
3607 * converted to either 0 or 1.
3609 HRESULT WINAPI
VarCyFromBool(VARIANT_BOOL boolIn
, CY
* pCyOut
)
3611 pCyOut
->int64
= (LONG64
)boolIn
* CY_MULTIPLIER
;
3615 /************************************************************************
3616 * VarCyFromI1 (OLEAUT32.225)
3618 * Convert a VT_I1 to a VT_CY.
3622 * pCyOut [O] Destination
3626 * Failure: E_INVALIDARG, if the source value is invalid
3627 * DISP_E_OVERFLOW, if the value will not fit in the destination
3628 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3630 HRESULT WINAPI
VarCyFromI1(signed char cIn
, CY
* pCyOut
)
3632 pCyOut
->int64
= (LONG64
)cIn
* CY_MULTIPLIER
;
3636 /************************************************************************
3637 * VarCyFromUI2 (OLEAUT32.226)
3639 * Convert a VT_UI2 to a VT_CY.
3643 * pCyOut [O] Destination
3647 * Failure: E_INVALIDARG, if the source value is invalid
3648 * DISP_E_OVERFLOW, if the value will not fit in the destination
3649 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3651 HRESULT WINAPI
VarCyFromUI2(USHORT usIn
, CY
* pCyOut
)
3653 pCyOut
->int64
= (ULONG64
)usIn
* CY_MULTIPLIER
;
3657 /************************************************************************
3658 * VarCyFromUI4 (OLEAUT32.227)
3660 * Convert a VT_UI4 to a VT_CY.
3664 * pCyOut [O] Destination
3668 * Failure: E_INVALIDARG, if the source value is invalid
3669 * DISP_E_OVERFLOW, if the value will not fit in the destination
3670 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3672 HRESULT WINAPI
VarCyFromUI4(ULONG ulIn
, CY
* pCyOut
)
3674 pCyOut
->int64
= (ULONG64
)ulIn
* CY_MULTIPLIER
;
3678 /************************************************************************
3679 * VarCyFromDec (OLEAUT32.228)
3681 * Convert a VT_DECIMAL to a VT_CY.
3685 * pCyOut [O] Destination
3689 * Failure: E_INVALIDARG, if the source value is invalid
3690 * DISP_E_OVERFLOW, if the value will not fit in the destination
3691 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3693 HRESULT WINAPI
VarCyFromDec(DECIMAL
* pdecIn
, CY
* pCyOut
)
3698 hRet
= VarDecRound(pdecIn
, 4, &rounded
);
3700 if (SUCCEEDED(hRet
))
3704 if (DEC_HI32(&rounded
))
3705 return DISP_E_OVERFLOW
;
3707 /* Note: Without the casts this promotes to int64 which loses precision */
3708 d
= (double)DEC_LO64(&rounded
) / (double)CY_Divisors
[DEC_SCALE(&rounded
)];
3709 if (DEC_SIGN(&rounded
))
3711 return VarCyFromR8(d
, pCyOut
);
3716 /************************************************************************
3717 * VarCyFromI8 (OLEAUT32.366)
3719 * Convert a VT_I8 to a VT_CY.
3723 * pCyOut [O] Destination
3727 * Failure: E_INVALIDARG, if the source value is invalid
3728 * DISP_E_OVERFLOW, if the value will not fit in the destination
3729 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3731 HRESULT WINAPI
VarCyFromI8(LONG64 llIn
, CY
* pCyOut
)
3733 if (llIn
<= (I8_MIN
/CY_MULTIPLIER
) || llIn
>= (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3734 pCyOut
->int64
= llIn
* CY_MULTIPLIER
;
3738 /************************************************************************
3739 * VarCyFromUI8 (OLEAUT32.375)
3741 * Convert a VT_UI8 to a VT_CY.
3745 * pCyOut [O] Destination
3749 * Failure: E_INVALIDARG, if the source value is invalid
3750 * DISP_E_OVERFLOW, if the value will not fit in the destination
3751 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3753 HRESULT WINAPI
VarCyFromUI8(ULONG64 ullIn
, CY
* pCyOut
)
3755 if (ullIn
> (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3756 pCyOut
->int64
= ullIn
* CY_MULTIPLIER
;
3760 /************************************************************************
3761 * VarCyAdd (OLEAUT32.299)
3763 * Add one CY to another.
3767 * cyRight [I] Value to add
3768 * pCyOut [O] Destination
3772 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3774 HRESULT WINAPI
VarCyAdd(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3777 _VarR8FromCy(cyLeft
, &l
);
3778 _VarR8FromCy(cyRight
, &r
);
3780 return VarCyFromR8(l
, pCyOut
);
3783 /************************************************************************
3784 * VarCyMul (OLEAUT32.303)
3786 * Multiply one CY by another.
3790 * cyRight [I] Value to multiply by
3791 * pCyOut [O] Destination
3795 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3797 HRESULT WINAPI
VarCyMul(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3800 _VarR8FromCy(cyLeft
, &l
);
3801 _VarR8FromCy(cyRight
, &r
);
3803 return VarCyFromR8(l
, pCyOut
);
3806 /************************************************************************
3807 * VarCyMulI4 (OLEAUT32.304)
3809 * Multiply one CY by a VT_I4.
3813 * lRight [I] Value to multiply by
3814 * pCyOut [O] Destination
3818 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3820 HRESULT WINAPI
VarCyMulI4(const CY cyLeft
, LONG lRight
, CY
* pCyOut
)
3824 _VarR8FromCy(cyLeft
, &d
);
3826 return VarCyFromR8(d
, pCyOut
);
3829 /************************************************************************
3830 * VarCySub (OLEAUT32.305)
3832 * Subtract one CY from another.
3836 * cyRight [I] Value to subtract
3837 * pCyOut [O] Destination
3841 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3843 HRESULT WINAPI
VarCySub(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3846 _VarR8FromCy(cyLeft
, &l
);
3847 _VarR8FromCy(cyRight
, &r
);
3849 return VarCyFromR8(l
, pCyOut
);
3852 /************************************************************************
3853 * VarCyAbs (OLEAUT32.306)
3855 * Convert a VT_CY into its absolute value.
3859 * pCyOut [O] Destination
3862 * Success: S_OK. pCyOut contains the absolute value.
3863 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3865 HRESULT WINAPI
VarCyAbs(const CY cyIn
, CY
* pCyOut
)
3867 if (cyIn
.s
.Hi
== (int)0x80000000 && !cyIn
.s
.Lo
)
3868 return DISP_E_OVERFLOW
;
3870 pCyOut
->int64
= cyIn
.int64
< 0 ? -cyIn
.int64
: cyIn
.int64
;
3874 /************************************************************************
3875 * VarCyFix (OLEAUT32.307)
3877 * Return the integer part of a VT_CY.
3881 * pCyOut [O] Destination
3885 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3888 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3889 * negative numbers away from 0, while this function rounds them towards zero.
3891 HRESULT WINAPI
VarCyFix(const CY cyIn
, CY
* pCyOut
)
3893 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3894 pCyOut
->int64
*= CY_MULTIPLIER
;
3898 /************************************************************************
3899 * VarCyInt (OLEAUT32.308)
3901 * Return the integer part of a VT_CY.
3905 * pCyOut [O] Destination
3909 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3912 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3913 * negative numbers towards 0, while this function rounds them away from zero.
3915 HRESULT WINAPI
VarCyInt(const CY cyIn
, CY
* pCyOut
)
3917 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3918 pCyOut
->int64
*= CY_MULTIPLIER
;
3920 if (cyIn
.int64
< 0 && cyIn
.int64
% CY_MULTIPLIER
!= 0)
3922 pCyOut
->int64
-= CY_MULTIPLIER
;
3927 /************************************************************************
3928 * VarCyNeg (OLEAUT32.309)
3930 * Change the sign of a VT_CY.
3934 * pCyOut [O] Destination
3938 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3940 HRESULT WINAPI
VarCyNeg(const CY cyIn
, CY
* pCyOut
)
3942 if (cyIn
.s
.Hi
== (int)0x80000000 && !cyIn
.s
.Lo
)
3943 return DISP_E_OVERFLOW
;
3945 pCyOut
->int64
= -cyIn
.int64
;
3949 /************************************************************************
3950 * VarCyRound (OLEAUT32.310)
3952 * Change the precision of a VT_CY.
3956 * cDecimals [I] New number of decimals to keep
3957 * pCyOut [O] Destination
3961 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3963 HRESULT WINAPI
VarCyRound(const CY cyIn
, int cDecimals
, CY
* pCyOut
)
3966 return E_INVALIDARG
;
3970 /* Rounding to more precision than we have */
3976 double d
, div
= CY_Divisors
[cDecimals
];
3978 _VarR8FromCy(cyIn
, &d
);
3980 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
3981 d
= (double)pCyOut
->int64
/ div
* CY_MULTIPLIER_F
;
3982 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
3987 /************************************************************************
3988 * VarCyCmp (OLEAUT32.311)
3990 * Compare two VT_CY values.
3994 * cyRight [I] Value to compare
3997 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
3998 * compare is less, equal or greater than source respectively.
3999 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4001 HRESULT WINAPI
VarCyCmp(const CY cyLeft
, const CY cyRight
)
4006 /* Subtract right from left, and compare the result to 0 */
4007 hRet
= VarCySub(cyLeft
, cyRight
, &result
);
4009 if (SUCCEEDED(hRet
))
4011 if (result
.int64
< 0)
4012 hRet
= (HRESULT
)VARCMP_LT
;
4013 else if (result
.int64
> 0)
4014 hRet
= (HRESULT
)VARCMP_GT
;
4016 hRet
= (HRESULT
)VARCMP_EQ
;
4021 /************************************************************************
4022 * VarCyCmpR8 (OLEAUT32.312)
4024 * Compare a VT_CY to a double
4027 * cyLeft [I] Currency Source
4028 * dblRight [I] double to compare to cyLeft
4031 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4032 * less than, equal to or greater than cyLeft respectively.
4033 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4035 HRESULT WINAPI
VarCyCmpR8(const CY cyLeft
, double dblRight
)
4040 hRet
= VarCyFromR8(dblRight
, &cyRight
);
4042 if (SUCCEEDED(hRet
))
4043 hRet
= VarCyCmp(cyLeft
, cyRight
);
4048 /************************************************************************
4049 * VarCyMulI8 (OLEAUT32.329)
4051 * Multiply a VT_CY by a VT_I8.
4055 * llRight [I] Value to multiply by
4056 * pCyOut [O] Destination
4060 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4062 HRESULT WINAPI
VarCyMulI8(const CY cyLeft
, LONG64 llRight
, CY
* pCyOut
)
4066 _VarR8FromCy(cyLeft
, &d
);
4067 d
= d
* (double)llRight
;
4068 return VarCyFromR8(d
, pCyOut
);
4074 /************************************************************************
4075 * VarDecFromUI1 (OLEAUT32.190)
4077 * Convert a VT_UI1 to a DECIMAL.
4081 * pDecOut [O] Destination
4086 HRESULT WINAPI
VarDecFromUI1(BYTE bIn
, DECIMAL
* pDecOut
)
4088 return VarDecFromUI4(bIn
, pDecOut
);
4091 /************************************************************************
4092 * VarDecFromI2 (OLEAUT32.191)
4094 * Convert a VT_I2 to a DECIMAL.
4098 * pDecOut [O] Destination
4103 HRESULT WINAPI
VarDecFromI2(SHORT sIn
, DECIMAL
* pDecOut
)
4105 return VarDecFromI4(sIn
, pDecOut
);
4108 /************************************************************************
4109 * VarDecFromI4 (OLEAUT32.192)
4111 * Convert a VT_I4 to a DECIMAL.
4115 * pDecOut [O] Destination
4120 HRESULT WINAPI
VarDecFromI4(LONG lIn
, DECIMAL
* pDecOut
)
4122 DEC_HI32(pDecOut
) = 0;
4123 DEC_MID32(pDecOut
) = 0;
4127 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4128 DEC_LO32(pDecOut
) = -lIn
;
4132 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4133 DEC_LO32(pDecOut
) = lIn
;
4138 /* internal representation of the value stored in a DECIMAL. The bytes are
4139 stored from LSB at index 0 to MSB at index 11
4141 typedef struct DECIMAL_internal
4143 DWORD bitsnum
[3]; /* 96 significant bits, unsigned */
4144 unsigned char scale
; /* number scaled * 10 ^ -(scale) */
4145 unsigned int sign
: 1; /* 0 - positive, 1 - negative */
4148 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
);
4149 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
);
4150 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
);
4151 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
);
4152 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
);
4153 static BOOL
VARIANT_int_iszero(const DWORD
* p
, unsigned int n
);
4155 /************************************************************************
4156 * VarDecFromR4 (OLEAUT32.193)
4158 * Convert a VT_R4 to a DECIMAL.
4162 * pDecOut [O] Destination
4167 HRESULT WINAPI
VarDecFromR4(FLOAT fltIn
, DECIMAL
* pDecOut
)
4172 hres
= VARIANT_DI_FromR4(fltIn
, &di
);
4173 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4177 /************************************************************************
4178 * VarDecFromR8 (OLEAUT32.194)
4180 * Convert a VT_R8 to a DECIMAL.
4184 * pDecOut [O] Destination
4189 HRESULT WINAPI
VarDecFromR8(double dblIn
, DECIMAL
* pDecOut
)
4194 hres
= VARIANT_DI_FromR8(dblIn
, &di
);
4195 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4199 /************************************************************************
4200 * VarDecFromDate (OLEAUT32.195)
4202 * Convert a VT_DATE to a DECIMAL.
4206 * pDecOut [O] Destination
4211 HRESULT WINAPI
VarDecFromDate(DATE dateIn
, DECIMAL
* pDecOut
)
4213 return VarDecFromR8(dateIn
, pDecOut
);
4216 /************************************************************************
4217 * VarDecFromCy (OLEAUT32.196)
4219 * Convert a VT_CY to a DECIMAL.
4223 * pDecOut [O] Destination
4228 HRESULT WINAPI
VarDecFromCy(CY cyIn
, DECIMAL
* pDecOut
)
4230 DEC_HI32(pDecOut
) = 0;
4232 /* Note: This assumes 2s complement integer representation */
4233 if (cyIn
.s
.Hi
& 0x80000000)
4235 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,4);
4236 DEC_LO64(pDecOut
) = -cyIn
.int64
;
4240 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,4);
4241 DEC_MID32(pDecOut
) = cyIn
.s
.Hi
;
4242 DEC_LO32(pDecOut
) = cyIn
.s
.Lo
;
4247 /************************************************************************
4248 * VarDecFromStr (OLEAUT32.197)
4250 * Convert a VT_BSTR to a DECIMAL.
4254 * lcid [I] LCID for the conversion
4255 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4256 * pDecOut [O] Destination
4260 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4262 HRESULT WINAPI
VarDecFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DECIMAL
* pDecOut
)
4264 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDecOut
, VT_DECIMAL
);
4267 /************************************************************************
4268 * VarDecFromDisp (OLEAUT32.198)
4270 * Convert a VT_DISPATCH to a DECIMAL.
4273 * pdispIn [I] Source
4274 * lcid [I] LCID for conversion
4275 * pDecOut [O] Destination
4279 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4281 HRESULT WINAPI
VarDecFromDisp(IDispatch
* pdispIn
, LCID lcid
, DECIMAL
* pDecOut
)
4283 return VARIANT_FromDisp(pdispIn
, lcid
, pDecOut
, VT_DECIMAL
, 0);
4286 /************************************************************************
4287 * VarDecFromBool (OLEAUT32.199)
4289 * Convert a VT_BOOL to a DECIMAL.
4293 * pDecOut [O] Destination
4299 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4301 HRESULT WINAPI
VarDecFromBool(VARIANT_BOOL bIn
, DECIMAL
* pDecOut
)
4303 DEC_HI32(pDecOut
) = 0;
4304 DEC_MID32(pDecOut
) = 0;
4307 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4308 DEC_LO32(pDecOut
) = 1;
4312 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4313 DEC_LO32(pDecOut
) = 0;
4318 /************************************************************************
4319 * VarDecFromI1 (OLEAUT32.241)
4321 * Convert a VT_I1 to a DECIMAL.
4325 * pDecOut [O] Destination
4330 HRESULT WINAPI
VarDecFromI1(signed char cIn
, DECIMAL
* pDecOut
)
4332 return VarDecFromI4(cIn
, pDecOut
);
4335 /************************************************************************
4336 * VarDecFromUI2 (OLEAUT32.242)
4338 * Convert a VT_UI2 to a DECIMAL.
4342 * pDecOut [O] Destination
4347 HRESULT WINAPI
VarDecFromUI2(USHORT usIn
, DECIMAL
* pDecOut
)
4349 return VarDecFromUI4(usIn
, pDecOut
);
4352 /************************************************************************
4353 * VarDecFromUI4 (OLEAUT32.243)
4355 * Convert a VT_UI4 to a DECIMAL.
4359 * pDecOut [O] Destination
4364 HRESULT WINAPI
VarDecFromUI4(ULONG ulIn
, DECIMAL
* pDecOut
)
4366 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4367 DEC_HI32(pDecOut
) = 0;
4368 DEC_MID32(pDecOut
) = 0;
4369 DEC_LO32(pDecOut
) = ulIn
;
4373 /************************************************************************
4374 * VarDecFromI8 (OLEAUT32.374)
4376 * Convert a VT_I8 to a DECIMAL.
4380 * pDecOut [O] Destination
4385 HRESULT WINAPI
VarDecFromI8(LONG64 llIn
, DECIMAL
* pDecOut
)
4387 PULARGE_INTEGER pLi
= (PULARGE_INTEGER
)&llIn
;
4389 DEC_HI32(pDecOut
) = 0;
4391 /* Note: This assumes 2s complement integer representation */
4392 if (pLi
->u
.HighPart
& 0x80000000)
4394 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4395 DEC_LO64(pDecOut
) = -pLi
->QuadPart
;
4399 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4400 DEC_MID32(pDecOut
) = pLi
->u
.HighPart
;
4401 DEC_LO32(pDecOut
) = pLi
->u
.LowPart
;
4406 /************************************************************************
4407 * VarDecFromUI8 (OLEAUT32.375)
4409 * Convert a VT_UI8 to a DECIMAL.
4413 * pDecOut [O] Destination
4418 HRESULT WINAPI
VarDecFromUI8(ULONG64 ullIn
, DECIMAL
* pDecOut
)
4420 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4421 DEC_HI32(pDecOut
) = 0;
4422 DEC_LO64(pDecOut
) = ullIn
;
4426 /* Make two DECIMALS the same scale; used by math functions below */
4427 static HRESULT
VARIANT_DecScale(const DECIMAL
** ppDecLeft
,
4428 const DECIMAL
** ppDecRight
,
4431 static DECIMAL scaleFactor
;
4432 unsigned char remainder
;
4437 if (DEC_SIGN(*ppDecLeft
) & ~DECIMAL_NEG
|| DEC_SIGN(*ppDecRight
) & ~DECIMAL_NEG
)
4438 return E_INVALIDARG
;
4440 DEC_LO32(&scaleFactor
) = 10;
4442 i
= scaleAmount
= DEC_SCALE(*ppDecLeft
) - DEC_SCALE(*ppDecRight
);
4445 return S_OK
; /* Same scale */
4447 if (scaleAmount
> 0)
4449 decTemp
= *(*ppDecRight
); /* Left is bigger - scale the right hand side */
4450 *ppDecRight
= &pDecOut
[0];
4454 decTemp
= *(*ppDecLeft
); /* Right is bigger - scale the left hand side */
4455 *ppDecLeft
= &pDecOut
[0];
4459 /* Multiply up the value to be scaled by the correct amount (if possible) */
4460 while (i
> 0 && SUCCEEDED(VarDecMul(&decTemp
, &scaleFactor
, &pDecOut
[0])))
4462 decTemp
= pDecOut
[0];
4468 DEC_SCALE(&pDecOut
[0]) += (scaleAmount
> 0) ? scaleAmount
: (-scaleAmount
);
4469 return S_OK
; /* Same scale */
4472 /* Scaling further not possible, reduce accuracy of other argument */
4473 pDecOut
[0] = decTemp
;
4474 if (scaleAmount
> 0)
4476 DEC_SCALE(&pDecOut
[0]) += scaleAmount
- i
;
4477 VARIANT_DIFromDec(*ppDecLeft
, &di
);
4478 *ppDecLeft
= &pDecOut
[1];
4482 DEC_SCALE(&pDecOut
[0]) += (-scaleAmount
) - i
;
4483 VARIANT_DIFromDec(*ppDecRight
, &di
);
4484 *ppDecRight
= &pDecOut
[1];
4489 while (i
-- > 0 && !VARIANT_int_iszero(di
.bitsnum
, sizeof(di
.bitsnum
)/sizeof(DWORD
)))
4491 remainder
= VARIANT_int_divbychar(di
.bitsnum
, sizeof(di
.bitsnum
)/sizeof(DWORD
), 10);
4492 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4495 /* round up the result - native oleaut32 does this */
4496 if (remainder
>= 5) {
4497 for (remainder
= 1, i
= 0; i
< sizeof(di
.bitsnum
)/sizeof(DWORD
) && remainder
; i
++) {
4498 ULONGLONG digit
= di
.bitsnum
[i
] + 1;
4499 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4500 di
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
4504 VARIANT_DecFromDI(&di
, &pDecOut
[1]);
4508 /* Add two unsigned 32 bit values with overflow */
4509 static ULONG
VARIANT_Add(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4511 ULARGE_INTEGER ul64
;
4513 ul64
.QuadPart
= (ULONG64
)ulLeft
+ (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4514 *pulHigh
= ul64
.u
.HighPart
;
4515 return ul64
.u
.LowPart
;
4518 /* Subtract two unsigned 32 bit values with underflow */
4519 static ULONG
VARIANT_Sub(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4521 BOOL invert
= FALSE
;
4522 ULARGE_INTEGER ul64
;
4524 ul64
.QuadPart
= (LONG64
)ulLeft
- (ULONG64
)ulRight
;
4525 if (ulLeft
< ulRight
)
4528 if (ul64
.QuadPart
> (ULONG64
)*pulHigh
)
4529 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4532 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4536 ul64
.u
.HighPart
= -ul64
.u
.HighPart
;
4538 *pulHigh
= ul64
.u
.HighPart
;
4539 return ul64
.u
.LowPart
;
4542 /* Multiply two unsigned 32 bit values with overflow */
4543 static ULONG
VARIANT_Mul(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4545 ULARGE_INTEGER ul64
;
4547 ul64
.QuadPart
= (ULONG64
)ulLeft
* (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4548 *pulHigh
= ul64
.u
.HighPart
;
4549 return ul64
.u
.LowPart
;
4552 /* Compare two decimals that have the same scale */
4553 static inline int VARIANT_DecCmp(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
)
4555 if ( DEC_HI32(pDecLeft
) < DEC_HI32(pDecRight
) ||
4556 (DEC_HI32(pDecLeft
) <= DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) < DEC_LO64(pDecRight
)))
4558 else if (DEC_HI32(pDecLeft
) == DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) == DEC_LO64(pDecRight
))
4563 /************************************************************************
4564 * VarDecAdd (OLEAUT32.177)
4566 * Add one DECIMAL to another.
4569 * pDecLeft [I] Source
4570 * pDecRight [I] Value to add
4571 * pDecOut [O] Destination
4575 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4577 HRESULT WINAPI
VarDecAdd(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
4582 hRet
= VARIANT_DecScale(&pDecLeft
, &pDecRight
, scaled
);
4584 if (SUCCEEDED(hRet
))
4586 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4588 BYTE sign
= DECIMAL_POS
;
4591 /* Correct for the sign of the result */
4592 if (DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4594 /* -x + -y : Negative */
4596 goto VarDecAdd_AsPositive
;
4598 else if (DEC_SIGN(pDecLeft
) && !DEC_SIGN(pDecRight
))
4600 cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4602 /* -x + y : Negative if x > y */
4606 VarDecAdd_AsNegative
:
4607 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4608 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4609 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4613 VarDecAdd_AsInvertedNegative
:
4614 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecRight
), DEC_LO32(pDecLeft
), &overflow
);
4615 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecRight
), DEC_MID32(pDecLeft
), &overflow
);
4616 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecRight
), DEC_HI32(pDecLeft
), &overflow
);
4619 else if (!DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4621 cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4623 /* x + -y : Negative if x <= y */
4627 goto VarDecAdd_AsInvertedNegative
;
4629 goto VarDecAdd_AsNegative
;
4633 /* x + y : Positive */
4634 VarDecAdd_AsPositive
:
4635 DEC_LO32(pDecOut
) = VARIANT_Add(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4636 DEC_MID32(pDecOut
) = VARIANT_Add(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4637 DEC_HI32(pDecOut
) = VARIANT_Add(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4641 return DISP_E_OVERFLOW
; /* overflowed */
4643 DEC_SCALE(pDecOut
) = DEC_SCALE(pDecLeft
);
4644 DEC_SIGN(pDecOut
) = sign
;
4649 /* translate from external DECIMAL format into an internal representation */
4650 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
)
4652 to
->scale
= DEC_SCALE(from
);
4653 to
->sign
= DEC_SIGN(from
) ? 1 : 0;
4655 to
->bitsnum
[0] = DEC_LO32(from
);
4656 to
->bitsnum
[1] = DEC_MID32(from
);
4657 to
->bitsnum
[2] = DEC_HI32(from
);
4660 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
)
4663 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_NEG
, from
->scale
);
4665 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_POS
, from
->scale
);
4668 DEC_LO32(to
) = from
->bitsnum
[0];
4669 DEC_MID32(to
) = from
->bitsnum
[1];
4670 DEC_HI32(to
) = from
->bitsnum
[2];
4673 /* clear an internal representation of a DECIMAL */
4674 static void VARIANT_DI_clear(VARIANT_DI
* i
)
4676 memset(i
, 0, sizeof(VARIANT_DI
));
4679 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4680 size is supported. The value in p is replaced by the quotient of the division, and
4681 the remainder is returned as a result. This routine is most often used with a divisor
4682 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4684 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
)
4689 } else if (divisor
== 1) {
4690 /* dividend remains unchanged */
4693 unsigned char remainder
= 0;
4694 ULONGLONG iTempDividend
;
4697 for (i
= n
- 1; i
>= 0 && !p
[i
]; i
--); /* skip leading zeros */
4698 for (; i
>= 0; i
--) {
4699 iTempDividend
= ((ULONGLONG
)remainder
<< 32) + p
[i
];
4700 remainder
= iTempDividend
% divisor
;
4701 p
[i
] = iTempDividend
/ divisor
;
4708 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4709 static BOOL
VARIANT_int_iszero(const DWORD
* p
, unsigned int n
)
4711 for (; n
> 0; n
--) if (*p
++ != 0) return FALSE
;
4715 /* multiply two DECIMALS, without changing either one, and place result in third
4716 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4717 digits when scale > 0 in order to fit an overflowing result. Final overflow
4720 static int VARIANT_DI_mul(const VARIANT_DI
* a
, const VARIANT_DI
* b
, VARIANT_DI
* result
)
4722 BOOL r_overflow
= FALSE
;
4724 signed int mulstart
;
4726 VARIANT_DI_clear(result
);
4727 result
->sign
= (a
->sign
^ b
->sign
) ? 1 : 0;
4729 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4730 of the result is formed by adding the scales of the operands.
4732 result
->scale
= a
->scale
+ b
->scale
;
4733 memset(running
, 0, sizeof(running
));
4735 /* count number of leading zero-bytes in operand A */
4736 for (mulstart
= sizeof(a
->bitsnum
)/sizeof(DWORD
) - 1; mulstart
>= 0 && !a
->bitsnum
[mulstart
]; mulstart
--);
4738 /* result is 0, because operand A is 0 */
4742 unsigned char remainder
= 0;
4745 /* perform actual multiplication */
4746 for (iA
= 0; iA
<= mulstart
; iA
++) {
4750 for (iOverflowMul
= 0, iB
= 0; iB
< sizeof(b
->bitsnum
)/sizeof(DWORD
); iB
++) {
4754 iRV
= VARIANT_Mul(b
->bitsnum
[iB
], a
->bitsnum
[iA
], &iOverflowMul
);
4757 running
[iR
] = VARIANT_Add(running
[iR
], 0, &iRV
);
4763 /* Too bad - native oleaut does not do this, so we should not either */
4765 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4766 This operation should not lose significant digits, and gives an
4767 opportunity to reduce the possibility of overflows in future
4768 operations issued by the application.
4770 while (result
->scale
> 0) {
4771 memcpy(quotient
, running
, sizeof(quotient
));
4772 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4773 if (remainder
> 0) break;
4774 memcpy(running
, quotient
, sizeof(quotient
));
4778 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4779 This operation *will* lose significant digits of the result because
4780 all the factors of 10 were consumed by the previous operation.
4782 while (result
->scale
> 0 && !VARIANT_int_iszero(
4783 running
+ sizeof(result
->bitsnum
) / sizeof(DWORD
),
4784 (sizeof(running
) - sizeof(result
->bitsnum
)) / sizeof(DWORD
))) {
4786 remainder
= VARIANT_int_divbychar(running
, sizeof(running
) / sizeof(DWORD
), 10);
4787 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4791 /* round up the result - native oleaut32 does this */
4792 if (remainder
>= 5) {
4794 for (remainder
= 1, i
= 0; i
< sizeof(running
)/sizeof(DWORD
) && remainder
; i
++) {
4795 ULONGLONG digit
= running
[i
] + 1;
4796 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4797 running
[i
] = digit
& 0xFFFFFFFF;
4801 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4802 and copy result bits into result structure
4804 r_overflow
= !VARIANT_int_iszero(
4805 running
+ sizeof(result
->bitsnum
)/sizeof(DWORD
),
4806 (sizeof(running
) - sizeof(result
->bitsnum
))/sizeof(DWORD
));
4807 memcpy(result
->bitsnum
, running
, sizeof(result
->bitsnum
));
4812 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4813 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4814 success, FALSE if insufficient space in output buffer.
4816 static BOOL
VARIANT_DI_tostringW(const VARIANT_DI
* a
, WCHAR
* s
, unsigned int n
)
4818 BOOL overflow
= FALSE
;
4820 unsigned char remainder
;
4823 /* place negative sign */
4824 if (!VARIANT_int_iszero(a
->bitsnum
, sizeof(a
->bitsnum
) / sizeof(DWORD
)) && a
->sign
) {
4829 else overflow
= TRUE
;
4832 /* prepare initial 0 */
4837 } else overflow
= TRUE
;
4841 memcpy(quotient
, a
->bitsnum
, sizeof(a
->bitsnum
));
4842 while (!overflow
&& !VARIANT_int_iszero(quotient
, sizeof(quotient
) / sizeof(DWORD
))) {
4843 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4847 s
[i
++] = '0' + remainder
;
4852 if (!overflow
&& !VARIANT_int_iszero(a
->bitsnum
, sizeof(a
->bitsnum
) / sizeof(DWORD
))) {
4854 /* reverse order of digits */
4855 WCHAR
* x
= s
; WCHAR
* y
= s
+ i
- 1;
4862 /* check for decimal point. "i" now has string length */
4863 if (i
<= a
->scale
) {
4864 unsigned int numzeroes
= a
->scale
+ 1 - i
;
4865 if (i
+ 1 + numzeroes
>= n
) {
4868 memmove(s
+ numzeroes
, s
, (i
+ 1) * sizeof(WCHAR
));
4870 while (numzeroes
> 0) {
4871 s
[--numzeroes
] = '0';
4876 /* place decimal point */
4878 unsigned int periodpos
= i
- a
->scale
;
4882 memmove(s
+ periodpos
+ 1, s
+ periodpos
, (i
+ 1 - periodpos
) * sizeof(WCHAR
));
4883 s
[periodpos
] = '.'; i
++;
4885 /* remove extra zeros at the end, if any */
4886 while (s
[i
- 1] == '0') s
[--i
] = '\0';
4887 if (s
[i
- 1] == '.') s
[--i
] = '\0';
4895 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4896 static void VARIANT_int_shiftleft(DWORD
* p
, unsigned int n
, unsigned int shift
)
4901 /* shift whole DWORDs to the left */
4904 memmove(p
+ 1, p
, (n
- 1) * sizeof(DWORD
));
4905 *p
= 0; shift
-= 32;
4908 /* shift remainder (1..31 bits) */
4910 if (shift
> 0) for (i
= 0; i
< n
; i
++)
4913 b
= p
[i
] >> (32 - shift
);
4914 p
[i
] = (p
[i
] << shift
) | shifted
;
4919 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4920 Value at v is incremented by the value at p. Any size is supported, provided
4921 that v is not shorter than p. Any unapplied carry is returned as a result.
4923 static unsigned char VARIANT_int_add(DWORD
* v
, unsigned int nv
, const DWORD
* p
,
4926 unsigned char carry
= 0;
4932 for (i
= 0; i
< np
; i
++) {
4933 sum
= (ULONGLONG
)v
[i
]
4936 v
[i
] = sum
& 0xffffffff;
4939 for (; i
< nv
&& carry
; i
++) {
4940 sum
= (ULONGLONG
)v
[i
]
4942 v
[i
] = sum
& 0xffffffff;
4949 /* perform integral division with operand p as dividend. Parameter n indicates
4950 number of available DWORDs in divisor p, but available space in p must be
4951 actually at least 2 * n DWORDs, because the remainder of the integral
4952 division is built in the next n DWORDs past the start of the quotient. This
4953 routine replaces the dividend in p with the quotient, and appends n
4954 additional DWORDs for the remainder.
4956 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4957 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4958 source code to the VLI (Very Large Integer) division operator. This algorithm
4959 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4960 variably-scaled integers such as the MS DECIMAL representation.
4962 static void VARIANT_int_div(DWORD
* p
, unsigned int n
, const DWORD
* divisor
,
4967 DWORD
* negdivisor
= tempsub
+ n
;
4969 /* build 2s-complement of divisor */
4970 for (i
= 0; i
< n
; i
++) negdivisor
[i
] = (i
< dn
) ? ~divisor
[i
] : 0xFFFFFFFF;
4972 VARIANT_int_add(negdivisor
, n
, p
+ n
, 1);
4973 memset(p
+ n
, 0, n
* sizeof(DWORD
));
4975 /* skip all leading zero DWORDs in quotient */
4976 for (i
= 0; i
< n
&& !p
[n
- 1]; i
++) VARIANT_int_shiftleft(p
, n
, 32);
4977 /* i is now number of DWORDs left to process */
4978 for (i
<<= 5; i
< (n
<< 5); i
++) {
4979 VARIANT_int_shiftleft(p
, n
<< 1, 1); /* shl quotient+remainder */
4981 /* trial subtraction */
4982 memcpy(tempsub
, p
+ n
, n
* sizeof(DWORD
));
4983 VARIANT_int_add(tempsub
, n
, negdivisor
, n
);
4985 /* check whether result of subtraction was negative */
4986 if ((tempsub
[n
- 1] & 0x80000000) == 0) {
4987 memcpy(p
+ n
, tempsub
, n
* sizeof(DWORD
));
4993 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4994 static unsigned char VARIANT_int_mulbychar(DWORD
* p
, unsigned int n
, unsigned char m
)
4999 for (iOverflowMul
= 0, i
= 0; i
< n
; i
++)
5000 p
[i
] = VARIANT_Mul(p
[i
], m
, &iOverflowMul
);
5001 return (unsigned char)iOverflowMul
;
5004 /* increment value in A by the value indicated in B, with scale adjusting.
5005 Modifies parameters by adjusting scales. Returns 0 if addition was
5006 successful, nonzero if a parameter underflowed before it could be
5007 successfully used in the addition.
5009 static int VARIANT_int_addlossy(
5010 DWORD
* a
, int * ascale
, unsigned int an
,
5011 DWORD
* b
, int * bscale
, unsigned int bn
)
5015 if (VARIANT_int_iszero(a
, an
)) {
5016 /* if A is zero, copy B into A, after removing digits */
5017 while (bn
> an
&& !VARIANT_int_iszero(b
+ an
, bn
- an
)) {
5018 VARIANT_int_divbychar(b
, bn
, 10);
5021 memcpy(a
, b
, an
* sizeof(DWORD
));
5023 } else if (!VARIANT_int_iszero(b
, bn
)) {
5024 unsigned int tn
= an
+ 1;
5027 if (bn
+ 1 > tn
) tn
= bn
+ 1;
5028 if (*ascale
!= *bscale
) {
5029 /* first (optimistic) try - try to scale down the one with the bigger
5030 scale, while this number is divisible by 10 */
5031 DWORD
* digitchosen
;
5032 unsigned int nchosen
;
5036 if (*ascale
< *bscale
) {
5037 targetscale
= *ascale
;
5038 scalechosen
= bscale
;
5042 targetscale
= *bscale
;
5043 scalechosen
= ascale
;
5047 memset(t
, 0, tn
* sizeof(DWORD
));
5048 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5050 /* divide by 10 until target scale is reached */
5051 while (*scalechosen
> targetscale
) {
5052 unsigned char remainder
= VARIANT_int_divbychar(t
, tn
, 10);
5055 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5060 if (*ascale
!= *bscale
) {
5061 DWORD
* digitchosen
;
5062 unsigned int nchosen
;
5066 /* try to scale up the one with the smaller scale */
5067 if (*ascale
> *bscale
) {
5068 targetscale
= *ascale
;
5069 scalechosen
= bscale
;
5073 targetscale
= *bscale
;
5074 scalechosen
= ascale
;
5078 memset(t
, 0, tn
* sizeof(DWORD
));
5079 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5081 /* multiply by 10 until target scale is reached, or
5082 significant bytes overflow the number
5084 while (*scalechosen
< targetscale
&& t
[nchosen
] == 0) {
5085 VARIANT_int_mulbychar(t
, tn
, 10);
5086 if (t
[nchosen
] == 0) {
5087 /* still does not overflow */
5089 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5094 if (*ascale
!= *bscale
) {
5095 /* still different? try to scale down the one with the bigger scale
5096 (this *will* lose significant digits) */
5097 DWORD
* digitchosen
;
5098 unsigned int nchosen
;
5102 if (*ascale
< *bscale
) {
5103 targetscale
= *ascale
;
5104 scalechosen
= bscale
;
5108 targetscale
= *bscale
;
5109 scalechosen
= ascale
;
5113 memset(t
, 0, tn
* sizeof(DWORD
));
5114 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5116 /* divide by 10 until target scale is reached */
5117 while (*scalechosen
> targetscale
) {
5118 VARIANT_int_divbychar(t
, tn
, 10);
5120 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5124 /* check whether any of the operands still has significant digits
5127 if (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
)) {
5130 /* at this step, both numbers have the same scale and can be added
5131 as integers. However, the result might not fit in A, so further
5132 scaling down might be necessary.
5134 while (!underflow
) {
5135 memset(t
, 0, tn
* sizeof(DWORD
));
5136 memcpy(t
, a
, an
* sizeof(DWORD
));
5138 VARIANT_int_add(t
, tn
, b
, bn
);
5139 if (VARIANT_int_iszero(t
+ an
, tn
- an
)) {
5140 /* addition was successful */
5141 memcpy(a
, t
, an
* sizeof(DWORD
));
5144 /* addition overflowed - remove significant digits
5145 from both operands and try again */
5146 VARIANT_int_divbychar(a
, an
, 10); (*ascale
)--;
5147 VARIANT_int_divbychar(b
, bn
, 10); (*bscale
)--;
5148 /* check whether any operand keeps significant digits after
5149 scaledown (underflow case 2)
5151 underflow
= (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
));
5159 /* perform complete DECIMAL division in the internal representation. Returns
5160 0 if the division was completed (even if quotient is set to 0), or nonzero
5161 in case of quotient overflow.
5163 static HRESULT
VARIANT_DI_div(const VARIANT_DI
* dividend
, const VARIANT_DI
* divisor
,
5164 VARIANT_DI
* quotient
, BOOL round_remainder
)
5166 HRESULT r_overflow
= S_OK
;
5168 if (VARIANT_int_iszero(divisor
->bitsnum
, sizeof(divisor
->bitsnum
)/sizeof(DWORD
))) {
5170 r_overflow
= DISP_E_DIVBYZERO
;
5171 } else if (VARIANT_int_iszero(dividend
->bitsnum
, sizeof(dividend
->bitsnum
)/sizeof(DWORD
))) {
5172 VARIANT_DI_clear(quotient
);
5174 int quotientscale
, remainderscale
, tempquotientscale
;
5175 DWORD remainderplusquotient
[8];
5178 quotientscale
= remainderscale
= (int)dividend
->scale
- (int)divisor
->scale
;
5179 tempquotientscale
= quotientscale
;
5180 VARIANT_DI_clear(quotient
);
5181 quotient
->sign
= (dividend
->sign
^ divisor
->sign
) ? 1 : 0;
5183 /* The following strategy is used for division
5184 1) if there was a nonzero remainder from previous iteration, use it as
5185 dividend for this iteration, else (for first iteration) use intended
5187 2) perform integer division in temporary buffer, develop quotient in
5188 low-order part, remainder in high-order part
5189 3) add quotient from step 2 to final result, with possible loss of
5191 4) multiply integer part of remainder by 10, while incrementing the
5192 scale of the remainder. This operation preserves the intended value
5194 5) loop to step 1 until one of the following is true:
5195 a) remainder is zero (exact division achieved)
5196 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5198 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5199 memcpy(remainderplusquotient
, dividend
->bitsnum
, sizeof(dividend
->bitsnum
));
5202 remainderplusquotient
, 4,
5203 divisor
->bitsnum
, sizeof(divisor
->bitsnum
)/sizeof(DWORD
));
5204 underflow
= VARIANT_int_addlossy(
5205 quotient
->bitsnum
, "ientscale
, sizeof(quotient
->bitsnum
) / sizeof(DWORD
),
5206 remainderplusquotient
, &tempquotientscale
, 4);
5207 if (round_remainder
) {
5208 if(remainderplusquotient
[4] >= 5){
5210 unsigned char remainder
= 1;
5211 for (i
= 0; i
< sizeof(quotient
->bitsnum
) / sizeof(DWORD
) && remainder
; i
++) {
5212 ULONGLONG digit
= quotient
->bitsnum
[i
] + 1;
5213 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5214 quotient
->bitsnum
[i
] = digit
& 0xFFFFFFFF;
5217 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5219 VARIANT_int_mulbychar(remainderplusquotient
+ 4, 4, 10);
5220 memcpy(remainderplusquotient
, remainderplusquotient
+ 4, 4 * sizeof(DWORD
));
5222 tempquotientscale
= ++remainderscale
;
5223 } while (!underflow
&& !VARIANT_int_iszero(remainderplusquotient
+ 4, 4));
5225 /* quotient scale might now be negative (extremely big number). If, so, try
5226 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5227 until scale is 0. If this cannot be done, it is a real overflow.
5229 while (r_overflow
== S_OK
&& quotientscale
< 0) {
5230 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5231 memcpy(remainderplusquotient
, quotient
->bitsnum
, sizeof(quotient
->bitsnum
));
5232 VARIANT_int_mulbychar(remainderplusquotient
, sizeof(remainderplusquotient
)/sizeof(DWORD
), 10);
5233 if (VARIANT_int_iszero(remainderplusquotient
+ sizeof(quotient
->bitsnum
)/sizeof(DWORD
),
5234 (sizeof(remainderplusquotient
) - sizeof(quotient
->bitsnum
))/sizeof(DWORD
))) {
5236 memcpy(quotient
->bitsnum
, remainderplusquotient
, sizeof(quotient
->bitsnum
));
5237 } else r_overflow
= DISP_E_OVERFLOW
;
5239 if (r_overflow
== S_OK
) {
5240 if (quotientscale
<= 255) quotient
->scale
= quotientscale
;
5241 else VARIANT_DI_clear(quotient
);
5247 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5248 with an undefined scale, which will be assigned to (if possible). It also
5249 receives an exponent of 2. This procedure will then manipulate the mantissa
5250 and calculate a corresponding scale, so that the exponent2 value is assimilated
5251 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5252 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5254 static HRESULT
VARIANT_DI_normalize(VARIANT_DI
* val
, int exponent2
, BOOL isDouble
)
5256 HRESULT hres
= S_OK
;
5257 int exponent5
, exponent10
;
5259 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5260 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5261 exponent10 might be used to set the VARIANT_DI scale directly. However,
5262 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5263 exponent5
= -exponent2
;
5264 exponent10
= exponent2
;
5266 /* Handle exponent5 > 0 */
5267 while (exponent5
> 0) {
5271 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5272 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5273 somehow the mantissa should be divided by 2. */
5274 if ((val
->bitsnum
[0] & 1) == 0) {
5275 /* The mantissa is divisible by 2. Therefore the division can be done
5276 without losing significant digits. */
5277 exponent10
++; exponent5
--;
5280 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5281 val
->bitsnum
[2] >>= 1;
5282 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5283 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5284 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5286 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5287 be multiplied by 5, unless the multiplication overflows. */
5288 DWORD temp_bitsnum
[3];
5292 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5293 if (0 == VARIANT_int_mulbychar(temp_bitsnum
, 3, 5)) {
5294 /* Multiplication succeeded without overflow, so copy result back
5296 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5298 /* Mask out 3 extraneous bits introduced by the multiply */
5300 /* Multiplication by 5 overflows. The mantissa should be divided
5301 by 2, and therefore will lose significant digits. */
5305 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5306 val
->bitsnum
[2] >>= 1;
5307 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5308 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5309 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5314 /* Handle exponent5 < 0 */
5315 while (exponent5
< 0) {
5316 /* In order to divide the value represented by the VARIANT_DI by 5, it
5317 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5318 and the mantissa should be multiplied by 2 */
5319 if ((val
->bitsnum
[2] & 0x80000000) == 0) {
5320 /* The mantissa can withstand a shift-left without overflowing */
5321 exponent10
--; exponent5
++;
5322 VARIANT_int_shiftleft(val
->bitsnum
, 3, 1);
5324 /* The mantissa would overflow if shifted. Therefore it should be
5325 directly divided by 5. This will lose significant digits, unless
5326 by chance the mantissa happens to be divisible by 5 */
5328 VARIANT_int_divbychar(val
->bitsnum
, 3, 5);
5332 /* At this point, the mantissa has assimilated the exponent5, but the
5333 exponent10 might not be suitable for assignment. The exponent10 must be
5334 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5335 down appropriately. */
5336 while (hres
== S_OK
&& exponent10
> 0) {
5337 /* In order to bring exponent10 down to 0, the mantissa should be
5338 multiplied by 10 to compensate. If the exponent10 is too big, this
5339 will cause the mantissa to overflow. */
5340 if (0 == VARIANT_int_mulbychar(val
->bitsnum
, 3, 10)) {
5343 hres
= DISP_E_OVERFLOW
;
5346 while (exponent10
< -DEC_MAX_SCALE
) {
5348 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5349 be divided by 10 to compensate. If the exponent10 is too small, this
5350 will cause the mantissa to underflow and become 0 */
5351 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5353 if (VARIANT_int_iszero(val
->bitsnum
, 3)) {
5354 /* Underflow, unable to keep dividing */
5356 } else if (rem10
>= 5) {
5358 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5361 /* This step is required in order to remove excess bits of precision from the
5362 end of the bit representation, down to the precision guaranteed by the
5363 floating point number. */
5365 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || (val
->bitsnum
[1] & 0xFFE00000) != 0)) {
5368 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5372 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5376 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || val
->bitsnum
[1] != 0 ||
5377 (val
->bitsnum
[2] == 0 && val
->bitsnum
[1] == 0 && (val
->bitsnum
[0] & 0xFF000000) != 0))) {
5380 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5384 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5388 /* Remove multiples of 10 from the representation */
5389 while (exponent10
< 0) {
5390 DWORD temp_bitsnum
[3];
5392 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5393 if (0 == VARIANT_int_divbychar(temp_bitsnum
, 3, 10)) {
5395 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5399 /* Scale assignment */
5400 if (hres
== S_OK
) val
->scale
= -exponent10
;
5409 unsigned int m
: 23;
5410 unsigned int exp_bias
: 8;
5411 unsigned int sign
: 1;
5416 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5417 intermediate string step. */
5418 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
)
5420 HRESULT hres
= S_OK
;
5425 /* Detect special cases */
5426 if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0) {
5427 /* Floating-point zero */
5428 VARIANT_DI_clear(dest
);
5429 } else if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0xFF) {
5430 /* Floating-point infinity */
5431 hres
= DISP_E_OVERFLOW
;
5432 } else if (fx
.i
.exp_bias
== 0xFF) {
5433 /* Floating-point NaN */
5434 hres
= DISP_E_BADVARTYPE
;
5437 VARIANT_DI_clear(dest
);
5439 exponent2
= fx
.i
.exp_bias
- 127; /* Get unbiased exponent */
5440 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5442 /* Copy significant bits to VARIANT_DI mantissa */
5443 dest
->bitsnum
[0] = fx
.i
.m
;
5444 dest
->bitsnum
[0] &= 0x007FFFFF;
5445 if (fx
.i
.exp_bias
== 0) {
5446 /* Denormalized number - correct exponent */
5449 /* Add hidden bit to mantissa */
5450 dest
->bitsnum
[0] |= 0x00800000;
5453 /* The act of copying a FP mantissa as integer bits is equivalent to
5454 shifting left the mantissa 23 bits. The exponent2 is reduced to
5458 hres
= VARIANT_DI_normalize(dest
, exponent2
, FALSE
);
5468 unsigned int m_lo
: 32; /* 52 bits of precision */
5469 unsigned int m_hi
: 20;
5470 unsigned int exp_bias
: 11; /* bias == 1023 */
5471 unsigned int sign
: 1;
5476 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5477 intermediate string step. */
5478 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
)
5480 HRESULT hres
= S_OK
;
5485 /* Detect special cases */
5486 if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0) {
5487 /* Floating-point zero */
5488 VARIANT_DI_clear(dest
);
5489 } else if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0x7FF) {
5490 /* Floating-point infinity */
5491 hres
= DISP_E_OVERFLOW
;
5492 } else if (fx
.i
.exp_bias
== 0x7FF) {
5493 /* Floating-point NaN */
5494 hres
= DISP_E_BADVARTYPE
;
5497 VARIANT_DI_clear(dest
);
5499 exponent2
= fx
.i
.exp_bias
- 1023; /* Get unbiased exponent */
5500 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5502 /* Copy significant bits to VARIANT_DI mantissa */
5503 dest
->bitsnum
[0] = fx
.i
.m_lo
;
5504 dest
->bitsnum
[1] = fx
.i
.m_hi
;
5505 dest
->bitsnum
[1] &= 0x000FFFFF;
5506 if (fx
.i
.exp_bias
== 0) {
5507 /* Denormalized number - correct exponent */
5510 /* Add hidden bit to mantissa */
5511 dest
->bitsnum
[1] |= 0x00100000;
5514 /* The act of copying a FP mantissa as integer bits is equivalent to
5515 shifting left the mantissa 52 bits. The exponent2 is reduced to
5519 hres
= VARIANT_DI_normalize(dest
, exponent2
, TRUE
);
5525 static HRESULT
VARIANT_do_division(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
, DECIMAL
*pDecOut
,
5528 HRESULT hRet
= S_OK
;
5529 VARIANT_DI di_left
, di_right
, di_result
;
5532 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5533 VARIANT_DIFromDec(pDecRight
, &di_right
);
5534 divresult
= VARIANT_DI_div(&di_left
, &di_right
, &di_result
, round
);
5535 if (divresult
!= S_OK
)
5537 /* division actually overflowed */
5544 if (di_result
.scale
> DEC_MAX_SCALE
)
5546 unsigned char remainder
= 0;
5548 /* division underflowed. In order to comply with the MSDN
5549 specifications for DECIMAL ranges, some significant digits
5552 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5554 while (di_result
.scale
> DEC_MAX_SCALE
&&
5555 !VARIANT_int_iszero(di_result
.bitsnum
, sizeof(di_result
.bitsnum
) / sizeof(DWORD
)))
5557 remainder
= VARIANT_int_divbychar(di_result
.bitsnum
, sizeof(di_result
.bitsnum
) / sizeof(DWORD
), 10);
5560 if (di_result
.scale
> DEC_MAX_SCALE
)
5562 WARN("result underflowed, setting to 0\n");
5563 di_result
.scale
= 0;
5566 else if (remainder
>= 5) /* round up result - native oleaut32 does this */
5569 for (remainder
= 1, i
= 0; i
< sizeof(di_result
.bitsnum
) / sizeof(DWORD
) && remainder
; i
++) {
5570 ULONGLONG digit
= di_result
.bitsnum
[i
] + 1;
5571 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5572 di_result
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
5576 VARIANT_DecFromDI(&di_result
, pDecOut
);
5581 /************************************************************************
5582 * VarDecDiv (OLEAUT32.178)
5584 * Divide one DECIMAL by another.
5587 * pDecLeft [I] Source
5588 * pDecRight [I] Value to divide by
5589 * pDecOut [O] Destination
5593 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5595 HRESULT WINAPI
VarDecDiv(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5597 if (!pDecLeft
|| !pDecRight
|| !pDecOut
) return E_INVALIDARG
;
5599 return VARIANT_do_division(pDecLeft
, pDecRight
, pDecOut
, FALSE
);
5602 /************************************************************************
5603 * VarDecMul (OLEAUT32.179)
5605 * Multiply one DECIMAL by another.
5608 * pDecLeft [I] Source
5609 * pDecRight [I] Value to multiply by
5610 * pDecOut [O] Destination
5614 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5616 HRESULT WINAPI
VarDecMul(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5618 HRESULT hRet
= S_OK
;
5619 VARIANT_DI di_left
, di_right
, di_result
;
5622 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5623 VARIANT_DIFromDec(pDecRight
, &di_right
);
5624 mulresult
= VARIANT_DI_mul(&di_left
, &di_right
, &di_result
);
5627 /* multiplication actually overflowed */
5628 hRet
= DISP_E_OVERFLOW
;
5632 if (di_result
.scale
> DEC_MAX_SCALE
)
5634 /* multiplication underflowed. In order to comply with the MSDN
5635 specifications for DECIMAL ranges, some significant digits
5638 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5640 while (di_result
.scale
> DEC_MAX_SCALE
&&
5641 !VARIANT_int_iszero(di_result
.bitsnum
, sizeof(di_result
.bitsnum
)/sizeof(DWORD
)))
5643 VARIANT_int_divbychar(di_result
.bitsnum
, sizeof(di_result
.bitsnum
)/sizeof(DWORD
), 10);
5646 if (di_result
.scale
> DEC_MAX_SCALE
)
5648 WARN("result underflowed, setting to 0\n");
5649 di_result
.scale
= 0;
5653 VARIANT_DecFromDI(&di_result
, pDecOut
);
5658 /************************************************************************
5659 * VarDecSub (OLEAUT32.181)
5661 * Subtract one DECIMAL from another.
5664 * pDecLeft [I] Source
5665 * pDecRight [I] DECIMAL to subtract from pDecLeft
5666 * pDecOut [O] Destination
5669 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5671 HRESULT WINAPI
VarDecSub(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5675 /* Implement as addition of the negative */
5676 VarDecNeg(pDecRight
, &decRight
);
5677 return VarDecAdd(pDecLeft
, &decRight
, pDecOut
);
5680 /************************************************************************
5681 * VarDecAbs (OLEAUT32.182)
5683 * Convert a DECIMAL into its absolute value.
5687 * pDecOut [O] Destination
5690 * S_OK. This function does not fail.
5692 HRESULT WINAPI
VarDecAbs(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5695 DEC_SIGN(pDecOut
) &= ~DECIMAL_NEG
;
5699 /************************************************************************
5700 * VarDecFix (OLEAUT32.187)
5702 * Return the integer portion of a DECIMAL.
5706 * pDecOut [O] Destination
5710 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5713 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5714 * negative numbers away from 0, while this function rounds them towards zero.
5716 HRESULT WINAPI
VarDecFix(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5721 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5722 return E_INVALIDARG
;
5724 if (!DEC_SCALE(pDecIn
))
5726 *pDecOut
= *pDecIn
; /* Already an integer */
5730 hr
= VarR8FromDec(pDecIn
, &dbl
);
5731 if (SUCCEEDED(hr
)) {
5732 LONGLONG rounded
= dbl
;
5734 hr
= VarDecFromI8(rounded
, pDecOut
);
5739 /************************************************************************
5740 * VarDecInt (OLEAUT32.188)
5742 * Return the integer portion of a DECIMAL.
5746 * pDecOut [O] Destination
5750 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5753 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5754 * negative numbers towards 0, while this function rounds them away from zero.
5756 HRESULT WINAPI
VarDecInt(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5761 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5762 return E_INVALIDARG
;
5764 if (!(DEC_SIGN(pDecIn
) & DECIMAL_NEG
) || !DEC_SCALE(pDecIn
))
5765 return VarDecFix(pDecIn
, pDecOut
); /* The same, if +ve or no fractionals */
5767 hr
= VarR8FromDec(pDecIn
, &dbl
);
5768 if (SUCCEEDED(hr
)) {
5769 LONGLONG rounded
= dbl
>= 0.0 ? dbl
+ 0.5 : dbl
- 0.5;
5771 hr
= VarDecFromI8(rounded
, pDecOut
);
5776 /************************************************************************
5777 * VarDecNeg (OLEAUT32.189)
5779 * Change the sign of a DECIMAL.
5783 * pDecOut [O] Destination
5786 * S_OK. This function does not fail.
5788 HRESULT WINAPI
VarDecNeg(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5791 DEC_SIGN(pDecOut
) ^= DECIMAL_NEG
;
5795 /************************************************************************
5796 * VarDecRound (OLEAUT32.203)
5798 * Change the precision of a DECIMAL.
5802 * cDecimals [I] New number of decimals to keep
5803 * pDecOut [O] Destination
5806 * Success: S_OK. pDecOut contains the rounded value.
5807 * Failure: E_INVALIDARG if any argument is invalid.
5809 HRESULT WINAPI
VarDecRound(const DECIMAL
* pDecIn
, int cDecimals
, DECIMAL
* pDecOut
)
5811 DECIMAL divisor
, tmp
;
5815 if (cDecimals
< 0 || (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
) || DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
)
5816 return E_INVALIDARG
;
5818 if (cDecimals
>= DEC_SCALE(pDecIn
))
5820 *pDecOut
= *pDecIn
; /* More precision than we have */
5824 /* truncate significant digits and rescale */
5825 memset(&divisor
, 0, sizeof(divisor
));
5826 DEC_LO64(&divisor
) = 1;
5828 memset(&tmp
, 0, sizeof(tmp
));
5829 DEC_LO64(&tmp
) = 10;
5830 for (i
= 0; i
< DEC_SCALE(pDecIn
) - cDecimals
; ++i
)
5832 hr
= VarDecMul(&divisor
, &tmp
, &divisor
);
5837 hr
= VARIANT_do_division(pDecIn
, &divisor
, pDecOut
, TRUE
);
5841 DEC_SCALE(pDecOut
) = cDecimals
;
5846 /************************************************************************
5847 * VarDecCmp (OLEAUT32.204)
5849 * Compare two DECIMAL values.
5852 * pDecLeft [I] Source
5853 * pDecRight [I] Value to compare
5856 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5857 * is less than, equal to or greater than pDecRight respectively.
5858 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5860 HRESULT WINAPI
VarDecCmp(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
)
5865 if (!pDecLeft
|| !pDecRight
)
5868 if ((!(DEC_SIGN(pDecLeft
) & DECIMAL_NEG
)) && (DEC_SIGN(pDecRight
) & DECIMAL_NEG
) &&
5869 (DEC_HI32(pDecLeft
) | DEC_MID32(pDecLeft
) | DEC_LO32(pDecLeft
)))
5871 else if ((DEC_SIGN(pDecLeft
) & DECIMAL_NEG
) && (!(DEC_SIGN(pDecRight
) & DECIMAL_NEG
)) &&
5872 (DEC_HI32(pDecLeft
) | DEC_MID32(pDecLeft
) | DEC_LO32(pDecLeft
)))
5875 /* Subtract right from left, and compare the result to 0 */
5876 hRet
= VarDecSub(pDecLeft
, pDecRight
, &result
);
5878 if (SUCCEEDED(hRet
))
5880 int non_zero
= DEC_HI32(&result
) | DEC_MID32(&result
) | DEC_LO32(&result
);
5882 if ((DEC_SIGN(&result
) & DECIMAL_NEG
) && non_zero
)
5883 hRet
= (HRESULT
)VARCMP_LT
;
5885 hRet
= (HRESULT
)VARCMP_GT
;
5887 hRet
= (HRESULT
)VARCMP_EQ
;
5892 /************************************************************************
5893 * VarDecCmpR8 (OLEAUT32.298)
5895 * Compare a DECIMAL to a double
5898 * pDecLeft [I] DECIMAL Source
5899 * dblRight [I] double to compare to pDecLeft
5902 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5903 * is less than, equal to or greater than pDecLeft respectively.
5904 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5906 HRESULT WINAPI
VarDecCmpR8(const DECIMAL
* pDecLeft
, double dblRight
)
5911 hRet
= VarDecFromR8(dblRight
, &decRight
);
5913 if (SUCCEEDED(hRet
))
5914 hRet
= VarDecCmp(pDecLeft
, &decRight
);
5922 /************************************************************************
5923 * VarBoolFromUI1 (OLEAUT32.118)
5925 * Convert a VT_UI1 to a VT_BOOL.
5929 * pBoolOut [O] Destination
5934 HRESULT WINAPI
VarBoolFromUI1(BYTE bIn
, VARIANT_BOOL
*pBoolOut
)
5936 *pBoolOut
= bIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5940 /************************************************************************
5941 * VarBoolFromI2 (OLEAUT32.119)
5943 * Convert a VT_I2 to a VT_BOOL.
5947 * pBoolOut [O] Destination
5952 HRESULT WINAPI
VarBoolFromI2(SHORT sIn
, VARIANT_BOOL
*pBoolOut
)
5954 *pBoolOut
= sIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5958 /************************************************************************
5959 * VarBoolFromI4 (OLEAUT32.120)
5961 * Convert a VT_I4 to a VT_BOOL.
5965 * pBoolOut [O] Destination
5970 HRESULT WINAPI
VarBoolFromI4(LONG lIn
, VARIANT_BOOL
*pBoolOut
)
5972 *pBoolOut
= lIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5976 /************************************************************************
5977 * VarBoolFromR4 (OLEAUT32.121)
5979 * Convert a VT_R4 to a VT_BOOL.
5983 * pBoolOut [O] Destination
5988 HRESULT WINAPI
VarBoolFromR4(FLOAT fltIn
, VARIANT_BOOL
*pBoolOut
)
5990 *pBoolOut
= fltIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5994 /************************************************************************
5995 * VarBoolFromR8 (OLEAUT32.122)
5997 * Convert a VT_R8 to a VT_BOOL.
6001 * pBoolOut [O] Destination
6006 HRESULT WINAPI
VarBoolFromR8(double dblIn
, VARIANT_BOOL
*pBoolOut
)
6008 *pBoolOut
= dblIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6012 /************************************************************************
6013 * VarBoolFromDate (OLEAUT32.123)
6015 * Convert a VT_DATE to a VT_BOOL.
6019 * pBoolOut [O] Destination
6024 HRESULT WINAPI
VarBoolFromDate(DATE dateIn
, VARIANT_BOOL
*pBoolOut
)
6026 *pBoolOut
= dateIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6030 /************************************************************************
6031 * VarBoolFromCy (OLEAUT32.124)
6033 * Convert a VT_CY to a VT_BOOL.
6037 * pBoolOut [O] Destination
6042 HRESULT WINAPI
VarBoolFromCy(CY cyIn
, VARIANT_BOOL
*pBoolOut
)
6044 *pBoolOut
= cyIn
.int64
? VARIANT_TRUE
: VARIANT_FALSE
;
6048 /************************************************************************
6049 * VARIANT_GetLocalisedText [internal]
6051 * Get a localized string from the resources
6054 static BOOL
VARIANT_GetLocalisedText(LANGID langId
, DWORD dwId
, WCHAR
*lpszDest
)
6058 hrsrc
= FindResourceExW( hProxyDll
, (LPWSTR
)RT_STRING
,
6059 MAKEINTRESOURCEW((dwId
>> 4) + 1), langId
);
6062 HGLOBAL hmem
= LoadResource( hProxyDll
, hrsrc
);
6069 p
= LockResource( hmem
);
6070 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
6072 memcpy( lpszDest
, p
+ 1, *p
* sizeof(WCHAR
) );
6073 lpszDest
[*p
] = '\0';
6074 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest
), langId
);
6081 /************************************************************************
6082 * VarBoolFromStr (OLEAUT32.125)
6084 * Convert a VT_BSTR to a VT_BOOL.
6088 * lcid [I] LCID for the conversion
6089 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6090 * pBoolOut [O] Destination
6094 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6095 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6098 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6099 * it may contain (in any case mapping) the text "true" or "false".
6100 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6101 * localised text of "True" or "False" in the language specified by lcid.
6102 * - If none of these matches occur, the string is treated as a numeric string
6103 * and the boolean pBoolOut will be set according to whether the number is zero
6104 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6105 * - If the text is not numeric and does not match any of the above, then
6106 * DISP_E_TYPEMISMATCH is returned.
6108 HRESULT WINAPI
VarBoolFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, VARIANT_BOOL
*pBoolOut
)
6110 /* Any VB/VBA programmers out there should recognise these strings... */
6111 static const WCHAR szFalse
[] = { '#','F','A','L','S','E','#','\0' };
6112 static const WCHAR szTrue
[] = { '#','T','R','U','E','#','\0' };
6114 LANGID langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6115 HRESULT hRes
= S_OK
;
6117 if (!strIn
|| !pBoolOut
)
6118 return DISP_E_TYPEMISMATCH
;
6120 /* Check if we should be comparing against localised text */
6121 if (dwFlags
& VAR_LOCALBOOL
)
6123 /* Convert our LCID into a usable value */
6124 lcid
= ConvertDefaultLocale(lcid
);
6126 langId
= LANGIDFROMLCID(lcid
);
6128 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6129 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6131 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6132 * I don't think this is needed unless any of the localised text strings
6133 * contain characters that can be so mapped. In the event that this is
6134 * true for a given language (possibly some Asian languages), then strIn
6135 * should be mapped here _only_ if langId is an Id for which this can occur.
6139 /* Note that if we are not comparing against localised strings, langId
6140 * will have its default value of LANG_ENGLISH. This allows us to mimic
6141 * the native behaviour of always checking against English strings even
6142 * after we've checked for localised ones.
6144 VarBoolFromStr_CheckLocalised
:
6145 if (VARIANT_GetLocalisedText(langId
, IDS_TRUE
, szBuff
))
6147 /* Compare against localised strings, ignoring case */
6148 if (!strcmpiW(strIn
, szBuff
))
6150 *pBoolOut
= VARIANT_TRUE
; /* Matched localised 'true' text */
6153 VARIANT_GetLocalisedText(langId
, IDS_FALSE
, szBuff
);
6154 if (!strcmpiW(strIn
, szBuff
))
6156 *pBoolOut
= VARIANT_FALSE
; /* Matched localised 'false' text */
6161 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6163 /* We have checked the localised text, now check English */
6164 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6165 goto VarBoolFromStr_CheckLocalised
;
6168 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6169 if (!strcmpW(strIn
, szFalse
))
6170 *pBoolOut
= VARIANT_FALSE
;
6171 else if (!strcmpW(strIn
, szTrue
))
6172 *pBoolOut
= VARIANT_TRUE
;
6177 /* If this string is a number, convert it as one */
6178 hRes
= VarR8FromStr(strIn
, lcid
, dwFlags
, &d
);
6179 if (SUCCEEDED(hRes
)) *pBoolOut
= d
? VARIANT_TRUE
: VARIANT_FALSE
;
6184 /************************************************************************
6185 * VarBoolFromDisp (OLEAUT32.126)
6187 * Convert a VT_DISPATCH to a VT_BOOL.
6190 * pdispIn [I] Source
6191 * lcid [I] LCID for conversion
6192 * pBoolOut [O] Destination
6196 * Failure: E_INVALIDARG, if the source value is invalid
6197 * DISP_E_OVERFLOW, if the value will not fit in the destination
6198 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6200 HRESULT WINAPI
VarBoolFromDisp(IDispatch
* pdispIn
, LCID lcid
, VARIANT_BOOL
*pBoolOut
)
6202 return VARIANT_FromDisp(pdispIn
, lcid
, pBoolOut
, VT_BOOL
, 0);
6205 /************************************************************************
6206 * VarBoolFromI1 (OLEAUT32.233)
6208 * Convert a VT_I1 to a VT_BOOL.
6212 * pBoolOut [O] Destination
6217 HRESULT WINAPI
VarBoolFromI1(signed char cIn
, VARIANT_BOOL
*pBoolOut
)
6219 *pBoolOut
= cIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6223 /************************************************************************
6224 * VarBoolFromUI2 (OLEAUT32.234)
6226 * Convert a VT_UI2 to a VT_BOOL.
6230 * pBoolOut [O] Destination
6235 HRESULT WINAPI
VarBoolFromUI2(USHORT usIn
, VARIANT_BOOL
*pBoolOut
)
6237 *pBoolOut
= usIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6241 /************************************************************************
6242 * VarBoolFromUI4 (OLEAUT32.235)
6244 * Convert a VT_UI4 to a VT_BOOL.
6248 * pBoolOut [O] Destination
6253 HRESULT WINAPI
VarBoolFromUI4(ULONG ulIn
, VARIANT_BOOL
*pBoolOut
)
6255 *pBoolOut
= ulIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6259 /************************************************************************
6260 * VarBoolFromDec (OLEAUT32.236)
6262 * Convert a VT_DECIMAL to a VT_BOOL.
6266 * pBoolOut [O] Destination
6270 * Failure: E_INVALIDARG, if pDecIn is invalid.
6272 HRESULT WINAPI
VarBoolFromDec(DECIMAL
* pDecIn
, VARIANT_BOOL
*pBoolOut
)
6274 if (DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
|| (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
))
6275 return E_INVALIDARG
;
6277 if (DEC_HI32(pDecIn
) || DEC_MID32(pDecIn
) || DEC_LO32(pDecIn
))
6278 *pBoolOut
= VARIANT_TRUE
;
6280 *pBoolOut
= VARIANT_FALSE
;
6284 /************************************************************************
6285 * VarBoolFromI8 (OLEAUT32.370)
6287 * Convert a VT_I8 to a VT_BOOL.
6291 * pBoolOut [O] Destination
6296 HRESULT WINAPI
VarBoolFromI8(LONG64 llIn
, VARIANT_BOOL
*pBoolOut
)
6298 *pBoolOut
= llIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6302 /************************************************************************
6303 * VarBoolFromUI8 (OLEAUT32.371)
6305 * Convert a VT_UI8 to a VT_BOOL.
6309 * pBoolOut [O] Destination
6314 HRESULT WINAPI
VarBoolFromUI8(ULONG64 ullIn
, VARIANT_BOOL
*pBoolOut
)
6316 *pBoolOut
= ullIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6323 /* Write a number from a UI8 and sign */
6324 static WCHAR
*VARIANT_WriteNumber(ULONG64 ulVal
, WCHAR
* szOut
)
6328 WCHAR ulNextDigit
= ulVal
% 10;
6330 *szOut
-- = '0' + ulNextDigit
;
6331 ulVal
= (ulVal
- ulNextDigit
) / 10;
6338 /* Create a (possibly localised) BSTR from a UI8 and sign */
6339 static BSTR
VARIANT_MakeBstr(LCID lcid
, DWORD dwFlags
, WCHAR
*szOut
)
6341 WCHAR szConverted
[256];
6343 if (dwFlags
& VAR_NEGATIVE
)
6346 if (dwFlags
& LOCALE_USE_NLS
)
6348 /* Format the number for the locale */
6349 szConverted
[0] = '\0';
6350 GetNumberFormatW(lcid
,
6351 dwFlags
& LOCALE_NOUSEROVERRIDE
,
6352 szOut
, NULL
, szConverted
, sizeof(szConverted
)/sizeof(WCHAR
));
6353 szOut
= szConverted
;
6355 return SysAllocStringByteLen((LPCSTR
)szOut
, strlenW(szOut
) * sizeof(WCHAR
));
6358 /* Create a (possibly localised) BSTR from a UI8 and sign */
6359 static HRESULT
VARIANT_BstrFromUInt(ULONG64 ulVal
, LCID lcid
, DWORD dwFlags
, BSTR
*pbstrOut
)
6361 WCHAR szBuff
[64], *szOut
= szBuff
+ sizeof(szBuff
)/sizeof(WCHAR
) - 1;
6364 return E_INVALIDARG
;
6366 /* Create the basic number string */
6368 szOut
= VARIANT_WriteNumber(ulVal
, szOut
);
6370 *pbstrOut
= VARIANT_MakeBstr(lcid
, dwFlags
, szOut
);
6371 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6372 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6375 /******************************************************************************
6376 * VarBstrFromUI1 (OLEAUT32.108)
6378 * Convert a VT_UI1 to a VT_BSTR.
6382 * lcid [I] LCID for the conversion
6383 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6384 * pbstrOut [O] Destination
6388 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6389 * E_OUTOFMEMORY, if memory allocation fails.
6391 HRESULT WINAPI
VarBstrFromUI1(BYTE bIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6393 return VARIANT_BstrFromUInt(bIn
, lcid
, dwFlags
, pbstrOut
);
6396 /******************************************************************************
6397 * VarBstrFromI2 (OLEAUT32.109)
6399 * Convert a VT_I2 to a VT_BSTR.
6403 * lcid [I] LCID for the conversion
6404 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6405 * pbstrOut [O] Destination
6409 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6410 * E_OUTOFMEMORY, if memory allocation fails.
6412 HRESULT WINAPI
VarBstrFromI2(short sIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6419 dwFlags
|= VAR_NEGATIVE
;
6421 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6424 /******************************************************************************
6425 * VarBstrFromI4 (OLEAUT32.110)
6427 * Convert a VT_I4 to a VT_BSTR.
6431 * lcid [I] LCID for the conversion
6432 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6433 * pbstrOut [O] Destination
6437 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6438 * E_OUTOFMEMORY, if memory allocation fails.
6440 HRESULT WINAPI
VarBstrFromI4(LONG lIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6447 dwFlags
|= VAR_NEGATIVE
;
6449 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6452 static BSTR
VARIANT_BstrReplaceDecimal(const WCHAR
* buff
, LCID lcid
, ULONG dwFlags
)
6455 WCHAR lpDecimalSep
[16];
6457 /* Native oleaut32 uses the locale-specific decimal separator even in the
6458 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6459 American locales will see "one thousand and one tenth" as "1000,1"
6460 instead of "1000.1" (notice the comma). The following code checks for
6461 the need to replace the decimal separator, and if so, will prepare an
6462 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6464 GetLocaleInfoW(lcid
, LOCALE_SDECIMAL
| (dwFlags
& LOCALE_NOUSEROVERRIDE
),
6465 lpDecimalSep
, sizeof(lpDecimalSep
) / sizeof(WCHAR
));
6466 if (lpDecimalSep
[0] == '.' && lpDecimalSep
[1] == '\0')
6468 /* locale is compatible with English - return original string */
6469 bstrOut
= SysAllocString(buff
);
6475 WCHAR empty
[] = {'\0'};
6476 NUMBERFMTW minFormat
;
6478 minFormat
.NumDigits
= 0;
6479 minFormat
.LeadingZero
= 0;
6480 minFormat
.Grouping
= 0;
6481 minFormat
.lpDecimalSep
= lpDecimalSep
;
6482 minFormat
.lpThousandSep
= empty
;
6483 minFormat
.NegativeOrder
= 1; /* NLS_NEG_LEFT */
6485 /* count number of decimal digits in string */
6486 p
= strchrW( buff
, '.' );
6487 if (p
) minFormat
.NumDigits
= strlenW(p
+ 1);
6490 if (!GetNumberFormatW(lcid
, 0, buff
, &minFormat
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
)))
6492 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6493 bstrOut
= SysAllocString(buff
);
6497 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff
));
6498 bstrOut
= SysAllocString(numbuff
);
6504 static HRESULT
VARIANT_BstrFromReal(DOUBLE dblIn
, LCID lcid
, ULONG dwFlags
,
6505 BSTR
* pbstrOut
, LPCWSTR lpszFormat
)
6510 return E_INVALIDARG
;
6512 sprintfW( buff
, lpszFormat
, dblIn
);
6514 /* Negative zeroes are disallowed (some applications depend on this).
6515 If buff starts with a minus, and then nothing follows but zeroes
6516 and/or a period, it is a negative zero and is replaced with a
6517 canonical zero. This duplicates native oleaut32 behavior.
6521 const WCHAR szAccept
[] = {'0', '.', '\0'};
6522 if (strlenW(buff
+ 1) == strspnW(buff
+ 1, szAccept
))
6523 { buff
[0] = '0'; buff
[1] = '\0'; }
6526 TRACE("created string %s\n", debugstr_w(buff
));
6527 if (dwFlags
& LOCALE_USE_NLS
)
6531 /* Format the number for the locale */
6533 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6534 buff
, NULL
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
));
6535 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
6536 *pbstrOut
= SysAllocString(numbuff
);
6540 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
6542 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6545 /******************************************************************************
6546 * VarBstrFromR4 (OLEAUT32.111)
6548 * Convert a VT_R4 to a VT_BSTR.
6552 * lcid [I] LCID for the conversion
6553 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6554 * pbstrOut [O] Destination
6558 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6559 * E_OUTOFMEMORY, if memory allocation fails.
6561 HRESULT WINAPI
VarBstrFromR4(FLOAT fltIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6563 return VARIANT_BstrFromReal(fltIn
, lcid
, dwFlags
, pbstrOut
, szFloatFormatW
);
6566 /******************************************************************************
6567 * VarBstrFromR8 (OLEAUT32.112)
6569 * Convert a VT_R8 to a VT_BSTR.
6573 * lcid [I] LCID for the conversion
6574 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6575 * pbstrOut [O] Destination
6579 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6580 * E_OUTOFMEMORY, if memory allocation fails.
6582 HRESULT WINAPI
VarBstrFromR8(double dblIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6584 return VARIANT_BstrFromReal(dblIn
, lcid
, dwFlags
, pbstrOut
, szDoubleFormatW
);
6587 /******************************************************************************
6588 * VarBstrFromCy [OLEAUT32.113]
6590 * Convert a VT_CY to a VT_BSTR.
6594 * lcid [I] LCID for the conversion
6595 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6596 * pbstrOut [O] Destination
6600 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6601 * E_OUTOFMEMORY, if memory allocation fails.
6603 HRESULT WINAPI
VarBstrFromCy(CY cyIn
, LCID lcid
, ULONG dwFlags
, BSTR
*pbstrOut
)
6609 return E_INVALIDARG
;
6613 decVal
.bitsnum
[0] = cyIn
.s
.Lo
;
6614 decVal
.bitsnum
[1] = cyIn
.s
.Hi
;
6615 if (cyIn
.s
.Hi
& 0x80000000UL
) {
6618 /* Negative number! */
6620 decVal
.bitsnum
[0] = ~decVal
.bitsnum
[0];
6621 decVal
.bitsnum
[1] = ~decVal
.bitsnum
[1];
6622 VARIANT_int_add(decVal
.bitsnum
, 3, &one
, 1);
6624 decVal
.bitsnum
[2] = 0;
6625 VARIANT_DI_tostringW(&decVal
, buff
, sizeof(buff
)/sizeof(buff
[0]));
6627 if (dwFlags
& LOCALE_USE_NLS
)
6631 /* Format the currency for the locale */
6633 GetCurrencyFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6634 buff
, NULL
, cybuff
, sizeof(cybuff
) / sizeof(WCHAR
));
6635 *pbstrOut
= SysAllocString(cybuff
);
6638 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
,lcid
,dwFlags
);
6640 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6643 static inline int output_int_len(int o
, int min_len
, WCHAR
*date
, int date_len
)
6647 if(min_len
>= date_len
)
6650 for(len
=0, tmp
=o
; tmp
; tmp
/=10) len
++;
6655 for(tmp
=min_len
-len
; tmp
>0; tmp
--)
6657 for(tmp
=len
; tmp
>0; tmp
--, o
/=10)
6658 date
[tmp
-1] = '0' + o
%10;
6659 return min_len
>len
? min_len
: len
;
6662 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6663 BOOL
get_date_format(LCID lcid
, DWORD flags
, const SYSTEMTIME
*st
,
6664 const WCHAR
*fmt
, WCHAR
*date
, int date_len
)
6666 static const LCTYPE dayname
[] = {
6667 LOCALE_SDAYNAME7
, LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
,
6668 LOCALE_SDAYNAME4
, LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
6670 static const LCTYPE sdayname
[] = {
6671 LOCALE_SABBREVDAYNAME7
, LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
,
6672 LOCALE_SABBREVDAYNAME3
, LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
,
6673 LOCALE_SABBREVDAYNAME6
6675 static const LCTYPE monthname
[] = {
6676 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
6677 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
6678 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
6680 static const LCTYPE smonthname
[] = {
6681 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
6682 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
6683 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
6684 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
6687 if(flags
& ~(LOCALE_NOUSEROVERRIDE
|VAR_DATEVALUEONLY
))
6688 FIXME("ignoring flags %x\n", flags
);
6689 flags
&= LOCALE_NOUSEROVERRIDE
;
6691 while(*fmt
&& date_len
) {
6699 while(*fmt
== *(fmt
+count
))
6707 count
= GetLocaleInfoW(lcid
, dayname
[st
->wDayOfWeek
] | flags
, date
, date_len
)-1;
6709 count
= GetLocaleInfoW(lcid
, sdayname
[st
->wDayOfWeek
] | flags
, date
, date_len
)-1;
6711 count
= output_int_len(st
->wDay
, count
, date
, date_len
);
6715 count
= GetLocaleInfoW(lcid
, monthname
[st
->wMonth
-1] | flags
, date
, date_len
)-1;
6717 count
= GetLocaleInfoW(lcid
, smonthname
[st
->wMonth
-1] | flags
, date
, date_len
)-1;
6719 count
= output_int_len(st
->wMonth
, count
, date
, date_len
);
6723 count
= output_int_len(st
->wYear
, 0, date
, date_len
);
6725 count
= output_int_len(st
->wYear
%100, count
, date
, date_len
);
6729 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6757 /******************************************************************************
6758 * VarBstrFromDate [OLEAUT32.114]
6760 * Convert a VT_DATE to a VT_BSTR.
6764 * lcid [I] LCID for the conversion
6765 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6766 * pbstrOut [O] Destination
6770 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6771 * E_OUTOFMEMORY, if memory allocation fails.
6773 HRESULT WINAPI
VarBstrFromDate(DATE dateIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6776 DWORD dwFormatFlags
= dwFlags
& LOCALE_NOUSEROVERRIDE
;
6777 WCHAR date
[128], fmt_buff
[80], *time
;
6779 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn
, lcid
, dwFlags
, pbstrOut
);
6781 if (!pbstrOut
|| !VariantTimeToSystemTime(dateIn
, &st
))
6782 return E_INVALIDARG
;
6786 if (dwFlags
& VAR_CALENDAR_THAI
)
6787 st
.wYear
+= 553; /* Use the Thai buddhist calendar year */
6788 else if (dwFlags
& (VAR_CALENDAR_HIJRI
|VAR_CALENDAR_GREGORIAN
))
6789 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6791 if (dwFlags
& LOCALE_USE_NLS
)
6792 dwFlags
&= ~(VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
);
6795 double whole
= dateIn
< 0 ? ceil(dateIn
) : floor(dateIn
);
6796 double partial
= dateIn
- whole
;
6799 dwFlags
|= VAR_TIMEVALUEONLY
;
6800 else if (partial
> -1e-12 && partial
< 1e-12)
6801 dwFlags
|= VAR_DATEVALUEONLY
;
6804 if (dwFlags
& VAR_TIMEVALUEONLY
)
6807 if (!GetLocaleInfoW(lcid
, LOCALE_SSHORTDATE
, fmt_buff
, sizeof(fmt_buff
)/sizeof(WCHAR
)) ||
6808 !get_date_format(lcid
, dwFlags
, &st
, fmt_buff
, date
, sizeof(date
)/sizeof(WCHAR
)))
6809 return E_INVALIDARG
;
6811 if (!(dwFlags
& VAR_DATEVALUEONLY
))
6813 time
= date
+ strlenW(date
);
6816 if (!GetTimeFormatW(lcid
, dwFormatFlags
, &st
, NULL
, time
,
6817 sizeof(date
)/sizeof(WCHAR
)-(time
-date
)))
6818 return E_INVALIDARG
;
6821 *pbstrOut
= SysAllocString(date
);
6823 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6824 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6827 /******************************************************************************
6828 * VarBstrFromBool (OLEAUT32.116)
6830 * Convert a VT_BOOL to a VT_BSTR.
6834 * lcid [I] LCID for the conversion
6835 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6836 * pbstrOut [O] Destination
6840 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6841 * E_OUTOFMEMORY, if memory allocation fails.
6844 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6845 * localised text of "True" or "False". To convert a bool into a
6846 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6848 HRESULT WINAPI
VarBstrFromBool(VARIANT_BOOL boolIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6851 DWORD dwResId
= IDS_TRUE
;
6854 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn
, lcid
, dwFlags
, pbstrOut
);
6857 return E_INVALIDARG
;
6859 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6860 * for variant formatting */
6861 switch (dwFlags
& (VAR_LOCALBOOL
|VAR_BOOLONOFF
|VAR_BOOLYESNO
))
6872 lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
),SORT_DEFAULT
);
6875 lcid
= ConvertDefaultLocale(lcid
);
6876 langId
= LANGIDFROMLCID(lcid
);
6877 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6878 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6880 if (boolIn
== VARIANT_FALSE
)
6881 dwResId
++; /* Use negative form */
6883 VarBstrFromBool_GetLocalised
:
6884 if (VARIANT_GetLocalisedText(langId
, dwResId
, szBuff
))
6886 *pbstrOut
= SysAllocString(szBuff
);
6887 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6890 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6892 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6893 goto VarBstrFromBool_GetLocalised
;
6896 /* Should never get here */
6897 WARN("Failed to load bool text!\n");
6898 return E_OUTOFMEMORY
;
6901 /******************************************************************************
6902 * VarBstrFromI1 (OLEAUT32.229)
6904 * Convert a VT_I1 to a VT_BSTR.
6908 * lcid [I] LCID for the conversion
6909 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6910 * pbstrOut [O] Destination
6914 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6915 * E_OUTOFMEMORY, if memory allocation fails.
6917 HRESULT WINAPI
VarBstrFromI1(signed char cIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6924 dwFlags
|= VAR_NEGATIVE
;
6926 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6929 /******************************************************************************
6930 * VarBstrFromUI2 (OLEAUT32.230)
6932 * Convert a VT_UI2 to a VT_BSTR.
6936 * lcid [I] LCID for the conversion
6937 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6938 * pbstrOut [O] Destination
6942 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6943 * E_OUTOFMEMORY, if memory allocation fails.
6945 HRESULT WINAPI
VarBstrFromUI2(USHORT usIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6947 return VARIANT_BstrFromUInt(usIn
, lcid
, dwFlags
, pbstrOut
);
6950 /******************************************************************************
6951 * VarBstrFromUI4 (OLEAUT32.231)
6953 * Convert a VT_UI4 to a VT_BSTR.
6957 * lcid [I] LCID for the conversion
6958 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6959 * pbstrOut [O] Destination
6963 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6964 * E_OUTOFMEMORY, if memory allocation fails.
6966 HRESULT WINAPI
VarBstrFromUI4(ULONG ulIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6968 return VARIANT_BstrFromUInt(ulIn
, lcid
, dwFlags
, pbstrOut
);
6971 /******************************************************************************
6972 * VarBstrFromDec (OLEAUT32.232)
6974 * Convert a VT_DECIMAL to a VT_BSTR.
6978 * lcid [I] LCID for the conversion
6979 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6980 * pbstrOut [O] Destination
6984 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6985 * E_OUTOFMEMORY, if memory allocation fails.
6987 HRESULT WINAPI
VarBstrFromDec(DECIMAL
* pDecIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6993 return E_INVALIDARG
;
6995 VARIANT_DIFromDec(pDecIn
, &temp
);
6996 VARIANT_DI_tostringW(&temp
, buff
, 256);
6998 if (dwFlags
& LOCALE_USE_NLS
)
7002 /* Format the number for the locale */
7004 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
7005 buff
, NULL
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
));
7006 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
7007 *pbstrOut
= SysAllocString(numbuff
);
7011 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
7014 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
7015 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
7018 /************************************************************************
7019 * VarBstrFromI8 (OLEAUT32.370)
7021 * Convert a VT_I8 to a VT_BSTR.
7025 * lcid [I] LCID for the conversion
7026 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7027 * pbstrOut [O] Destination
7031 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7032 * E_OUTOFMEMORY, if memory allocation fails.
7034 HRESULT WINAPI
VarBstrFromI8(LONG64 llIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7036 ULONG64 ul64
= llIn
;
7041 dwFlags
|= VAR_NEGATIVE
;
7043 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
7046 /************************************************************************
7047 * VarBstrFromUI8 (OLEAUT32.371)
7049 * Convert a VT_UI8 to a VT_BSTR.
7053 * lcid [I] LCID for the conversion
7054 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7055 * pbstrOut [O] Destination
7059 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7060 * E_OUTOFMEMORY, if memory allocation fails.
7062 HRESULT WINAPI
VarBstrFromUI8(ULONG64 ullIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7064 return VARIANT_BstrFromUInt(ullIn
, lcid
, dwFlags
, pbstrOut
);
7067 /************************************************************************
7068 * VarBstrFromDisp (OLEAUT32.115)
7070 * Convert a VT_DISPATCH to a BSTR.
7073 * pdispIn [I] Source
7074 * lcid [I] LCID for conversion
7075 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7076 * pbstrOut [O] Destination
7080 * Failure: E_INVALIDARG, if the source value is invalid
7081 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7083 HRESULT WINAPI
VarBstrFromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7085 return VARIANT_FromDisp(pdispIn
, lcid
, pbstrOut
, VT_BSTR
, dwFlags
);
7088 /**********************************************************************
7089 * VarBstrCat (OLEAUT32.313)
7091 * Concatenate two BSTR values.
7094 * pbstrLeft [I] Source
7095 * pbstrRight [I] Value to concatenate
7096 * pbstrOut [O] Destination
7100 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7101 * E_OUTOFMEMORY, if memory allocation fails.
7103 HRESULT WINAPI
VarBstrCat(BSTR pbstrLeft
, BSTR pbstrRight
, BSTR
*pbstrOut
)
7105 unsigned int lenLeft
, lenRight
;
7108 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
7109 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), pbstrOut
);
7112 return E_INVALIDARG
;
7114 /* use byte length here to properly handle ansi-allocated BSTRs */
7115 lenLeft
= pbstrLeft
? SysStringByteLen(pbstrLeft
) : 0;
7116 lenRight
= pbstrRight
? SysStringByteLen(pbstrRight
) : 0;
7118 *pbstrOut
= SysAllocStringByteLen(NULL
, lenLeft
+ lenRight
);
7120 return E_OUTOFMEMORY
;
7122 (*pbstrOut
)[0] = '\0';
7125 memcpy(*pbstrOut
, pbstrLeft
, lenLeft
);
7128 memcpy((CHAR
*)*pbstrOut
+ lenLeft
, pbstrRight
, lenRight
);
7130 TRACE("%s\n", debugstr_wn(*pbstrOut
, SysStringLen(*pbstrOut
)));
7134 /**********************************************************************
7135 * VarBstrCmp (OLEAUT32.314)
7137 * Compare two BSTR values.
7140 * pbstrLeft [I] Source
7141 * pbstrRight [I] Value to compare
7142 * lcid [I] LCID for the comparison
7143 * dwFlags [I] Flags to pass directly to CompareStringW().
7146 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7147 * than, equal to or greater than pbstrRight respectively.
7150 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7151 * states. A NULL BSTR pointer is equivalent to an empty string.
7152 * If LCID is equal to 0, a byte by byte comparison is performed.
7154 HRESULT WINAPI
VarBstrCmp(BSTR pbstrLeft
, BSTR pbstrRight
, LCID lcid
, DWORD dwFlags
)
7159 TRACE("%s,%s,%d,%08x\n",
7160 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
7161 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), lcid
, dwFlags
);
7163 if (!pbstrLeft
|| !*pbstrLeft
)
7165 if (pbstrRight
&& *pbstrRight
)
7168 else if (!pbstrRight
|| !*pbstrRight
)
7173 unsigned int lenLeft
= SysStringByteLen(pbstrLeft
);
7174 unsigned int lenRight
= SysStringByteLen(pbstrRight
);
7175 ret
= memcmp(pbstrLeft
, pbstrRight
, min(lenLeft
, lenRight
));
7180 if (lenLeft
< lenRight
)
7182 if (lenLeft
> lenRight
)
7188 unsigned int lenLeft
= SysStringLen(pbstrLeft
);
7189 unsigned int lenRight
= SysStringLen(pbstrRight
);
7191 if (lenLeft
== 0 || lenRight
== 0)
7193 if (lenLeft
== 0 && lenRight
== 0) return VARCMP_EQ
;
7194 return lenLeft
< lenRight
? VARCMP_LT
: VARCMP_GT
;
7197 hres
= CompareStringW(lcid
, dwFlags
, pbstrLeft
, lenLeft
,
7198 pbstrRight
, lenRight
) - CSTR_LESS_THAN
;
7199 TRACE("%d\n", hres
);
7208 /******************************************************************************
7209 * VarDateFromUI1 (OLEAUT32.88)
7211 * Convert a VT_UI1 to a VT_DATE.
7215 * pdateOut [O] Destination
7220 HRESULT WINAPI
VarDateFromUI1(BYTE bIn
, DATE
* pdateOut
)
7222 return VarR8FromUI1(bIn
, pdateOut
);
7225 /******************************************************************************
7226 * VarDateFromI2 (OLEAUT32.89)
7228 * Convert a VT_I2 to a VT_DATE.
7232 * pdateOut [O] Destination
7237 HRESULT WINAPI
VarDateFromI2(short sIn
, DATE
* pdateOut
)
7239 return VarR8FromI2(sIn
, pdateOut
);
7242 /******************************************************************************
7243 * VarDateFromI4 (OLEAUT32.90)
7245 * Convert a VT_I4 to a VT_DATE.
7249 * pdateOut [O] Destination
7254 HRESULT WINAPI
VarDateFromI4(LONG lIn
, DATE
* pdateOut
)
7256 return VarDateFromR8(lIn
, pdateOut
);
7259 /******************************************************************************
7260 * VarDateFromR4 (OLEAUT32.91)
7262 * Convert a VT_R4 to a VT_DATE.
7266 * pdateOut [O] Destination
7271 HRESULT WINAPI
VarDateFromR4(FLOAT fltIn
, DATE
* pdateOut
)
7273 return VarR8FromR4(fltIn
, pdateOut
);
7276 /******************************************************************************
7277 * VarDateFromR8 (OLEAUT32.92)
7279 * Convert a VT_R8 to a VT_DATE.
7283 * pdateOut [O] Destination
7288 HRESULT WINAPI
VarDateFromR8(double dblIn
, DATE
* pdateOut
)
7290 if (dblIn
<= (DATE_MIN
- 1.0) || dblIn
>= (DATE_MAX
+ 1.0)) return DISP_E_OVERFLOW
;
7291 *pdateOut
= (DATE
)dblIn
;
7295 /**********************************************************************
7296 * VarDateFromDisp (OLEAUT32.95)
7298 * Convert a VT_DISPATCH to a VT_DATE.
7301 * pdispIn [I] Source
7302 * lcid [I] LCID for conversion
7303 * pdateOut [O] Destination
7307 * Failure: E_INVALIDARG, if the source value is invalid
7308 * DISP_E_OVERFLOW, if the value will not fit in the destination
7309 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7311 HRESULT WINAPI
VarDateFromDisp(IDispatch
* pdispIn
, LCID lcid
, DATE
* pdateOut
)
7313 return VARIANT_FromDisp(pdispIn
, lcid
, pdateOut
, VT_DATE
, 0);
7316 /******************************************************************************
7317 * VarDateFromBool (OLEAUT32.96)
7319 * Convert a VT_BOOL to a VT_DATE.
7323 * pdateOut [O] Destination
7328 HRESULT WINAPI
VarDateFromBool(VARIANT_BOOL boolIn
, DATE
* pdateOut
)
7330 return VarR8FromBool(boolIn
, pdateOut
);
7333 /**********************************************************************
7334 * VarDateFromCy (OLEAUT32.93)
7336 * Convert a VT_CY to a VT_DATE.
7340 * pdateOut [O] Destination
7345 HRESULT WINAPI
VarDateFromCy(CY cyIn
, DATE
* pdateOut
)
7347 return VarR8FromCy(cyIn
, pdateOut
);
7350 /* Date string parsing */
7351 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7352 #define DP_DATESEP 0x02 /* Date separator */
7353 #define DP_MONTH 0x04 /* Month name */
7354 #define DP_AM 0x08 /* AM */
7355 #define DP_PM 0x10 /* PM */
7357 typedef struct tagDATEPARSE
7359 DWORD dwCount
; /* Number of fields found so far (maximum 6) */
7360 DWORD dwParseFlags
; /* Global parse flags (DP_ Flags above) */
7361 DWORD dwFlags
[6]; /* Flags for each field */
7362 DWORD dwValues
[6]; /* Value of each field */
7365 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7367 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7369 /* Determine if a day is valid in a given month of a given year */
7370 static BOOL
VARIANT_IsValidMonthDay(DWORD day
, DWORD month
, DWORD year
)
7372 static const BYTE days
[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7374 if (day
&& month
&& month
< 13)
7376 if (day
<= days
[month
] || (month
== 2 && day
== 29 && IsLeapYear(year
)))
7382 /* Possible orders for 3 numbers making up a date */
7383 #define ORDER_MDY 0x01
7384 #define ORDER_YMD 0x02
7385 #define ORDER_YDM 0x04
7386 #define ORDER_DMY 0x08
7387 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7389 /* Determine a date for a particular locale, from 3 numbers */
7390 static inline HRESULT
VARIANT_MakeDate(DATEPARSE
*dp
, DWORD iDate
,
7391 DWORD offset
, SYSTEMTIME
*st
)
7393 DWORD dwAllOrders
, dwTry
, dwCount
= 0, v1
, v2
, v3
;
7397 v1
= 30; /* Default to (Variant) 0 date part */
7400 goto VARIANT_MakeDate_OK
;
7403 v1
= dp
->dwValues
[offset
+ 0];
7404 v2
= dp
->dwValues
[offset
+ 1];
7405 if (dp
->dwCount
== 2)
7408 GetSystemTime(¤t
);
7412 v3
= dp
->dwValues
[offset
+ 2];
7414 TRACE("(%d,%d,%d,%d,%d)\n", v1
, v2
, v3
, iDate
, offset
);
7416 /* If one number must be a month (Because a month name was given), then only
7417 * consider orders with the month in that position.
7418 * If we took the current year as 'v3', then only allow a year in that position.
7420 if (dp
->dwFlags
[offset
+ 0] & DP_MONTH
)
7422 dwAllOrders
= ORDER_MDY
;
7424 else if (dp
->dwFlags
[offset
+ 1] & DP_MONTH
)
7426 dwAllOrders
= ORDER_DMY
;
7427 if (dp
->dwCount
> 2)
7428 dwAllOrders
|= ORDER_YMD
;
7430 else if (dp
->dwCount
> 2 && dp
->dwFlags
[offset
+ 2] & DP_MONTH
)
7432 dwAllOrders
= ORDER_YDM
;
7436 dwAllOrders
= ORDER_MDY
|ORDER_DMY
;
7437 if (dp
->dwCount
> 2)
7438 dwAllOrders
|= (ORDER_YMD
|ORDER_YDM
);
7441 VARIANT_MakeDate_Start
:
7442 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders
);
7450 /* First: Try the order given by iDate */
7453 case 0: dwTry
= dwAllOrders
& ORDER_MDY
; break;
7454 case 1: dwTry
= dwAllOrders
& ORDER_DMY
; break;
7455 default: dwTry
= dwAllOrders
& ORDER_YMD
; break;
7458 else if (dwCount
== 1)
7460 /* Second: Try all the orders compatible with iDate */
7463 case 0: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7464 case 1: dwTry
= dwAllOrders
& ~(ORDER_MDY
|ORDER_YDM
|ORDER_MYD
); break;
7465 default: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7470 /* Finally: Try any remaining orders */
7471 dwTry
= dwAllOrders
;
7474 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount
, dwTry
);
7480 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7482 if (dwTry
& ORDER_MDY
)
7484 if (VARIANT_IsValidMonthDay(v2
,v1
,v3
))
7487 goto VARIANT_MakeDate_OK
;
7489 dwAllOrders
&= ~ORDER_MDY
;
7491 if (dwTry
& ORDER_YMD
)
7493 if (VARIANT_IsValidMonthDay(v3
,v2
,v1
))
7496 goto VARIANT_MakeDate_OK
;
7498 dwAllOrders
&= ~ORDER_YMD
;
7500 if (dwTry
& ORDER_YDM
)
7502 if (VARIANT_IsValidMonthDay(v2
,v3
,v1
))
7506 goto VARIANT_MakeDate_OK
;
7508 dwAllOrders
&= ~ORDER_YDM
;
7510 if (dwTry
& ORDER_DMY
)
7512 if (VARIANT_IsValidMonthDay(v1
,v2
,v3
))
7513 goto VARIANT_MakeDate_OK
;
7514 dwAllOrders
&= ~ORDER_DMY
;
7516 if (dwTry
& ORDER_MYD
)
7518 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7519 if (VARIANT_IsValidMonthDay(v3
,v1
,v2
))
7523 goto VARIANT_MakeDate_OK
;
7525 dwAllOrders
&= ~ORDER_MYD
;
7529 if (dp
->dwCount
== 2)
7531 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7532 v3
= 1; /* 1st of the month */
7533 dwAllOrders
= ORDER_YMD
|ORDER_MYD
;
7534 dp
->dwCount
= 0; /* Don't return to this code path again */
7536 goto VARIANT_MakeDate_Start
;
7539 /* No valid dates were able to be constructed */
7540 return DISP_E_TYPEMISMATCH
;
7542 VARIANT_MakeDate_OK
:
7544 /* Check that the time part is ok */
7545 if (st
->wHour
> 23 || st
->wMinute
> 59 || st
->wSecond
> 59)
7546 return DISP_E_TYPEMISMATCH
;
7548 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7549 if (st
->wHour
< 12 && (dp
->dwParseFlags
& DP_PM
))
7551 else if (st
->wHour
== 12 && (dp
->dwParseFlags
& DP_AM
))
7553 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7557 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7558 * be retrieved from:
7559 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7560 * But Wine doesn't have/use that key as at the time of writing.
7562 st
->wYear
= v3
< 30 ? 2000 + v3
: v3
< 100 ? 1900 + v3
: v3
;
7563 TRACE("Returning date %d/%d/%d\n", v1
, v2
, st
->wYear
);
7567 /******************************************************************************
7568 * VarDateFromStr [OLEAUT32.94]
7570 * Convert a VT_BSTR to at VT_DATE.
7573 * strIn [I] String to convert
7574 * lcid [I] Locale identifier for the conversion
7575 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7576 * pdateOut [O] Destination for the converted value
7579 * Success: S_OK. pdateOut contains the converted value.
7580 * FAILURE: An HRESULT error code indicating the problem.
7583 * Any date format that can be created using the date formats from lcid
7584 * (Either from kernel Nls functions, variant conversion or formatting) is a
7585 * valid input to this function. In addition, a few more esoteric formats are
7586 * also supported for compatibility with the native version. The date is
7587 * interpreted according to the date settings in the control panel, unless
7588 * the date is invalid in that format, in which the most compatible format
7589 * that produces a valid date will be used.
7591 HRESULT WINAPI
VarDateFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DATE
* pdateOut
)
7593 static const USHORT ParseDateTokens
[] =
7595 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
7596 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
7597 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
,
7598 LOCALE_SMONTHNAME13
,
7599 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
7600 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
7601 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
7602 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
,
7603 LOCALE_SABBREVMONTHNAME13
,
7604 LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
, LOCALE_SDAYNAME4
,
7605 LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
, LOCALE_SDAYNAME7
,
7606 LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
, LOCALE_SABBREVDAYNAME3
,
7607 LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
, LOCALE_SABBREVDAYNAME6
,
7608 LOCALE_SABBREVDAYNAME7
,
7609 LOCALE_S1159
, LOCALE_S2359
,
7612 static const BYTE ParseDateMonths
[] =
7614 1,2,3,4,5,6,7,8,9,10,11,12,13,
7615 1,2,3,4,5,6,7,8,9,10,11,12,13
7618 BSTR tokens
[sizeof(ParseDateTokens
)/sizeof(ParseDateTokens
[0])];
7620 DWORD dwDateSeps
= 0, iDate
= 0;
7621 HRESULT hRet
= S_OK
;
7623 if ((dwFlags
& (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
)) ==
7624 (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
))
7625 return E_INVALIDARG
;
7628 return DISP_E_TYPEMISMATCH
;
7632 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn
), lcid
, dwFlags
, pdateOut
);
7634 memset(&dp
, 0, sizeof(dp
));
7636 GetLocaleInfoW(lcid
, LOCALE_IDATE
|LOCALE_RETURN_NUMBER
|(dwFlags
& LOCALE_NOUSEROVERRIDE
),
7637 (LPWSTR
)&iDate
, sizeof(iDate
)/sizeof(WCHAR
));
7638 TRACE("iDate is %d\n", iDate
);
7640 /* Get the month/day/am/pm tokens for this locale */
7641 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7644 LCTYPE lctype
= ParseDateTokens
[i
] | (dwFlags
& LOCALE_NOUSEROVERRIDE
);
7646 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7647 * GetAltMonthNames(). We should really cache these strings too.
7650 GetLocaleInfoW(lcid
, lctype
, buff
, sizeof(buff
)/sizeof(WCHAR
));
7651 tokens
[i
] = SysAllocString(buff
);
7652 TRACE("token %d is %s\n", i
, debugstr_w(tokens
[i
]));
7655 /* Parse the string into our structure */
7658 if (isdigitW(*strIn
))
7660 if (dp
.dwCount
>= 6)
7662 hRet
= DISP_E_TYPEMISMATCH
;
7665 dp
.dwValues
[dp
.dwCount
] = strtoulW(strIn
, &strIn
, 10);
7669 else if (isalphaW(*strIn
))
7671 BOOL bFound
= FALSE
;
7673 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7675 DWORD dwLen
= strlenW(tokens
[i
]);
7676 if (dwLen
&& !strncmpiW(strIn
, tokens
[i
], dwLen
))
7680 if (dp
.dwCount
>= 6)
7681 hRet
= DISP_E_TYPEMISMATCH
;
7684 dp
.dwValues
[dp
.dwCount
] = ParseDateMonths
[i
];
7685 dp
.dwFlags
[dp
.dwCount
] |= (DP_MONTH
|DP_DATESEP
);
7689 else if (i
> 39 && i
< 42)
7691 if (!dp
.dwCount
|| dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7692 hRet
= DISP_E_TYPEMISMATCH
;
7695 dp
.dwFlags
[dp
.dwCount
- 1] |= (i
== 40 ? DP_AM
: DP_PM
);
7696 dp
.dwParseFlags
|= (i
== 40 ? DP_AM
: DP_PM
);
7699 strIn
+= (dwLen
- 1);
7707 if ((*strIn
== 'a' || *strIn
== 'A' || *strIn
== 'p' || *strIn
== 'P') &&
7708 (dp
.dwCount
&& !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7710 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7711 if (*strIn
== 'a' || *strIn
== 'A')
7713 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_AM
;
7714 dp
.dwParseFlags
|= DP_AM
;
7718 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_PM
;
7719 dp
.dwParseFlags
|= DP_PM
;
7725 TRACE("No matching token for %s\n", debugstr_w(strIn
));
7726 hRet
= DISP_E_TYPEMISMATCH
;
7731 else if (*strIn
== ':' || *strIn
== '.')
7733 if (!dp
.dwCount
|| !strIn
[1])
7734 hRet
= DISP_E_TYPEMISMATCH
;
7736 if (tokens
[42][0] == *strIn
)
7740 hRet
= DISP_E_TYPEMISMATCH
;
7742 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7745 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_TIMESEP
;
7747 else if (*strIn
== '-' || *strIn
== '/')
7750 if (dwDateSeps
> 2 || !dp
.dwCount
|| !strIn
[1])
7751 hRet
= DISP_E_TYPEMISMATCH
;
7753 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7755 else if (*strIn
== ',' || isspaceW(*strIn
))
7757 if (*strIn
== ',' && !strIn
[1])
7758 hRet
= DISP_E_TYPEMISMATCH
;
7762 hRet
= DISP_E_TYPEMISMATCH
;
7767 if (!dp
.dwCount
|| dp
.dwCount
> 6 ||
7768 (dp
.dwCount
== 1 && !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7769 hRet
= DISP_E_TYPEMISMATCH
;
7771 if (SUCCEEDED(hRet
))
7774 DWORD dwOffset
= 0; /* Start of date fields in dp.dwValues */
7776 st
.wDayOfWeek
= st
.wHour
= st
.wMinute
= st
.wSecond
= st
.wMilliseconds
= 0;
7778 /* Figure out which numbers correspond to which fields.
7780 * This switch statement works based on the fact that native interprets any
7781 * fields that are not joined with a time separator ('.' or ':') as date
7782 * fields. Thus we construct a value from 0-32 where each set bit indicates
7783 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7784 * For valid permutations, we set dwOffset to point to the first date field
7785 * and shorten dp.dwCount by the number of time fields found. The real
7786 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7787 * each date number must represent in the context of iDate.
7789 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7791 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7793 case 0x1: /* TT TTDD TTDDD */
7794 if (dp
.dwCount
> 3 &&
7795 ((dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) ||
7796 (dp
.dwFlags
[4] & (DP_AM
|DP_PM
))))
7797 hRet
= DISP_E_TYPEMISMATCH
;
7798 else if (dp
.dwCount
!= 2 && dp
.dwCount
!= 4 && dp
.dwCount
!= 5)
7799 hRet
= DISP_E_TYPEMISMATCH
;
7800 st
.wHour
= dp
.dwValues
[0];
7801 st
.wMinute
= dp
.dwValues
[1];
7806 case 0x3: /* TTT TTTDD TTTDDD */
7807 if (dp
.dwCount
> 4 &&
7808 ((dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[4] & (DP_AM
|DP_PM
)) ||
7809 (dp
.dwFlags
[5] & (DP_AM
|DP_PM
))))
7810 hRet
= DISP_E_TYPEMISMATCH
;
7811 else if (dp
.dwCount
!= 3 && dp
.dwCount
!= 5 && dp
.dwCount
!= 6)
7812 hRet
= DISP_E_TYPEMISMATCH
;
7813 st
.wHour
= dp
.dwValues
[0];
7814 st
.wMinute
= dp
.dwValues
[1];
7815 st
.wSecond
= dp
.dwValues
[2];
7820 case 0x4: /* DDTT */
7821 if (dp
.dwCount
!= 4 ||
7822 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7823 hRet
= DISP_E_TYPEMISMATCH
;
7825 st
.wHour
= dp
.dwValues
[2];
7826 st
.wMinute
= dp
.dwValues
[3];
7830 case 0x0: /* T DD DDD TDDD TDDD */
7831 if (dp
.dwCount
== 1 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7833 st
.wHour
= dp
.dwValues
[0]; /* T */
7837 else if (dp
.dwCount
> 4 || (dp
.dwCount
< 3 && dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7839 hRet
= DISP_E_TYPEMISMATCH
;
7841 else if (dp
.dwCount
== 3)
7843 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDD */
7846 st
.wHour
= dp
.dwValues
[0];
7850 if (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) /* DDT */
7853 st
.wHour
= dp
.dwValues
[2];
7856 else if (dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7857 hRet
= DISP_E_TYPEMISMATCH
;
7859 else if (dp
.dwCount
== 4)
7862 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDDD */
7864 st
.wHour
= dp
.dwValues
[0];
7867 else if (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) /* DDDT */
7869 st
.wHour
= dp
.dwValues
[3];
7872 hRet
= DISP_E_TYPEMISMATCH
;
7875 /* .. fall through .. */
7877 case 0x8: /* DDDTT */
7878 if ((dp
.dwCount
== 2 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
))) ||
7879 (dp
.dwCount
== 5 && ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) ||
7880 (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))) ||
7881 dp
.dwCount
== 4 || dp
.dwCount
== 6)
7882 hRet
= DISP_E_TYPEMISMATCH
;
7883 st
.wHour
= dp
.dwValues
[3];
7884 st
.wMinute
= dp
.dwValues
[4];
7885 if (dp
.dwCount
== 5)
7889 case 0xC: /* DDTTT */
7890 if (dp
.dwCount
!= 5 ||
7891 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7892 hRet
= DISP_E_TYPEMISMATCH
;
7893 st
.wHour
= dp
.dwValues
[2];
7894 st
.wMinute
= dp
.dwValues
[3];
7895 st
.wSecond
= dp
.dwValues
[4];
7899 case 0x18: /* DDDTTT */
7900 if ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) ||
7901 (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))
7902 hRet
= DISP_E_TYPEMISMATCH
;
7903 st
.wHour
= dp
.dwValues
[3];
7904 st
.wMinute
= dp
.dwValues
[4];
7905 st
.wSecond
= dp
.dwValues
[5];
7910 hRet
= DISP_E_TYPEMISMATCH
;
7914 if (SUCCEEDED(hRet
))
7916 hRet
= VARIANT_MakeDate(&dp
, iDate
, dwOffset
, &st
);
7918 if (dwFlags
& VAR_TIMEVALUEONLY
)
7924 else if (dwFlags
& VAR_DATEVALUEONLY
)
7925 st
.wHour
= st
.wMinute
= st
.wSecond
= 0;
7927 /* Finally, convert the value to a VT_DATE */
7928 if (SUCCEEDED(hRet
))
7929 hRet
= SystemTimeToVariantTime(&st
, pdateOut
) ? S_OK
: DISP_E_TYPEMISMATCH
;
7933 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7934 SysFreeString(tokens
[i
]);
7938 /******************************************************************************
7939 * VarDateFromI1 (OLEAUT32.221)
7941 * Convert a VT_I1 to a VT_DATE.
7945 * pdateOut [O] Destination
7950 HRESULT WINAPI
VarDateFromI1(signed char cIn
, DATE
* pdateOut
)
7952 return VarR8FromI1(cIn
, pdateOut
);
7955 /******************************************************************************
7956 * VarDateFromUI2 (OLEAUT32.222)
7958 * Convert a VT_UI2 to a VT_DATE.
7962 * pdateOut [O] Destination
7967 HRESULT WINAPI
VarDateFromUI2(USHORT uiIn
, DATE
* pdateOut
)
7969 return VarR8FromUI2(uiIn
, pdateOut
);
7972 /******************************************************************************
7973 * VarDateFromUI4 (OLEAUT32.223)
7975 * Convert a VT_UI4 to a VT_DATE.
7979 * pdateOut [O] Destination
7984 HRESULT WINAPI
VarDateFromUI4(ULONG ulIn
, DATE
* pdateOut
)
7986 return VarDateFromR8(ulIn
, pdateOut
);
7989 /**********************************************************************
7990 * VarDateFromDec (OLEAUT32.224)
7992 * Convert a VT_DECIMAL to a VT_DATE.
7996 * pdateOut [O] Destination
8001 HRESULT WINAPI
VarDateFromDec(DECIMAL
*pdecIn
, DATE
* pdateOut
)
8003 return VarR8FromDec(pdecIn
, pdateOut
);
8006 /******************************************************************************
8007 * VarDateFromI8 (OLEAUT32.364)
8009 * Convert a VT_I8 to a VT_DATE.
8013 * pdateOut [O] Destination
8017 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8019 HRESULT WINAPI
VarDateFromI8(LONG64 llIn
, DATE
* pdateOut
)
8021 if (llIn
< DATE_MIN
|| llIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
8022 *pdateOut
= (DATE
)llIn
;
8026 /******************************************************************************
8027 * VarDateFromUI8 (OLEAUT32.365)
8029 * Convert a VT_UI8 to a VT_DATE.
8033 * pdateOut [O] Destination
8037 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8039 HRESULT WINAPI
VarDateFromUI8(ULONG64 ullIn
, DATE
* pdateOut
)
8041 if (ullIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
8042 *pdateOut
= (DATE
)ullIn
;