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 V_VT(&dstVar
) = VT_EMPTY
;
123 hRet
= VariantChangeTypeEx(&dstVar
, &srcVar
, lcid
, dwFlags
, vt
);
124 VariantClear(&srcVar
);
128 VARIANT_CopyData(&dstVar
, vt
, pOut
);
129 VariantClear(&srcVar
);
133 hRet
= DISP_E_TYPEMISMATCH
;
137 /* Inline return type */
138 #define RETTYP static inline HRESULT
141 /* Simple compiler cast from one type to another */
142 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
143 *out = in; return S_OK; }
145 /* Compiler cast where input cannot be negative */
146 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
147 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
149 /* Compiler cast where input cannot be > some number */
150 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
151 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
153 /* Compiler cast where input cannot be < some number or >= some other number */
154 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
155 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
158 POSTST(signed char, BYTE
, VarI1FromUI1
, I1_MAX
)
159 BOTHTST(signed char, SHORT
, VarI1FromI2
, I1_MIN
, I1_MAX
)
160 BOTHTST(signed char, LONG
, VarI1FromI4
, I1_MIN
, I1_MAX
)
161 SIMPLE(signed char, VARIANT_BOOL
, VarI1FromBool
)
162 POSTST(signed char, USHORT
, VarI1FromUI2
, I1_MAX
)
163 POSTST(signed char, ULONG
, VarI1FromUI4
, I1_MAX
)
164 BOTHTST(signed char, LONG64
, VarI1FromI8
, I1_MIN
, I1_MAX
)
165 POSTST(signed char, ULONG64
, VarI1FromUI8
, I1_MAX
)
168 BOTHTST(BYTE
, SHORT
, VarUI1FromI2
, UI1_MIN
, UI1_MAX
)
169 SIMPLE(BYTE
, VARIANT_BOOL
, VarUI1FromBool
)
170 NEGTST(BYTE
, signed char, VarUI1FromI1
)
171 POSTST(BYTE
, USHORT
, VarUI1FromUI2
, UI1_MAX
)
172 BOTHTST(BYTE
, LONG
, VarUI1FromI4
, UI1_MIN
, UI1_MAX
)
173 POSTST(BYTE
, ULONG
, VarUI1FromUI4
, UI1_MAX
)
174 BOTHTST(BYTE
, LONG64
, VarUI1FromI8
, UI1_MIN
, UI1_MAX
)
175 POSTST(BYTE
, ULONG64
, VarUI1FromUI8
, UI1_MAX
)
178 SIMPLE(SHORT
, BYTE
, VarI2FromUI1
)
179 BOTHTST(SHORT
, LONG
, VarI2FromI4
, I2_MIN
, I2_MAX
)
180 SIMPLE(SHORT
, VARIANT_BOOL
, VarI2FromBool
)
181 SIMPLE(SHORT
, signed char, VarI2FromI1
)
182 POSTST(SHORT
, USHORT
, VarI2FromUI2
, I2_MAX
)
183 POSTST(SHORT
, ULONG
, VarI2FromUI4
, I2_MAX
)
184 BOTHTST(SHORT
, LONG64
, VarI2FromI8
, I2_MIN
, I2_MAX
)
185 POSTST(SHORT
, ULONG64
, VarI2FromUI8
, I2_MAX
)
188 SIMPLE(USHORT
, BYTE
, VarUI2FromUI1
)
189 NEGTST(USHORT
, SHORT
, VarUI2FromI2
)
190 BOTHTST(USHORT
, LONG
, VarUI2FromI4
, UI2_MIN
, UI2_MAX
)
191 SIMPLE(USHORT
, VARIANT_BOOL
, VarUI2FromBool
)
192 NEGTST(USHORT
, signed char, VarUI2FromI1
)
193 POSTST(USHORT
, ULONG
, VarUI2FromUI4
, UI2_MAX
)
194 BOTHTST(USHORT
, LONG64
, VarUI2FromI8
, UI2_MIN
, UI2_MAX
)
195 POSTST(USHORT
, ULONG64
, VarUI2FromUI8
, UI2_MAX
)
198 SIMPLE(LONG
, BYTE
, VarI4FromUI1
)
199 SIMPLE(LONG
, SHORT
, VarI4FromI2
)
200 SIMPLE(LONG
, VARIANT_BOOL
, VarI4FromBool
)
201 SIMPLE(LONG
, signed char, VarI4FromI1
)
202 SIMPLE(LONG
, USHORT
, VarI4FromUI2
)
203 POSTST(LONG
, ULONG
, VarI4FromUI4
, I4_MAX
)
204 BOTHTST(LONG
, LONG64
, VarI4FromI8
, I4_MIN
, I4_MAX
)
205 POSTST(LONG
, ULONG64
, VarI4FromUI8
, I4_MAX
)
208 SIMPLE(ULONG
, BYTE
, VarUI4FromUI1
)
209 NEGTST(ULONG
, SHORT
, VarUI4FromI2
)
210 NEGTST(ULONG
, LONG
, VarUI4FromI4
)
211 SIMPLE(ULONG
, VARIANT_BOOL
, VarUI4FromBool
)
212 NEGTST(ULONG
, signed char, VarUI4FromI1
)
213 SIMPLE(ULONG
, USHORT
, VarUI4FromUI2
)
214 BOTHTST(ULONG
, LONG64
, VarUI4FromI8
, UI4_MIN
, UI4_MAX
)
215 POSTST(ULONG
, ULONG64
, VarUI4FromUI8
, UI4_MAX
)
218 SIMPLE(LONG64
, BYTE
, VarI8FromUI1
)
219 SIMPLE(LONG64
, SHORT
, VarI8FromI2
)
220 SIMPLE(LONG64
, signed char, VarI8FromI1
)
221 SIMPLE(LONG64
, USHORT
, VarI8FromUI2
)
222 SIMPLE(LONG64
, ULONG
, VarI8FromUI4
)
223 POSTST(LONG64
, ULONG64
, VarI8FromUI8
, I8_MAX
)
226 SIMPLE(ULONG64
, BYTE
, VarUI8FromUI1
)
227 NEGTST(ULONG64
, SHORT
, VarUI8FromI2
)
228 NEGTST(ULONG64
, signed char, VarUI8FromI1
)
229 SIMPLE(ULONG64
, USHORT
, VarUI8FromUI2
)
230 SIMPLE(ULONG64
, ULONG
, VarUI8FromUI4
)
231 NEGTST(ULONG64
, LONG64
, VarUI8FromI8
)
234 SIMPLE(float, BYTE
, VarR4FromUI1
)
235 SIMPLE(float, SHORT
, VarR4FromI2
)
236 SIMPLE(float, signed char, VarR4FromI1
)
237 SIMPLE(float, USHORT
, VarR4FromUI2
)
238 SIMPLE(float, LONG
, VarR4FromI4
)
239 SIMPLE(float, ULONG
, VarR4FromUI4
)
240 SIMPLE(float, LONG64
, VarR4FromI8
)
241 SIMPLE(float, ULONG64
, VarR4FromUI8
)
244 SIMPLE(double, BYTE
, VarR8FromUI1
)
245 SIMPLE(double, SHORT
, VarR8FromI2
)
246 SIMPLE(double, float, VarR8FromR4
)
247 RETTYP
_VarR8FromCy(CY i
, double* o
) { *o
= (double)i
.int64
/ CY_MULTIPLIER_F
; return S_OK
; }
248 SIMPLE(double, DATE
, VarR8FromDate
)
249 SIMPLE(double, signed char, VarR8FromI1
)
250 SIMPLE(double, USHORT
, VarR8FromUI2
)
251 SIMPLE(double, LONG
, VarR8FromI4
)
252 SIMPLE(double, ULONG
, VarR8FromUI4
)
253 SIMPLE(double, LONG64
, VarR8FromI8
)
254 SIMPLE(double, ULONG64
, VarR8FromUI8
)
260 /************************************************************************
261 * VarI1FromUI1 (OLEAUT32.244)
263 * Convert a VT_UI1 to a VT_I1.
267 * pcOut [O] Destination
271 * Failure: E_INVALIDARG, if the source value is invalid
272 * DISP_E_OVERFLOW, if the value will not fit in the destination
274 HRESULT WINAPI
VarI1FromUI1(BYTE bIn
, signed char* pcOut
)
276 return _VarI1FromUI1(bIn
, pcOut
);
279 /************************************************************************
280 * VarI1FromI2 (OLEAUT32.245)
282 * Convert a VT_I2 to a VT_I1.
286 * pcOut [O] Destination
290 * Failure: E_INVALIDARG, if the source value is invalid
291 * DISP_E_OVERFLOW, if the value will not fit in the destination
293 HRESULT WINAPI
VarI1FromI2(SHORT sIn
, signed char* pcOut
)
295 return _VarI1FromI2(sIn
, pcOut
);
298 /************************************************************************
299 * VarI1FromI4 (OLEAUT32.246)
301 * Convert a VT_I4 to a VT_I1.
305 * pcOut [O] Destination
309 * Failure: E_INVALIDARG, if the source value is invalid
310 * DISP_E_OVERFLOW, if the value will not fit in the destination
312 HRESULT WINAPI
VarI1FromI4(LONG iIn
, signed char* pcOut
)
314 return _VarI1FromI4(iIn
, pcOut
);
317 /************************************************************************
318 * VarI1FromR4 (OLEAUT32.247)
320 * Convert a VT_R4 to a VT_I1.
324 * pcOut [O] Destination
328 * Failure: E_INVALIDARG, if the source value is invalid
329 * DISP_E_OVERFLOW, if the value will not fit in the destination
331 HRESULT WINAPI
VarI1FromR4(FLOAT fltIn
, signed char* pcOut
)
333 return VarI1FromR8(fltIn
, pcOut
);
336 /************************************************************************
337 * VarI1FromR8 (OLEAUT32.248)
339 * Convert a VT_R8 to a VT_I1.
343 * pcOut [O] Destination
347 * Failure: E_INVALIDARG, if the source value is invalid
348 * DISP_E_OVERFLOW, if the value will not fit in the destination
351 * See VarI8FromR8() for details concerning rounding.
353 HRESULT WINAPI
VarI1FromR8(double dblIn
, signed char* pcOut
)
355 if (dblIn
< I1_MIN
- 0.5 || dblIn
>= I1_MAX
+ 0.5)
356 return DISP_E_OVERFLOW
;
357 VARIANT_DutchRound(CHAR
, dblIn
, *pcOut
);
361 /************************************************************************
362 * VarI1FromDate (OLEAUT32.249)
364 * Convert a VT_DATE to a VT_I1.
368 * pcOut [O] Destination
372 * Failure: E_INVALIDARG, if the source value is invalid
373 * DISP_E_OVERFLOW, if the value will not fit in the destination
375 HRESULT WINAPI
VarI1FromDate(DATE dateIn
, signed char* pcOut
)
377 return VarI1FromR8(dateIn
, pcOut
);
380 /************************************************************************
381 * VarI1FromCy (OLEAUT32.250)
383 * Convert a VT_CY to a VT_I1.
387 * pcOut [O] Destination
391 * Failure: E_INVALIDARG, if the source value is invalid
392 * DISP_E_OVERFLOW, if the value will not fit in the destination
394 HRESULT WINAPI
VarI1FromCy(CY cyIn
, signed char* pcOut
)
398 VarI4FromCy(cyIn
, &i
);
399 return _VarI1FromI4(i
, pcOut
);
402 /************************************************************************
403 * VarI1FromStr (OLEAUT32.251)
405 * Convert a VT_BSTR to a VT_I1.
409 * lcid [I] LCID for the conversion
410 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
411 * pcOut [O] Destination
415 * Failure: E_INVALIDARG, if the source value is invalid
416 * DISP_E_OVERFLOW, if the value will not fit in the destination
417 * DISP_E_TYPEMISMATCH, if the type cannot be converted
419 HRESULT WINAPI
VarI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, signed char* pcOut
)
421 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pcOut
, VT_I1
);
424 /************************************************************************
425 * VarI1FromDisp (OLEAUT32.252)
427 * Convert a VT_DISPATCH to a VT_I1.
431 * lcid [I] LCID for conversion
432 * pcOut [O] Destination
436 * Failure: E_INVALIDARG, if the source value is invalid
437 * DISP_E_OVERFLOW, if the value will not fit in the destination
438 * DISP_E_TYPEMISMATCH, if the type cannot be converted
440 HRESULT WINAPI
VarI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, signed char* pcOut
)
442 return VARIANT_FromDisp(pdispIn
, lcid
, pcOut
, VT_I1
, 0);
445 /************************************************************************
446 * VarI1FromBool (OLEAUT32.253)
448 * Convert a VT_BOOL to a VT_I1.
452 * pcOut [O] Destination
457 HRESULT WINAPI
VarI1FromBool(VARIANT_BOOL boolIn
, signed char* pcOut
)
459 return _VarI1FromBool(boolIn
, pcOut
);
462 /************************************************************************
463 * VarI1FromUI2 (OLEAUT32.254)
465 * Convert a VT_UI2 to a VT_I1.
469 * pcOut [O] Destination
473 * Failure: E_INVALIDARG, if the source value is invalid
474 * DISP_E_OVERFLOW, if the value will not fit in the destination
476 HRESULT WINAPI
VarI1FromUI2(USHORT usIn
, signed char* pcOut
)
478 return _VarI1FromUI2(usIn
, pcOut
);
481 /************************************************************************
482 * VarI1FromUI4 (OLEAUT32.255)
484 * Convert a VT_UI4 to a VT_I1.
488 * pcOut [O] Destination
492 * Failure: E_INVALIDARG, if the source value is invalid
493 * DISP_E_OVERFLOW, if the value will not fit in the destination
494 * DISP_E_TYPEMISMATCH, if the type cannot be converted
496 HRESULT WINAPI
VarI1FromUI4(ULONG ulIn
, signed char* pcOut
)
498 return _VarI1FromUI4(ulIn
, pcOut
);
501 /************************************************************************
502 * VarI1FromDec (OLEAUT32.256)
504 * Convert a VT_DECIMAL to a VT_I1.
508 * pcOut [O] Destination
512 * Failure: E_INVALIDARG, if the source value is invalid
513 * DISP_E_OVERFLOW, if the value will not fit in the destination
515 HRESULT WINAPI
VarI1FromDec(DECIMAL
*pdecIn
, signed char* pcOut
)
520 hRet
= VarI8FromDec(pdecIn
, &i64
);
523 hRet
= _VarI1FromI8(i64
, pcOut
);
527 /************************************************************************
528 * VarI1FromI8 (OLEAUT32.376)
530 * Convert a VT_I8 to a VT_I1.
534 * pcOut [O] Destination
538 * Failure: E_INVALIDARG, if the source value is invalid
539 * DISP_E_OVERFLOW, if the value will not fit in the destination
541 HRESULT WINAPI
VarI1FromI8(LONG64 llIn
, signed char* pcOut
)
543 return _VarI1FromI8(llIn
, pcOut
);
546 /************************************************************************
547 * VarI1FromUI8 (OLEAUT32.377)
549 * Convert a VT_UI8 to a VT_I1.
553 * pcOut [O] Destination
557 * Failure: E_INVALIDARG, if the source value is invalid
558 * DISP_E_OVERFLOW, if the value will not fit in the destination
560 HRESULT WINAPI
VarI1FromUI8(ULONG64 ullIn
, signed char* pcOut
)
562 return _VarI1FromUI8(ullIn
, pcOut
);
568 /************************************************************************
569 * VarUI1FromI2 (OLEAUT32.130)
571 * Convert a VT_I2 to a VT_UI1.
575 * pbOut [O] Destination
579 * Failure: E_INVALIDARG, if the source value is invalid
580 * DISP_E_OVERFLOW, if the value will not fit in the destination
582 HRESULT WINAPI
VarUI1FromI2(SHORT sIn
, BYTE
* pbOut
)
584 return _VarUI1FromI2(sIn
, pbOut
);
587 /************************************************************************
588 * VarUI1FromI4 (OLEAUT32.131)
590 * Convert a VT_I4 to a VT_UI1.
594 * pbOut [O] Destination
598 * Failure: E_INVALIDARG, if the source value is invalid
599 * DISP_E_OVERFLOW, if the value will not fit in the destination
601 HRESULT WINAPI
VarUI1FromI4(LONG iIn
, BYTE
* pbOut
)
603 return _VarUI1FromI4(iIn
, pbOut
);
606 /************************************************************************
607 * VarUI1FromR4 (OLEAUT32.132)
609 * Convert a VT_R4 to a VT_UI1.
613 * pbOut [O] Destination
617 * Failure: E_INVALIDARG, if the source value is invalid
618 * DISP_E_OVERFLOW, if the value will not fit in the destination
619 * DISP_E_TYPEMISMATCH, if the type cannot be converted
621 HRESULT WINAPI
VarUI1FromR4(FLOAT fltIn
, BYTE
* pbOut
)
623 return VarUI1FromR8(fltIn
, pbOut
);
626 /************************************************************************
627 * VarUI1FromR8 (OLEAUT32.133)
629 * Convert a VT_R8 to a VT_UI1.
633 * pbOut [O] Destination
637 * Failure: E_INVALIDARG, if the source value is invalid
638 * DISP_E_OVERFLOW, if the value will not fit in the destination
641 * See VarI8FromR8() for details concerning rounding.
643 HRESULT WINAPI
VarUI1FromR8(double dblIn
, BYTE
* pbOut
)
645 if (dblIn
< -0.5 || dblIn
>= UI1_MAX
+ 0.5)
646 return DISP_E_OVERFLOW
;
647 VARIANT_DutchRound(BYTE
, dblIn
, *pbOut
);
651 /************************************************************************
652 * VarUI1FromCy (OLEAUT32.134)
654 * Convert a VT_CY to a VT_UI1.
658 * pbOut [O] Destination
662 * Failure: E_INVALIDARG, if the source value is invalid
663 * DISP_E_OVERFLOW, if the value will not fit in the destination
666 * Negative values >= -5000 will be converted to 0.
668 HRESULT WINAPI
VarUI1FromCy(CY cyIn
, BYTE
* pbOut
)
670 ULONG i
= UI1_MAX
+ 1;
672 VarUI4FromCy(cyIn
, &i
);
673 return _VarUI1FromUI4(i
, pbOut
);
676 /************************************************************************
677 * VarUI1FromDate (OLEAUT32.135)
679 * Convert a VT_DATE to a VT_UI1.
683 * pbOut [O] Destination
687 * Failure: E_INVALIDARG, if the source value is invalid
688 * DISP_E_OVERFLOW, if the value will not fit in the destination
690 HRESULT WINAPI
VarUI1FromDate(DATE dateIn
, BYTE
* pbOut
)
692 return VarUI1FromR8(dateIn
, pbOut
);
695 /************************************************************************
696 * VarUI1FromStr (OLEAUT32.136)
698 * Convert a VT_BSTR to a VT_UI1.
702 * lcid [I] LCID for the conversion
703 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
704 * pbOut [O] Destination
708 * Failure: E_INVALIDARG, if the source value is invalid
709 * DISP_E_OVERFLOW, if the value will not fit in the destination
710 * DISP_E_TYPEMISMATCH, if the type cannot be converted
712 HRESULT WINAPI
VarUI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, BYTE
* pbOut
)
714 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pbOut
, VT_UI1
);
717 /************************************************************************
718 * VarUI1FromDisp (OLEAUT32.137)
720 * Convert a VT_DISPATCH to a VT_UI1.
724 * lcid [I] LCID for conversion
725 * pbOut [O] Destination
729 * Failure: E_INVALIDARG, if the source value is invalid
730 * DISP_E_OVERFLOW, if the value will not fit in the destination
731 * DISP_E_TYPEMISMATCH, if the type cannot be converted
733 HRESULT WINAPI
VarUI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, BYTE
* pbOut
)
735 return VARIANT_FromDisp(pdispIn
, lcid
, pbOut
, VT_UI1
, 0);
738 /************************************************************************
739 * VarUI1FromBool (OLEAUT32.138)
741 * Convert a VT_BOOL to a VT_UI1.
745 * pbOut [O] Destination
750 HRESULT WINAPI
VarUI1FromBool(VARIANT_BOOL boolIn
, BYTE
* pbOut
)
752 return _VarUI1FromBool(boolIn
, pbOut
);
755 /************************************************************************
756 * VarUI1FromI1 (OLEAUT32.237)
758 * Convert a VT_I1 to a VT_UI1.
762 * pbOut [O] Destination
766 * Failure: E_INVALIDARG, if the source value is invalid
767 * DISP_E_OVERFLOW, if the value will not fit in the destination
769 HRESULT WINAPI
VarUI1FromI1(signed char cIn
, BYTE
* pbOut
)
771 return _VarUI1FromI1(cIn
, pbOut
);
774 /************************************************************************
775 * VarUI1FromUI2 (OLEAUT32.238)
777 * Convert a VT_UI2 to a VT_UI1.
781 * pbOut [O] Destination
785 * Failure: E_INVALIDARG, if the source value is invalid
786 * DISP_E_OVERFLOW, if the value will not fit in the destination
788 HRESULT WINAPI
VarUI1FromUI2(USHORT usIn
, BYTE
* pbOut
)
790 return _VarUI1FromUI2(usIn
, pbOut
);
793 /************************************************************************
794 * VarUI1FromUI4 (OLEAUT32.239)
796 * Convert a VT_UI4 to a VT_UI1.
800 * pbOut [O] Destination
804 * Failure: E_INVALIDARG, if the source value is invalid
805 * DISP_E_OVERFLOW, if the value will not fit in the destination
807 HRESULT WINAPI
VarUI1FromUI4(ULONG ulIn
, BYTE
* pbOut
)
809 return _VarUI1FromUI4(ulIn
, pbOut
);
812 /************************************************************************
813 * VarUI1FromDec (OLEAUT32.240)
815 * Convert a VT_DECIMAL to a VT_UI1.
819 * pbOut [O] Destination
823 * Failure: E_INVALIDARG, if the source value is invalid
824 * DISP_E_OVERFLOW, if the value will not fit in the destination
826 HRESULT WINAPI
VarUI1FromDec(DECIMAL
*pdecIn
, BYTE
* pbOut
)
831 hRet
= VarI8FromDec(pdecIn
, &i64
);
834 hRet
= _VarUI1FromI8(i64
, pbOut
);
838 /************************************************************************
839 * VarUI1FromI8 (OLEAUT32.372)
841 * Convert a VT_I8 to a VT_UI1.
845 * pbOut [O] Destination
849 * Failure: E_INVALIDARG, if the source value is invalid
850 * DISP_E_OVERFLOW, if the value will not fit in the destination
852 HRESULT WINAPI
VarUI1FromI8(LONG64 llIn
, BYTE
* pbOut
)
854 return _VarUI1FromI8(llIn
, pbOut
);
857 /************************************************************************
858 * VarUI1FromUI8 (OLEAUT32.373)
860 * Convert a VT_UI8 to a VT_UI1.
864 * pbOut [O] Destination
868 * Failure: E_INVALIDARG, if the source value is invalid
869 * DISP_E_OVERFLOW, if the value will not fit in the destination
871 HRESULT WINAPI
VarUI1FromUI8(ULONG64 ullIn
, BYTE
* pbOut
)
873 return _VarUI1FromUI8(ullIn
, pbOut
);
880 /************************************************************************
881 * VarI2FromUI1 (OLEAUT32.48)
883 * Convert a VT_UI2 to a VT_I2.
887 * psOut [O] Destination
892 HRESULT WINAPI
VarI2FromUI1(BYTE bIn
, SHORT
* psOut
)
894 return _VarI2FromUI1(bIn
, psOut
);
897 /************************************************************************
898 * VarI2FromI4 (OLEAUT32.49)
900 * Convert a VT_I4 to a VT_I2.
904 * psOut [O] Destination
908 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
910 HRESULT WINAPI
VarI2FromI4(LONG iIn
, SHORT
* psOut
)
912 return _VarI2FromI4(iIn
, psOut
);
915 /************************************************************************
916 * VarI2FromR4 (OLEAUT32.50)
918 * Convert a VT_R4 to a VT_I2.
922 * psOut [O] Destination
926 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
928 HRESULT WINAPI
VarI2FromR4(FLOAT fltIn
, SHORT
* psOut
)
930 return VarI2FromR8(fltIn
, psOut
);
933 /************************************************************************
934 * VarI2FromR8 (OLEAUT32.51)
936 * Convert a VT_R8 to a VT_I2.
940 * psOut [O] Destination
944 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
947 * See VarI8FromR8() for details concerning rounding.
949 HRESULT WINAPI
VarI2FromR8(double dblIn
, SHORT
* psOut
)
951 if (dblIn
< I2_MIN
- 0.5 || dblIn
>= I2_MAX
+ 0.5)
952 return DISP_E_OVERFLOW
;
953 VARIANT_DutchRound(SHORT
, dblIn
, *psOut
);
957 /************************************************************************
958 * VarI2FromCy (OLEAUT32.52)
960 * Convert a VT_CY to a VT_I2.
964 * psOut [O] Destination
968 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
970 HRESULT WINAPI
VarI2FromCy(CY cyIn
, SHORT
* psOut
)
974 VarI4FromCy(cyIn
, &i
);
975 return _VarI2FromI4(i
, psOut
);
978 /************************************************************************
979 * VarI2FromDate (OLEAUT32.53)
981 * Convert a VT_DATE to a VT_I2.
985 * psOut [O] Destination
989 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
991 HRESULT WINAPI
VarI2FromDate(DATE dateIn
, SHORT
* psOut
)
993 return VarI2FromR8(dateIn
, psOut
);
996 /************************************************************************
997 * VarI2FromStr (OLEAUT32.54)
999 * Convert a VT_BSTR to a VT_I2.
1003 * lcid [I] LCID for the conversion
1004 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1005 * psOut [O] Destination
1009 * Failure: E_INVALIDARG, if any parameter is invalid
1010 * DISP_E_OVERFLOW, if the value will not fit in the destination
1011 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1013 HRESULT WINAPI
VarI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, SHORT
* psOut
)
1015 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, psOut
, VT_I2
);
1018 /************************************************************************
1019 * VarI2FromDisp (OLEAUT32.55)
1021 * Convert a VT_DISPATCH to a VT_I2.
1024 * pdispIn [I] Source
1025 * lcid [I] LCID for conversion
1026 * psOut [O] Destination
1030 * Failure: E_INVALIDARG, if pdispIn is invalid,
1031 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1032 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1034 HRESULT WINAPI
VarI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, SHORT
* psOut
)
1036 return VARIANT_FromDisp(pdispIn
, lcid
, psOut
, VT_I2
, 0);
1039 /************************************************************************
1040 * VarI2FromBool (OLEAUT32.56)
1042 * Convert a VT_BOOL to a VT_I2.
1046 * psOut [O] Destination
1051 HRESULT WINAPI
VarI2FromBool(VARIANT_BOOL boolIn
, SHORT
* psOut
)
1053 return _VarI2FromBool(boolIn
, psOut
);
1056 /************************************************************************
1057 * VarI2FromI1 (OLEAUT32.205)
1059 * Convert a VT_I1 to a VT_I2.
1063 * psOut [O] Destination
1068 HRESULT WINAPI
VarI2FromI1(signed char cIn
, SHORT
* psOut
)
1070 return _VarI2FromI1(cIn
, psOut
);
1073 /************************************************************************
1074 * VarI2FromUI2 (OLEAUT32.206)
1076 * Convert a VT_UI2 to a VT_I2.
1080 * psOut [O] Destination
1084 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1086 HRESULT WINAPI
VarI2FromUI2(USHORT usIn
, SHORT
* psOut
)
1088 return _VarI2FromUI2(usIn
, psOut
);
1091 /************************************************************************
1092 * VarI2FromUI4 (OLEAUT32.207)
1094 * Convert a VT_UI4 to a VT_I2.
1098 * psOut [O] Destination
1102 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1104 HRESULT WINAPI
VarI2FromUI4(ULONG ulIn
, SHORT
* psOut
)
1106 return _VarI2FromUI4(ulIn
, psOut
);
1109 /************************************************************************
1110 * VarI2FromDec (OLEAUT32.208)
1112 * Convert a VT_DECIMAL to a VT_I2.
1116 * psOut [O] Destination
1120 * Failure: E_INVALIDARG, if the source value is invalid
1121 * DISP_E_OVERFLOW, if the value will not fit in the destination
1123 HRESULT WINAPI
VarI2FromDec(DECIMAL
*pdecIn
, SHORT
* psOut
)
1128 hRet
= VarI8FromDec(pdecIn
, &i64
);
1130 if (SUCCEEDED(hRet
))
1131 hRet
= _VarI2FromI8(i64
, psOut
);
1135 /************************************************************************
1136 * VarI2FromI8 (OLEAUT32.346)
1138 * Convert a VT_I8 to a VT_I2.
1142 * psOut [O] Destination
1146 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1148 HRESULT WINAPI
VarI2FromI8(LONG64 llIn
, SHORT
* psOut
)
1150 return _VarI2FromI8(llIn
, psOut
);
1153 /************************************************************************
1154 * VarI2FromUI8 (OLEAUT32.347)
1156 * Convert a VT_UI8 to a VT_I2.
1160 * psOut [O] Destination
1164 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1166 HRESULT WINAPI
VarI2FromUI8(ULONG64 ullIn
, SHORT
* psOut
)
1168 return _VarI2FromUI8(ullIn
, psOut
);
1174 /************************************************************************
1175 * VarUI2FromUI1 (OLEAUT32.257)
1177 * Convert a VT_UI1 to a VT_UI2.
1181 * pusOut [O] Destination
1186 HRESULT WINAPI
VarUI2FromUI1(BYTE bIn
, USHORT
* pusOut
)
1188 return _VarUI2FromUI1(bIn
, pusOut
);
1191 /************************************************************************
1192 * VarUI2FromI2 (OLEAUT32.258)
1194 * Convert a VT_I2 to a VT_UI2.
1198 * pusOut [O] Destination
1202 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1204 HRESULT WINAPI
VarUI2FromI2(SHORT sIn
, USHORT
* pusOut
)
1206 return _VarUI2FromI2(sIn
, pusOut
);
1209 /************************************************************************
1210 * VarUI2FromI4 (OLEAUT32.259)
1212 * Convert a VT_I4 to a VT_UI2.
1216 * pusOut [O] Destination
1220 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1222 HRESULT WINAPI
VarUI2FromI4(LONG iIn
, USHORT
* pusOut
)
1224 return _VarUI2FromI4(iIn
, pusOut
);
1227 /************************************************************************
1228 * VarUI2FromR4 (OLEAUT32.260)
1230 * Convert a VT_R4 to a VT_UI2.
1234 * pusOut [O] Destination
1238 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1240 HRESULT WINAPI
VarUI2FromR4(FLOAT fltIn
, USHORT
* pusOut
)
1242 return VarUI2FromR8(fltIn
, pusOut
);
1245 /************************************************************************
1246 * VarUI2FromR8 (OLEAUT32.261)
1248 * Convert a VT_R8 to a VT_UI2.
1252 * pusOut [O] Destination
1256 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1259 * See VarI8FromR8() for details concerning rounding.
1261 HRESULT WINAPI
VarUI2FromR8(double dblIn
, USHORT
* pusOut
)
1263 if (dblIn
< -0.5 || dblIn
>= UI2_MAX
+ 0.5)
1264 return DISP_E_OVERFLOW
;
1265 VARIANT_DutchRound(USHORT
, dblIn
, *pusOut
);
1269 /************************************************************************
1270 * VarUI2FromDate (OLEAUT32.262)
1272 * Convert a VT_DATE to a VT_UI2.
1276 * pusOut [O] Destination
1280 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1282 HRESULT WINAPI
VarUI2FromDate(DATE dateIn
, USHORT
* pusOut
)
1284 return VarUI2FromR8(dateIn
, pusOut
);
1287 /************************************************************************
1288 * VarUI2FromCy (OLEAUT32.263)
1290 * Convert a VT_CY to a VT_UI2.
1294 * pusOut [O] Destination
1298 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1301 * Negative values >= -5000 will be converted to 0.
1303 HRESULT WINAPI
VarUI2FromCy(CY cyIn
, USHORT
* pusOut
)
1305 ULONG i
= UI2_MAX
+ 1;
1307 VarUI4FromCy(cyIn
, &i
);
1308 return _VarUI2FromUI4(i
, pusOut
);
1311 /************************************************************************
1312 * VarUI2FromStr (OLEAUT32.264)
1314 * Convert a VT_BSTR to a VT_UI2.
1318 * lcid [I] LCID for the conversion
1319 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1320 * pusOut [O] Destination
1324 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1325 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1327 HRESULT WINAPI
VarUI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, USHORT
* pusOut
)
1329 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pusOut
, VT_UI2
);
1332 /************************************************************************
1333 * VarUI2FromDisp (OLEAUT32.265)
1335 * Convert a VT_DISPATCH to a VT_UI2.
1338 * pdispIn [I] Source
1339 * lcid [I] LCID for conversion
1340 * pusOut [O] Destination
1344 * Failure: E_INVALIDARG, if the source value is invalid
1345 * DISP_E_OVERFLOW, if the value will not fit in the destination
1346 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1348 HRESULT WINAPI
VarUI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, USHORT
* pusOut
)
1350 return VARIANT_FromDisp(pdispIn
, lcid
, pusOut
, VT_UI2
, 0);
1353 /************************************************************************
1354 * VarUI2FromBool (OLEAUT32.266)
1356 * Convert a VT_BOOL to a VT_UI2.
1360 * pusOut [O] Destination
1365 HRESULT WINAPI
VarUI2FromBool(VARIANT_BOOL boolIn
, USHORT
* pusOut
)
1367 return _VarUI2FromBool(boolIn
, pusOut
);
1370 /************************************************************************
1371 * VarUI2FromI1 (OLEAUT32.267)
1373 * Convert a VT_I1 to a VT_UI2.
1377 * pusOut [O] Destination
1381 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1383 HRESULT WINAPI
VarUI2FromI1(signed char cIn
, USHORT
* pusOut
)
1385 return _VarUI2FromI1(cIn
, pusOut
);
1388 /************************************************************************
1389 * VarUI2FromUI4 (OLEAUT32.268)
1391 * Convert a VT_UI4 to a VT_UI2.
1395 * pusOut [O] Destination
1399 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1401 HRESULT WINAPI
VarUI2FromUI4(ULONG ulIn
, USHORT
* pusOut
)
1403 return _VarUI2FromUI4(ulIn
, pusOut
);
1406 /************************************************************************
1407 * VarUI2FromDec (OLEAUT32.269)
1409 * Convert a VT_DECIMAL to a VT_UI2.
1413 * pusOut [O] Destination
1417 * Failure: E_INVALIDARG, if the source value is invalid
1418 * DISP_E_OVERFLOW, if the value will not fit in the destination
1420 HRESULT WINAPI
VarUI2FromDec(DECIMAL
*pdecIn
, USHORT
* pusOut
)
1425 hRet
= VarI8FromDec(pdecIn
, &i64
);
1427 if (SUCCEEDED(hRet
))
1428 hRet
= _VarUI2FromI8(i64
, pusOut
);
1432 /************************************************************************
1433 * VarUI2FromI8 (OLEAUT32.378)
1435 * Convert a VT_I8 to a VT_UI2.
1439 * pusOut [O] Destination
1443 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1445 HRESULT WINAPI
VarUI2FromI8(LONG64 llIn
, USHORT
* pusOut
)
1447 return _VarUI2FromI8(llIn
, pusOut
);
1450 /************************************************************************
1451 * VarUI2FromUI8 (OLEAUT32.379)
1453 * Convert a VT_UI8 to a VT_UI2.
1457 * pusOut [O] Destination
1461 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1463 HRESULT WINAPI
VarUI2FromUI8(ULONG64 ullIn
, USHORT
* pusOut
)
1465 return _VarUI2FromUI8(ullIn
, pusOut
);
1471 /************************************************************************
1472 * VarI4FromUI1 (OLEAUT32.58)
1474 * Convert a VT_UI1 to a VT_I4.
1478 * piOut [O] Destination
1483 HRESULT WINAPI
VarI4FromUI1(BYTE bIn
, LONG
*piOut
)
1485 return _VarI4FromUI1(bIn
, piOut
);
1488 /************************************************************************
1489 * VarI4FromI2 (OLEAUT32.59)
1491 * Convert a VT_I2 to a VT_I4.
1495 * piOut [O] Destination
1499 * Failure: E_INVALIDARG, if the source value is invalid
1500 * DISP_E_OVERFLOW, if the value will not fit in the destination
1502 HRESULT WINAPI
VarI4FromI2(SHORT sIn
, LONG
*piOut
)
1504 return _VarI4FromI2(sIn
, piOut
);
1507 /************************************************************************
1508 * VarI4FromR4 (OLEAUT32.60)
1510 * Convert a VT_R4 to a VT_I4.
1514 * piOut [O] Destination
1518 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1520 HRESULT WINAPI
VarI4FromR4(FLOAT fltIn
, LONG
*piOut
)
1522 return VarI4FromR8(fltIn
, piOut
);
1525 /************************************************************************
1526 * VarI4FromR8 (OLEAUT32.61)
1528 * Convert a VT_R8 to a VT_I4.
1532 * piOut [O] Destination
1536 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1539 * See VarI8FromR8() for details concerning rounding.
1541 HRESULT WINAPI
VarI4FromR8(double dblIn
, LONG
*piOut
)
1543 if (dblIn
< I4_MIN
- 0.5 || dblIn
>= I4_MAX
+ 0.5)
1544 return DISP_E_OVERFLOW
;
1545 VARIANT_DutchRound(LONG
, dblIn
, *piOut
);
1549 /************************************************************************
1550 * VarI4FromCy (OLEAUT32.62)
1552 * Convert a VT_CY to a VT_I4.
1556 * piOut [O] Destination
1560 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1562 HRESULT WINAPI
VarI4FromCy(CY cyIn
, LONG
*piOut
)
1564 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1565 return VarI4FromR8(d
, piOut
);
1568 /************************************************************************
1569 * VarI4FromDate (OLEAUT32.63)
1571 * Convert a VT_DATE to a VT_I4.
1575 * piOut [O] Destination
1579 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1581 HRESULT WINAPI
VarI4FromDate(DATE dateIn
, LONG
*piOut
)
1583 return VarI4FromR8(dateIn
, piOut
);
1586 /************************************************************************
1587 * VarI4FromStr (OLEAUT32.64)
1589 * Convert a VT_BSTR to a VT_I4.
1593 * lcid [I] LCID for the conversion
1594 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1595 * piOut [O] Destination
1599 * Failure: E_INVALIDARG, if any parameter is invalid
1600 * DISP_E_OVERFLOW, if the value will not fit in the destination
1601 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1603 HRESULT WINAPI
VarI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG
*piOut
)
1605 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, piOut
, VT_I4
);
1608 /************************************************************************
1609 * VarI4FromDisp (OLEAUT32.65)
1611 * Convert a VT_DISPATCH to a VT_I4.
1614 * pdispIn [I] Source
1615 * lcid [I] LCID for conversion
1616 * piOut [O] Destination
1620 * Failure: E_INVALIDARG, if the source value is invalid
1621 * DISP_E_OVERFLOW, if the value will not fit in the destination
1622 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1624 HRESULT WINAPI
VarI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG
*piOut
)
1626 return VARIANT_FromDisp(pdispIn
, lcid
, piOut
, VT_I4
, 0);
1629 /************************************************************************
1630 * VarI4FromBool (OLEAUT32.66)
1632 * Convert a VT_BOOL to a VT_I4.
1636 * piOut [O] Destination
1641 HRESULT WINAPI
VarI4FromBool(VARIANT_BOOL boolIn
, LONG
*piOut
)
1643 return _VarI4FromBool(boolIn
, piOut
);
1646 /************************************************************************
1647 * VarI4FromI1 (OLEAUT32.209)
1649 * Convert a VT_I1 to a VT_I4.
1653 * piOut [O] Destination
1658 HRESULT WINAPI
VarI4FromI1(signed char cIn
, LONG
*piOut
)
1660 return _VarI4FromI1(cIn
, piOut
);
1663 /************************************************************************
1664 * VarI4FromUI2 (OLEAUT32.210)
1666 * Convert a VT_UI2 to a VT_I4.
1670 * piOut [O] Destination
1675 HRESULT WINAPI
VarI4FromUI2(USHORT usIn
, LONG
*piOut
)
1677 return _VarI4FromUI2(usIn
, piOut
);
1680 /************************************************************************
1681 * VarI4FromUI4 (OLEAUT32.211)
1683 * Convert a VT_UI4 to a VT_I4.
1687 * piOut [O] Destination
1691 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1693 HRESULT WINAPI
VarI4FromUI4(ULONG ulIn
, LONG
*piOut
)
1695 return _VarI4FromUI4(ulIn
, piOut
);
1698 /************************************************************************
1699 * VarI4FromDec (OLEAUT32.212)
1701 * Convert a VT_DECIMAL to a VT_I4.
1705 * piOut [O] Destination
1709 * Failure: E_INVALIDARG, if pdecIn is invalid
1710 * DISP_E_OVERFLOW, if the value will not fit in the destination
1712 HRESULT WINAPI
VarI4FromDec(DECIMAL
*pdecIn
, LONG
*piOut
)
1717 hRet
= VarI8FromDec(pdecIn
, &i64
);
1719 if (SUCCEEDED(hRet
))
1720 hRet
= _VarI4FromI8(i64
, piOut
);
1724 /************************************************************************
1725 * VarI4FromI8 (OLEAUT32.348)
1727 * Convert a VT_I8 to a VT_I4.
1731 * piOut [O] Destination
1735 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1737 HRESULT WINAPI
VarI4FromI8(LONG64 llIn
, LONG
*piOut
)
1739 return _VarI4FromI8(llIn
, piOut
);
1742 /************************************************************************
1743 * VarI4FromUI8 (OLEAUT32.349)
1745 * Convert a VT_UI8 to a VT_I4.
1749 * piOut [O] Destination
1753 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1755 HRESULT WINAPI
VarI4FromUI8(ULONG64 ullIn
, LONG
*piOut
)
1757 return _VarI4FromUI8(ullIn
, piOut
);
1763 /************************************************************************
1764 * VarUI4FromUI1 (OLEAUT32.270)
1766 * Convert a VT_UI1 to a VT_UI4.
1770 * pulOut [O] Destination
1775 HRESULT WINAPI
VarUI4FromUI1(BYTE bIn
, ULONG
*pulOut
)
1777 return _VarUI4FromUI1(bIn
, pulOut
);
1780 /************************************************************************
1781 * VarUI4FromI2 (OLEAUT32.271)
1783 * Convert a VT_I2 to a VT_UI4.
1787 * pulOut [O] Destination
1791 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1793 HRESULT WINAPI
VarUI4FromI2(SHORT sIn
, ULONG
*pulOut
)
1795 return _VarUI4FromI2(sIn
, pulOut
);
1798 /************************************************************************
1799 * VarUI4FromI4 (OLEAUT32.272)
1801 * Convert a VT_I4 to a VT_UI4.
1805 * pulOut [O] Destination
1809 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1811 HRESULT WINAPI
VarUI4FromI4(LONG iIn
, ULONG
*pulOut
)
1813 return _VarUI4FromI4(iIn
, pulOut
);
1816 /************************************************************************
1817 * VarUI4FromR4 (OLEAUT32.273)
1819 * Convert a VT_R4 to a VT_UI4.
1823 * pulOut [O] Destination
1827 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1829 HRESULT WINAPI
VarUI4FromR4(FLOAT fltIn
, ULONG
*pulOut
)
1831 return VarUI4FromR8(fltIn
, pulOut
);
1834 /************************************************************************
1835 * VarUI4FromR8 (OLEAUT32.274)
1837 * Convert a VT_R8 to a VT_UI4.
1841 * pulOut [O] Destination
1845 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1848 * See VarI8FromR8() for details concerning rounding.
1850 HRESULT WINAPI
VarUI4FromR8(double dblIn
, ULONG
*pulOut
)
1852 if (dblIn
< -0.5 || dblIn
>= UI4_MAX
+ 0.5)
1853 return DISP_E_OVERFLOW
;
1854 VARIANT_DutchRound(ULONG
, dblIn
, *pulOut
);
1858 /************************************************************************
1859 * VarUI4FromDate (OLEAUT32.275)
1861 * Convert a VT_DATE to a VT_UI4.
1865 * pulOut [O] Destination
1869 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1871 HRESULT WINAPI
VarUI4FromDate(DATE dateIn
, ULONG
*pulOut
)
1873 return VarUI4FromR8(dateIn
, pulOut
);
1876 /************************************************************************
1877 * VarUI4FromCy (OLEAUT32.276)
1879 * Convert a VT_CY to a VT_UI4.
1883 * pulOut [O] Destination
1887 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1889 HRESULT WINAPI
VarUI4FromCy(CY cyIn
, ULONG
*pulOut
)
1891 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1892 return VarUI4FromR8(d
, pulOut
);
1895 /************************************************************************
1896 * VarUI4FromStr (OLEAUT32.277)
1898 * Convert a VT_BSTR to a VT_UI4.
1902 * lcid [I] LCID for the conversion
1903 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1904 * pulOut [O] Destination
1908 * Failure: E_INVALIDARG, if any parameter is invalid
1909 * DISP_E_OVERFLOW, if the value will not fit in the destination
1910 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1912 HRESULT WINAPI
VarUI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG
*pulOut
)
1914 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pulOut
, VT_UI4
);
1917 /************************************************************************
1918 * VarUI4FromDisp (OLEAUT32.278)
1920 * Convert a VT_DISPATCH to a VT_UI4.
1923 * pdispIn [I] Source
1924 * lcid [I] LCID for conversion
1925 * pulOut [O] Destination
1929 * Failure: E_INVALIDARG, if the source value is invalid
1930 * DISP_E_OVERFLOW, if the value will not fit in the destination
1931 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1933 HRESULT WINAPI
VarUI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG
*pulOut
)
1935 return VARIANT_FromDisp(pdispIn
, lcid
, pulOut
, VT_UI4
, 0);
1938 /************************************************************************
1939 * VarUI4FromBool (OLEAUT32.279)
1941 * Convert a VT_BOOL to a VT_UI4.
1945 * pulOut [O] Destination
1950 HRESULT WINAPI
VarUI4FromBool(VARIANT_BOOL boolIn
, ULONG
*pulOut
)
1952 return _VarUI4FromBool(boolIn
, pulOut
);
1955 /************************************************************************
1956 * VarUI4FromI1 (OLEAUT32.280)
1958 * Convert a VT_I1 to a VT_UI4.
1962 * pulOut [O] Destination
1966 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1968 HRESULT WINAPI
VarUI4FromI1(signed char cIn
, ULONG
*pulOut
)
1970 return _VarUI4FromI1(cIn
, pulOut
);
1973 /************************************************************************
1974 * VarUI4FromUI2 (OLEAUT32.281)
1976 * Convert a VT_UI2 to a VT_UI4.
1980 * pulOut [O] Destination
1985 HRESULT WINAPI
VarUI4FromUI2(USHORT usIn
, ULONG
*pulOut
)
1987 return _VarUI4FromUI2(usIn
, pulOut
);
1990 /************************************************************************
1991 * VarUI4FromDec (OLEAUT32.282)
1993 * Convert a VT_DECIMAL to a VT_UI4.
1997 * pulOut [O] Destination
2001 * Failure: E_INVALIDARG, if pdecIn is invalid
2002 * DISP_E_OVERFLOW, if the value will not fit in the destination
2004 HRESULT WINAPI
VarUI4FromDec(DECIMAL
*pdecIn
, ULONG
*pulOut
)
2009 hRet
= VarI8FromDec(pdecIn
, &i64
);
2011 if (SUCCEEDED(hRet
))
2012 hRet
= _VarUI4FromI8(i64
, pulOut
);
2016 /************************************************************************
2017 * VarUI4FromI8 (OLEAUT32.425)
2019 * Convert a VT_I8 to a VT_UI4.
2023 * pulOut [O] Destination
2027 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2029 HRESULT WINAPI
VarUI4FromI8(LONG64 llIn
, ULONG
*pulOut
)
2031 return _VarUI4FromI8(llIn
, pulOut
);
2034 /************************************************************************
2035 * VarUI4FromUI8 (OLEAUT32.426)
2037 * Convert a VT_UI8 to a VT_UI4.
2041 * pulOut [O] Destination
2045 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2047 HRESULT WINAPI
VarUI4FromUI8(ULONG64 ullIn
, ULONG
*pulOut
)
2049 return _VarUI4FromUI8(ullIn
, pulOut
);
2055 /************************************************************************
2056 * VarI8FromUI1 (OLEAUT32.333)
2058 * Convert a VT_UI1 to a VT_I8.
2062 * pi64Out [O] Destination
2067 HRESULT WINAPI
VarI8FromUI1(BYTE bIn
, LONG64
* pi64Out
)
2069 return _VarI8FromUI1(bIn
, pi64Out
);
2073 /************************************************************************
2074 * VarI8FromI2 (OLEAUT32.334)
2076 * Convert a VT_I2 to a VT_I8.
2080 * pi64Out [O] Destination
2085 HRESULT WINAPI
VarI8FromI2(SHORT sIn
, LONG64
* pi64Out
)
2087 return _VarI8FromI2(sIn
, pi64Out
);
2090 /************************************************************************
2091 * VarI8FromR4 (OLEAUT32.335)
2093 * Convert a VT_R4 to a VT_I8.
2097 * pi64Out [O] Destination
2101 * Failure: E_INVALIDARG, if the source value is invalid
2102 * DISP_E_OVERFLOW, if the value will not fit in the destination
2104 HRESULT WINAPI
VarI8FromR4(FLOAT fltIn
, LONG64
* pi64Out
)
2106 return VarI8FromR8(fltIn
, pi64Out
);
2109 /************************************************************************
2110 * VarI8FromR8 (OLEAUT32.336)
2112 * Convert a VT_R8 to a VT_I8.
2116 * pi64Out [O] Destination
2120 * Failure: E_INVALIDARG, if the source value is invalid
2121 * DISP_E_OVERFLOW, if the value will not fit in the destination
2124 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2125 * very high or low values will not be accurately converted.
2127 * Numbers are rounded using Dutch rounding, as follows:
2129 *| Fractional Part Sign Direction Example
2130 *| --------------- ---- --------- -------
2131 *| < 0.5 + Down 0.4 -> 0.0
2132 *| < 0.5 - Up -0.4 -> 0.0
2133 *| > 0.5 + Up 0.6 -> 1.0
2134 *| < 0.5 - Up -0.6 -> -1.0
2135 *| = 0.5 + Up/Down Down if even, Up if odd
2136 *| = 0.5 - Up/Down Up if even, Down if odd
2138 * This system is often used in supermarkets.
2140 HRESULT WINAPI
VarI8FromR8(double dblIn
, LONG64
* pi64Out
)
2142 if ( dblIn
< -4611686018427387904.0 || dblIn
>= 4611686018427387904.0)
2143 return DISP_E_OVERFLOW
;
2144 VARIANT_DutchRound(LONG64
, dblIn
, *pi64Out
);
2148 /************************************************************************
2149 * VarI8FromCy (OLEAUT32.337)
2151 * Convert a VT_CY to a VT_I8.
2155 * pi64Out [O] Destination
2161 * All negative numbers are rounded down by 1, including those that are
2162 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2163 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2166 HRESULT WINAPI
VarI8FromCy(CY cyIn
, LONG64
* pi64Out
)
2168 *pi64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2171 (*pi64Out
)--; /* Mimic Win32 bug */
2174 cyIn
.int64
-= *pi64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2176 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pi64Out
& 0x1)))
2182 /************************************************************************
2183 * VarI8FromDate (OLEAUT32.338)
2185 * Convert a VT_DATE to a VT_I8.
2189 * pi64Out [O] Destination
2193 * Failure: E_INVALIDARG, if the source value is invalid
2194 * DISP_E_OVERFLOW, if the value will not fit in the destination
2195 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2197 HRESULT WINAPI
VarI8FromDate(DATE dateIn
, LONG64
* pi64Out
)
2199 return VarI8FromR8(dateIn
, pi64Out
);
2202 /************************************************************************
2203 * VarI8FromStr (OLEAUT32.339)
2205 * Convert a VT_BSTR to a VT_I8.
2209 * lcid [I] LCID for the conversion
2210 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2211 * pi64Out [O] Destination
2215 * Failure: E_INVALIDARG, if the source value is invalid
2216 * DISP_E_OVERFLOW, if the value will not fit in the destination
2217 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2219 HRESULT WINAPI
VarI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG64
* pi64Out
)
2221 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pi64Out
, VT_I8
);
2224 /************************************************************************
2225 * VarI8FromDisp (OLEAUT32.340)
2227 * Convert a VT_DISPATCH to a VT_I8.
2230 * pdispIn [I] Source
2231 * lcid [I] LCID for conversion
2232 * pi64Out [O] Destination
2236 * Failure: E_INVALIDARG, if the source value is invalid
2237 * DISP_E_OVERFLOW, if the value will not fit in the destination
2238 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2240 HRESULT WINAPI
VarI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG64
* pi64Out
)
2242 return VARIANT_FromDisp(pdispIn
, lcid
, pi64Out
, VT_I8
, 0);
2245 /************************************************************************
2246 * VarI8FromBool (OLEAUT32.341)
2248 * Convert a VT_BOOL to a VT_I8.
2252 * pi64Out [O] Destination
2257 HRESULT WINAPI
VarI8FromBool(VARIANT_BOOL boolIn
, LONG64
* pi64Out
)
2259 return VarI8FromI2(boolIn
, pi64Out
);
2262 /************************************************************************
2263 * VarI8FromI1 (OLEAUT32.342)
2265 * Convert a VT_I1 to a VT_I8.
2269 * pi64Out [O] Destination
2274 HRESULT WINAPI
VarI8FromI1(signed char cIn
, LONG64
* pi64Out
)
2276 return _VarI8FromI1(cIn
, pi64Out
);
2279 /************************************************************************
2280 * VarI8FromUI2 (OLEAUT32.343)
2282 * Convert a VT_UI2 to a VT_I8.
2286 * pi64Out [O] Destination
2291 HRESULT WINAPI
VarI8FromUI2(USHORT usIn
, LONG64
* pi64Out
)
2293 return _VarI8FromUI2(usIn
, pi64Out
);
2296 /************************************************************************
2297 * VarI8FromUI4 (OLEAUT32.344)
2299 * Convert a VT_UI4 to a VT_I8.
2303 * pi64Out [O] Destination
2308 HRESULT WINAPI
VarI8FromUI4(ULONG ulIn
, LONG64
* pi64Out
)
2310 return _VarI8FromUI4(ulIn
, pi64Out
);
2313 /************************************************************************
2314 * VarI8FromDec (OLEAUT32.345)
2316 * Convert a VT_DECIMAL to a VT_I8.
2320 * pi64Out [O] Destination
2324 * Failure: E_INVALIDARG, if the source value is invalid
2325 * DISP_E_OVERFLOW, if the value will not fit in the destination
2327 HRESULT WINAPI
VarI8FromDec(DECIMAL
*pdecIn
, LONG64
* pi64Out
)
2329 if (!DEC_SCALE(pdecIn
))
2331 /* This decimal is just a 96 bit integer */
2332 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2333 return E_INVALIDARG
;
2335 if (DEC_HI32(pdecIn
) || DEC_MID32(pdecIn
) & 0x80000000)
2336 return DISP_E_OVERFLOW
;
2338 if (DEC_SIGN(pdecIn
))
2339 *pi64Out
= -DEC_LO64(pdecIn
);
2341 *pi64Out
= DEC_LO64(pdecIn
);
2346 /* Decimal contains a floating point number */
2350 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2351 if (SUCCEEDED(hRet
))
2352 hRet
= VarI8FromR8(dbl
, pi64Out
);
2357 /************************************************************************
2358 * VarI8FromUI8 (OLEAUT32.427)
2360 * Convert a VT_UI8 to a VT_I8.
2364 * pi64Out [O] Destination
2368 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2370 HRESULT WINAPI
VarI8FromUI8(ULONG64 ullIn
, LONG64
* pi64Out
)
2372 return _VarI8FromUI8(ullIn
, pi64Out
);
2378 /************************************************************************
2379 * VarUI8FromI8 (OLEAUT32.428)
2381 * Convert a VT_I8 to a VT_UI8.
2385 * pui64Out [O] Destination
2389 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2391 HRESULT WINAPI
VarUI8FromI8(LONG64 llIn
, ULONG64
* pui64Out
)
2393 return _VarUI8FromI8(llIn
, pui64Out
);
2396 /************************************************************************
2397 * VarUI8FromUI1 (OLEAUT32.429)
2399 * Convert a VT_UI1 to a VT_UI8.
2403 * pui64Out [O] Destination
2408 HRESULT WINAPI
VarUI8FromUI1(BYTE bIn
, ULONG64
* pui64Out
)
2410 return _VarUI8FromUI1(bIn
, pui64Out
);
2413 /************************************************************************
2414 * VarUI8FromI2 (OLEAUT32.430)
2416 * Convert a VT_I2 to a VT_UI8.
2420 * pui64Out [O] Destination
2425 HRESULT WINAPI
VarUI8FromI2(SHORT sIn
, ULONG64
* pui64Out
)
2427 return _VarUI8FromI2(sIn
, pui64Out
);
2430 /************************************************************************
2431 * VarUI8FromR4 (OLEAUT32.431)
2433 * Convert a VT_R4 to a VT_UI8.
2437 * pui64Out [O] Destination
2441 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2443 HRESULT WINAPI
VarUI8FromR4(FLOAT fltIn
, ULONG64
* pui64Out
)
2445 return VarUI8FromR8(fltIn
, pui64Out
);
2448 /************************************************************************
2449 * VarUI8FromR8 (OLEAUT32.432)
2451 * Convert a VT_R8 to a VT_UI8.
2455 * pui64Out [O] Destination
2459 * Failure: E_INVALIDARG, if the source value is invalid
2460 * DISP_E_OVERFLOW, if the value will not fit in the destination
2463 * See VarI8FromR8() for details concerning rounding.
2465 HRESULT WINAPI
VarUI8FromR8(double dblIn
, ULONG64
* pui64Out
)
2467 if (dblIn
< -0.5 || dblIn
> 1.844674407370955e19
)
2468 return DISP_E_OVERFLOW
;
2469 VARIANT_DutchRound(ULONG64
, dblIn
, *pui64Out
);
2473 /************************************************************************
2474 * VarUI8FromCy (OLEAUT32.433)
2476 * Convert a VT_CY to a VT_UI8.
2480 * pui64Out [O] Destination
2484 * Failure: E_INVALIDARG, if the source value is invalid
2485 * DISP_E_OVERFLOW, if the value will not fit in the destination
2488 * Negative values >= -5000 will be converted to 0.
2490 HRESULT WINAPI
VarUI8FromCy(CY cyIn
, ULONG64
* pui64Out
)
2494 if (cyIn
.int64
< -CY_HALF
)
2495 return DISP_E_OVERFLOW
;
2500 *pui64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2502 cyIn
.int64
-= *pui64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2504 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pui64Out
& 0x1)))
2510 /************************************************************************
2511 * VarUI8FromDate (OLEAUT32.434)
2513 * Convert a VT_DATE to a VT_UI8.
2517 * pui64Out [O] Destination
2521 * Failure: E_INVALIDARG, if the source value is invalid
2522 * DISP_E_OVERFLOW, if the value will not fit in the destination
2523 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2525 HRESULT WINAPI
VarUI8FromDate(DATE dateIn
, ULONG64
* pui64Out
)
2527 return VarUI8FromR8(dateIn
, pui64Out
);
2530 /************************************************************************
2531 * VarUI8FromStr (OLEAUT32.435)
2533 * Convert a VT_BSTR to a VT_UI8.
2537 * lcid [I] LCID for the conversion
2538 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2539 * pui64Out [O] Destination
2543 * Failure: E_INVALIDARG, if the source value is invalid
2544 * DISP_E_OVERFLOW, if the value will not fit in the destination
2545 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2547 HRESULT WINAPI
VarUI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG64
* pui64Out
)
2549 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pui64Out
, VT_UI8
);
2552 /************************************************************************
2553 * VarUI8FromDisp (OLEAUT32.436)
2555 * Convert a VT_DISPATCH to a VT_UI8.
2558 * pdispIn [I] Source
2559 * lcid [I] LCID for conversion
2560 * pui64Out [O] Destination
2564 * Failure: E_INVALIDARG, if the source value is invalid
2565 * DISP_E_OVERFLOW, if the value will not fit in the destination
2566 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2568 HRESULT WINAPI
VarUI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG64
* pui64Out
)
2570 return VARIANT_FromDisp(pdispIn
, lcid
, pui64Out
, VT_UI8
, 0);
2573 /************************************************************************
2574 * VarUI8FromBool (OLEAUT32.437)
2576 * Convert a VT_BOOL to a VT_UI8.
2580 * pui64Out [O] Destination
2584 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2586 HRESULT WINAPI
VarUI8FromBool(VARIANT_BOOL boolIn
, ULONG64
* pui64Out
)
2588 return VarI8FromI2(boolIn
, (LONG64
*)pui64Out
);
2590 /************************************************************************
2591 * VarUI8FromI1 (OLEAUT32.438)
2593 * Convert a VT_I1 to a VT_UI8.
2597 * pui64Out [O] Destination
2601 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2603 HRESULT WINAPI
VarUI8FromI1(signed char cIn
, ULONG64
* pui64Out
)
2605 return _VarUI8FromI1(cIn
, pui64Out
);
2608 /************************************************************************
2609 * VarUI8FromUI2 (OLEAUT32.439)
2611 * Convert a VT_UI2 to a VT_UI8.
2615 * pui64Out [O] Destination
2620 HRESULT WINAPI
VarUI8FromUI2(USHORT usIn
, ULONG64
* pui64Out
)
2622 return _VarUI8FromUI2(usIn
, pui64Out
);
2625 /************************************************************************
2626 * VarUI8FromUI4 (OLEAUT32.440)
2628 * Convert a VT_UI4 to a VT_UI8.
2632 * pui64Out [O] Destination
2637 HRESULT WINAPI
VarUI8FromUI4(ULONG ulIn
, ULONG64
* pui64Out
)
2639 return _VarUI8FromUI4(ulIn
, pui64Out
);
2642 /************************************************************************
2643 * VarUI8FromDec (OLEAUT32.441)
2645 * Convert a VT_DECIMAL to a VT_UI8.
2649 * pui64Out [O] Destination
2653 * Failure: E_INVALIDARG, if the source value is invalid
2654 * DISP_E_OVERFLOW, if the value will not fit in the destination
2657 * Under native Win32, if the source value has a scale of 0, its sign is
2658 * ignored, i.e. this function takes the absolute value rather than fail
2659 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2660 * (use VarAbs() on pDecIn first if you really want this behaviour).
2662 HRESULT WINAPI
VarUI8FromDec(DECIMAL
*pdecIn
, ULONG64
* pui64Out
)
2664 if (!DEC_SCALE(pdecIn
))
2666 /* This decimal is just a 96 bit integer */
2667 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2668 return E_INVALIDARG
;
2670 if (DEC_HI32(pdecIn
))
2671 return DISP_E_OVERFLOW
;
2673 if (DEC_SIGN(pdecIn
))
2675 WARN("Sign would be ignored under Win32!\n");
2676 return DISP_E_OVERFLOW
;
2679 *pui64Out
= DEC_LO64(pdecIn
);
2684 /* Decimal contains a floating point number */
2688 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2689 if (SUCCEEDED(hRet
))
2690 hRet
= VarUI8FromR8(dbl
, pui64Out
);
2698 /************************************************************************
2699 * VarR4FromUI1 (OLEAUT32.68)
2701 * Convert a VT_UI1 to a VT_R4.
2705 * pFltOut [O] Destination
2710 HRESULT WINAPI
VarR4FromUI1(BYTE bIn
, float *pFltOut
)
2712 return _VarR4FromUI1(bIn
, pFltOut
);
2715 /************************************************************************
2716 * VarR4FromI2 (OLEAUT32.69)
2718 * Convert a VT_I2 to a VT_R4.
2722 * pFltOut [O] Destination
2727 HRESULT WINAPI
VarR4FromI2(SHORT sIn
, float *pFltOut
)
2729 return _VarR4FromI2(sIn
, pFltOut
);
2732 /************************************************************************
2733 * VarR4FromI4 (OLEAUT32.70)
2735 * Convert a VT_I4 to a VT_R4.
2739 * pFltOut [O] Destination
2744 HRESULT WINAPI
VarR4FromI4(LONG lIn
, float *pFltOut
)
2746 return _VarR4FromI4(lIn
, pFltOut
);
2749 /************************************************************************
2750 * VarR4FromR8 (OLEAUT32.71)
2752 * Convert a VT_R8 to a VT_R4.
2756 * pFltOut [O] Destination
2760 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2762 HRESULT WINAPI
VarR4FromR8(double dblIn
, float *pFltOut
)
2764 double d
= dblIn
< 0.0 ? -dblIn
: dblIn
;
2765 if (d
> R4_MAX
) return DISP_E_OVERFLOW
;
2770 /************************************************************************
2771 * VarR4FromCy (OLEAUT32.72)
2773 * Convert a VT_CY to a VT_R4.
2777 * pFltOut [O] Destination
2782 HRESULT WINAPI
VarR4FromCy(CY cyIn
, float *pFltOut
)
2784 *pFltOut
= (double)cyIn
.int64
/ CY_MULTIPLIER_F
;
2788 /************************************************************************
2789 * VarR4FromDate (OLEAUT32.73)
2791 * Convert a VT_DATE to a VT_R4.
2795 * pFltOut [O] Destination
2799 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2801 HRESULT WINAPI
VarR4FromDate(DATE dateIn
, float *pFltOut
)
2803 return VarR4FromR8(dateIn
, pFltOut
);
2806 /************************************************************************
2807 * VarR4FromStr (OLEAUT32.74)
2809 * Convert a VT_BSTR to a VT_R4.
2813 * lcid [I] LCID for the conversion
2814 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2815 * pFltOut [O] Destination
2819 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2820 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2822 HRESULT WINAPI
VarR4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, float *pFltOut
)
2824 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pFltOut
, VT_R4
);
2827 /************************************************************************
2828 * VarR4FromDisp (OLEAUT32.75)
2830 * Convert a VT_DISPATCH to a VT_R4.
2833 * pdispIn [I] Source
2834 * lcid [I] LCID for conversion
2835 * pFltOut [O] Destination
2839 * Failure: E_INVALIDARG, if the source value is invalid
2840 * DISP_E_OVERFLOW, if the value will not fit in the destination
2841 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2843 HRESULT WINAPI
VarR4FromDisp(IDispatch
* pdispIn
, LCID lcid
, float *pFltOut
)
2845 return VARIANT_FromDisp(pdispIn
, lcid
, pFltOut
, VT_R4
, 0);
2848 /************************************************************************
2849 * VarR4FromBool (OLEAUT32.76)
2851 * Convert a VT_BOOL to a VT_R4.
2855 * pFltOut [O] Destination
2860 HRESULT WINAPI
VarR4FromBool(VARIANT_BOOL boolIn
, float *pFltOut
)
2862 return VarR4FromI2(boolIn
, pFltOut
);
2865 /************************************************************************
2866 * VarR4FromI1 (OLEAUT32.213)
2868 * Convert a VT_I1 to a VT_R4.
2872 * pFltOut [O] Destination
2876 * Failure: E_INVALIDARG, if the source value is invalid
2877 * DISP_E_OVERFLOW, if the value will not fit in the destination
2878 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2880 HRESULT WINAPI
VarR4FromI1(signed char cIn
, float *pFltOut
)
2882 return _VarR4FromI1(cIn
, pFltOut
);
2885 /************************************************************************
2886 * VarR4FromUI2 (OLEAUT32.214)
2888 * Convert a VT_UI2 to a VT_R4.
2892 * pFltOut [O] Destination
2896 * Failure: E_INVALIDARG, if the source value is invalid
2897 * DISP_E_OVERFLOW, if the value will not fit in the destination
2898 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2900 HRESULT WINAPI
VarR4FromUI2(USHORT usIn
, float *pFltOut
)
2902 return _VarR4FromUI2(usIn
, pFltOut
);
2905 /************************************************************************
2906 * VarR4FromUI4 (OLEAUT32.215)
2908 * Convert a VT_UI4 to a VT_R4.
2912 * pFltOut [O] Destination
2916 * Failure: E_INVALIDARG, if the source value is invalid
2917 * DISP_E_OVERFLOW, if the value will not fit in the destination
2918 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2920 HRESULT WINAPI
VarR4FromUI4(ULONG ulIn
, float *pFltOut
)
2922 return _VarR4FromUI4(ulIn
, pFltOut
);
2925 /************************************************************************
2926 * VarR4FromDec (OLEAUT32.216)
2928 * Convert a VT_DECIMAL to a VT_R4.
2932 * pFltOut [O] Destination
2936 * Failure: E_INVALIDARG, if the source value is invalid.
2938 HRESULT WINAPI
VarR4FromDec(DECIMAL
* pDecIn
, float *pFltOut
)
2940 BYTE scale
= DEC_SCALE(pDecIn
);
2941 double divisor
= 1.0;
2944 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
2945 return E_INVALIDARG
;
2950 if (DEC_SIGN(pDecIn
))
2953 if (DEC_HI32(pDecIn
))
2955 highPart
= (double)DEC_HI32(pDecIn
) / divisor
;
2956 highPart
*= 4294967296.0F
;
2957 highPart
*= 4294967296.0F
;
2962 *pFltOut
= (double)DEC_LO64(pDecIn
) / divisor
+ highPart
;
2966 /************************************************************************
2967 * VarR4FromI8 (OLEAUT32.360)
2969 * Convert a VT_I8 to a VT_R4.
2973 * pFltOut [O] Destination
2978 HRESULT WINAPI
VarR4FromI8(LONG64 llIn
, float *pFltOut
)
2980 return _VarR4FromI8(llIn
, pFltOut
);
2983 /************************************************************************
2984 * VarR4FromUI8 (OLEAUT32.361)
2986 * Convert a VT_UI8 to a VT_R4.
2990 * pFltOut [O] Destination
2995 HRESULT WINAPI
VarR4FromUI8(ULONG64 ullIn
, float *pFltOut
)
2997 return _VarR4FromUI8(ullIn
, pFltOut
);
3000 /************************************************************************
3001 * VarR4CmpR8 (OLEAUT32.316)
3003 * Compare a VT_R4 to a VT_R8.
3006 * fltLeft [I] Source
3007 * dblRight [I] Value to compare
3010 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3011 * equal to or greater than dblRight respectively.
3013 HRESULT WINAPI
VarR4CmpR8(float fltLeft
, double dblRight
)
3015 if (fltLeft
< dblRight
)
3017 else if (fltLeft
> dblRight
)
3025 /************************************************************************
3026 * VarR8FromUI1 (OLEAUT32.78)
3028 * Convert a VT_UI1 to a VT_R8.
3032 * pDblOut [O] Destination
3037 HRESULT WINAPI
VarR8FromUI1(BYTE bIn
, double *pDblOut
)
3039 return _VarR8FromUI1(bIn
, pDblOut
);
3042 /************************************************************************
3043 * VarR8FromI2 (OLEAUT32.79)
3045 * Convert a VT_I2 to a VT_R8.
3049 * pDblOut [O] Destination
3054 HRESULT WINAPI
VarR8FromI2(SHORT sIn
, double *pDblOut
)
3056 return _VarR8FromI2(sIn
, pDblOut
);
3059 /************************************************************************
3060 * VarR8FromI4 (OLEAUT32.80)
3062 * Convert a VT_I4 to a VT_R8.
3066 * pDblOut [O] Destination
3071 HRESULT WINAPI
VarR8FromI4(LONG lIn
, double *pDblOut
)
3073 return _VarR8FromI4(lIn
, pDblOut
);
3076 /************************************************************************
3077 * VarR8FromR4 (OLEAUT32.81)
3079 * Convert a VT_R4 to a VT_R8.
3083 * pDblOut [O] Destination
3088 HRESULT WINAPI
VarR8FromR4(FLOAT fltIn
, double *pDblOut
)
3090 return _VarR8FromR4(fltIn
, pDblOut
);
3093 /************************************************************************
3094 * VarR8FromCy (OLEAUT32.82)
3096 * Convert a VT_CY to a VT_R8.
3100 * pDblOut [O] Destination
3105 HRESULT WINAPI
VarR8FromCy(CY cyIn
, double *pDblOut
)
3107 return _VarR8FromCy(cyIn
, pDblOut
);
3110 /************************************************************************
3111 * VarR8FromDate (OLEAUT32.83)
3113 * Convert a VT_DATE to a VT_R8.
3117 * pDblOut [O] Destination
3122 HRESULT WINAPI
VarR8FromDate(DATE dateIn
, double *pDblOut
)
3124 return _VarR8FromDate(dateIn
, pDblOut
);
3127 /************************************************************************
3128 * VarR8FromStr (OLEAUT32.84)
3130 * Convert a VT_BSTR to a VT_R8.
3134 * lcid [I] LCID for the conversion
3135 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3136 * pDblOut [O] Destination
3140 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3141 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3143 HRESULT WINAPI
VarR8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, double *pDblOut
)
3145 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDblOut
, VT_R8
);
3148 /************************************************************************
3149 * VarR8FromDisp (OLEAUT32.85)
3151 * Convert a VT_DISPATCH to a VT_R8.
3154 * pdispIn [I] Source
3155 * lcid [I] LCID for conversion
3156 * pDblOut [O] Destination
3160 * Failure: E_INVALIDARG, if the source value is invalid
3161 * DISP_E_OVERFLOW, if the value will not fit in the destination
3162 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3164 HRESULT WINAPI
VarR8FromDisp(IDispatch
* pdispIn
, LCID lcid
, double *pDblOut
)
3166 return VARIANT_FromDisp(pdispIn
, lcid
, pDblOut
, VT_R8
, 0);
3169 /************************************************************************
3170 * VarR8FromBool (OLEAUT32.86)
3172 * Convert a VT_BOOL to a VT_R8.
3176 * pDblOut [O] Destination
3181 HRESULT WINAPI
VarR8FromBool(VARIANT_BOOL boolIn
, double *pDblOut
)
3183 return VarR8FromI2(boolIn
, pDblOut
);
3186 /************************************************************************
3187 * VarR8FromI1 (OLEAUT32.217)
3189 * Convert a VT_I1 to a VT_R8.
3193 * pDblOut [O] Destination
3197 * Failure: E_INVALIDARG, if the source value is invalid
3198 * DISP_E_OVERFLOW, if the value will not fit in the destination
3199 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3201 HRESULT WINAPI
VarR8FromI1(signed char cIn
, double *pDblOut
)
3203 return _VarR8FromI1(cIn
, pDblOut
);
3206 /************************************************************************
3207 * VarR8FromUI2 (OLEAUT32.218)
3209 * Convert a VT_UI2 to a VT_R8.
3213 * pDblOut [O] Destination
3217 * Failure: E_INVALIDARG, if the source value is invalid
3218 * DISP_E_OVERFLOW, if the value will not fit in the destination
3219 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3221 HRESULT WINAPI
VarR8FromUI2(USHORT usIn
, double *pDblOut
)
3223 return _VarR8FromUI2(usIn
, pDblOut
);
3226 /************************************************************************
3227 * VarR8FromUI4 (OLEAUT32.219)
3229 * Convert a VT_UI4 to a VT_R8.
3233 * pDblOut [O] Destination
3237 * Failure: E_INVALIDARG, if the source value is invalid
3238 * DISP_E_OVERFLOW, if the value will not fit in the destination
3239 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3241 HRESULT WINAPI
VarR8FromUI4(ULONG ulIn
, double *pDblOut
)
3243 return _VarR8FromUI4(ulIn
, pDblOut
);
3246 /************************************************************************
3247 * VarR8FromDec (OLEAUT32.220)
3249 * Convert a VT_DECIMAL to a VT_R8.
3253 * pDblOut [O] Destination
3257 * Failure: E_INVALIDARG, if the source value is invalid.
3259 HRESULT WINAPI
VarR8FromDec(const DECIMAL
* pDecIn
, double *pDblOut
)
3261 BYTE scale
= DEC_SCALE(pDecIn
);
3262 double divisor
= 1.0, highPart
;
3264 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
3265 return E_INVALIDARG
;
3270 if (DEC_SIGN(pDecIn
))
3273 if (DEC_HI32(pDecIn
))
3275 highPart
= (double)DEC_HI32(pDecIn
) / divisor
;
3276 highPart
*= 4294967296.0F
;
3277 highPart
*= 4294967296.0F
;
3282 *pDblOut
= (double)DEC_LO64(pDecIn
) / divisor
+ highPart
;
3286 /************************************************************************
3287 * VarR8FromI8 (OLEAUT32.362)
3289 * Convert a VT_I8 to a VT_R8.
3293 * pDblOut [O] Destination
3298 HRESULT WINAPI
VarR8FromI8(LONG64 llIn
, double *pDblOut
)
3300 return _VarR8FromI8(llIn
, pDblOut
);
3303 /************************************************************************
3304 * VarR8FromUI8 (OLEAUT32.363)
3306 * Convert a VT_UI8 to a VT_R8.
3310 * pDblOut [O] Destination
3315 HRESULT WINAPI
VarR8FromUI8(ULONG64 ullIn
, double *pDblOut
)
3317 return _VarR8FromUI8(ullIn
, pDblOut
);
3320 /************************************************************************
3321 * VarR8Pow (OLEAUT32.315)
3323 * Raise a VT_R8 to a power.
3326 * dblLeft [I] Source
3327 * dblPow [I] Power to raise dblLeft by
3328 * pDblOut [O] Destination
3331 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3333 HRESULT WINAPI
VarR8Pow(double dblLeft
, double dblPow
, double *pDblOut
)
3335 *pDblOut
= pow(dblLeft
, dblPow
);
3339 /************************************************************************
3340 * VarR8Round (OLEAUT32.317)
3342 * Round a VT_R8 to a given number of decimal points.
3346 * nDig [I] Number of decimal points to round to
3347 * pDblOut [O] Destination for rounded number
3350 * Success: S_OK. pDblOut is rounded to nDig digits.
3351 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3354 * The native version of this function rounds using the internal
3355 * binary representation of the number. Wine uses the dutch rounding
3356 * convention, so therefore small differences can occur in the value returned.
3357 * MSDN says that you should use your own rounding function if you want
3358 * rounding to be predictable in your application.
3360 HRESULT WINAPI
VarR8Round(double dblIn
, int nDig
, double *pDblOut
)
3362 double scale
, whole
, fract
;
3365 return E_INVALIDARG
;
3367 scale
= pow(10.0, nDig
);
3370 whole
= dblIn
< 0 ? ceil(dblIn
) : floor(dblIn
);
3371 fract
= dblIn
- whole
;
3374 dblIn
= whole
+ 1.0;
3375 else if (fract
== 0.5)
3376 dblIn
= whole
+ fmod(whole
, 2.0);
3377 else if (fract
>= 0.0)
3379 else if (fract
== -0.5)
3380 dblIn
= whole
- fmod(whole
, 2.0);
3381 else if (fract
> -0.5)
3384 dblIn
= whole
- 1.0;
3386 *pDblOut
= dblIn
/ scale
;
3393 /* Powers of 10 from 0..4 D.P. */
3394 static const int CY_Divisors
[5] = { CY_MULTIPLIER
/10000, CY_MULTIPLIER
/1000,
3395 CY_MULTIPLIER
/100, CY_MULTIPLIER
/10, CY_MULTIPLIER
};
3397 /************************************************************************
3398 * VarCyFromUI1 (OLEAUT32.98)
3400 * Convert a VT_UI1 to a VT_CY.
3404 * pCyOut [O] Destination
3408 * Failure: E_INVALIDARG, if the source value is invalid
3409 * DISP_E_OVERFLOW, if the value will not fit in the destination
3410 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3412 HRESULT WINAPI
VarCyFromUI1(BYTE bIn
, CY
* pCyOut
)
3414 pCyOut
->int64
= (ULONG64
)bIn
* CY_MULTIPLIER
;
3418 /************************************************************************
3419 * VarCyFromI2 (OLEAUT32.99)
3421 * Convert a VT_I2 to a VT_CY.
3425 * pCyOut [O] Destination
3429 * Failure: E_INVALIDARG, if the source value is invalid
3430 * DISP_E_OVERFLOW, if the value will not fit in the destination
3431 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3433 HRESULT WINAPI
VarCyFromI2(SHORT sIn
, CY
* pCyOut
)
3435 pCyOut
->int64
= (LONG64
)sIn
* CY_MULTIPLIER
;
3439 /************************************************************************
3440 * VarCyFromI4 (OLEAUT32.100)
3442 * Convert a VT_I4 to a VT_CY.
3446 * pCyOut [O] Destination
3450 * Failure: E_INVALIDARG, if the source value is invalid
3451 * DISP_E_OVERFLOW, if the value will not fit in the destination
3452 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3454 HRESULT WINAPI
VarCyFromI4(LONG lIn
, CY
* pCyOut
)
3456 pCyOut
->int64
= (LONG64
)lIn
* CY_MULTIPLIER
;
3460 /************************************************************************
3461 * VarCyFromR4 (OLEAUT32.101)
3463 * Convert a VT_R4 to a VT_CY.
3467 * pCyOut [O] Destination
3471 * Failure: E_INVALIDARG, if the source value is invalid
3472 * DISP_E_OVERFLOW, if the value will not fit in the destination
3473 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3475 HRESULT WINAPI
VarCyFromR4(FLOAT fltIn
, CY
* pCyOut
)
3477 return VarCyFromR8(fltIn
, pCyOut
);
3480 /************************************************************************
3481 * VarCyFromR8 (OLEAUT32.102)
3483 * Convert a VT_R8 to a VT_CY.
3487 * pCyOut [O] Destination
3491 * Failure: E_INVALIDARG, if the source value is invalid
3492 * DISP_E_OVERFLOW, if the value will not fit in the destination
3493 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3495 HRESULT WINAPI
VarCyFromR8(double dblIn
, CY
* pCyOut
)
3497 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3498 /* This code gives identical results to Win32 on Intel.
3499 * Here we use fp exceptions to catch overflows when storing the value.
3501 static const unsigned short r8_fpcontrol
= 0x137f;
3502 static const double r8_multiplier
= CY_MULTIPLIER_F
;
3503 unsigned short old_fpcontrol
, result_fpstatus
;
3505 /* Clear exceptions, save the old fp state and load the new state */
3506 __asm__
__volatile__( "fnclex" );
3507 __asm__
__volatile__( "fstcw %0" : "=m" (old_fpcontrol
) : );
3508 __asm__
__volatile__( "fldcw %0" : : "m" (r8_fpcontrol
) );
3509 /* Perform the conversion. */
3510 __asm__
__volatile__( "fldl %0" : : "m" (dblIn
) );
3511 __asm__
__volatile__( "fmull %0" : : "m" (r8_multiplier
) );
3512 __asm__
__volatile__( "fistpll %0" : : "m" (*pCyOut
) );
3513 /* Save the resulting fp state, load the old state and clear exceptions */
3514 __asm__
__volatile__( "fstsw %0" : "=m" (result_fpstatus
) : );
3515 __asm__
__volatile__( "fnclex" );
3516 __asm__
__volatile__( "fldcw %0" : : "m" (old_fpcontrol
) );
3518 if (result_fpstatus
& 0x9) /* Overflow | Invalid */
3519 return DISP_E_OVERFLOW
;
3521 /* This version produces slightly different results for boundary cases */
3522 if (dblIn
< -922337203685477.5807 || dblIn
>= 922337203685477.5807)
3523 return DISP_E_OVERFLOW
;
3524 dblIn
*= CY_MULTIPLIER_F
;
3525 VARIANT_DutchRound(LONG64
, dblIn
, pCyOut
->int64
);
3530 /************************************************************************
3531 * VarCyFromDate (OLEAUT32.103)
3533 * Convert a VT_DATE to a VT_CY.
3537 * pCyOut [O] Destination
3541 * Failure: E_INVALIDARG, if the source value is invalid
3542 * DISP_E_OVERFLOW, if the value will not fit in the destination
3543 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3545 HRESULT WINAPI
VarCyFromDate(DATE dateIn
, CY
* pCyOut
)
3547 return VarCyFromR8(dateIn
, pCyOut
);
3550 /************************************************************************
3551 * VarCyFromStr (OLEAUT32.104)
3553 * Convert a VT_BSTR to a VT_CY.
3557 * lcid [I] LCID for the conversion
3558 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3559 * pCyOut [O] Destination
3563 * Failure: E_INVALIDARG, if the source value is invalid
3564 * DISP_E_OVERFLOW, if the value will not fit in the destination
3565 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3567 HRESULT WINAPI
VarCyFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, CY
* pCyOut
)
3569 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pCyOut
, VT_CY
);
3572 /************************************************************************
3573 * VarCyFromDisp (OLEAUT32.105)
3575 * Convert a VT_DISPATCH to a VT_CY.
3578 * pdispIn [I] Source
3579 * lcid [I] LCID for conversion
3580 * pCyOut [O] Destination
3584 * Failure: E_INVALIDARG, if the source value is invalid
3585 * DISP_E_OVERFLOW, if the value will not fit in the destination
3586 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3588 HRESULT WINAPI
VarCyFromDisp(IDispatch
* pdispIn
, LCID lcid
, CY
* pCyOut
)
3590 return VARIANT_FromDisp(pdispIn
, lcid
, pCyOut
, VT_CY
, 0);
3593 /************************************************************************
3594 * VarCyFromBool (OLEAUT32.106)
3596 * Convert a VT_BOOL to a VT_CY.
3600 * pCyOut [O] Destination
3604 * Failure: E_INVALIDARG, if the source value is invalid
3605 * DISP_E_OVERFLOW, if the value will not fit in the destination
3606 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3609 * While the sign of the boolean is stored in the currency, the value is
3610 * converted to either 0 or 1.
3612 HRESULT WINAPI
VarCyFromBool(VARIANT_BOOL boolIn
, CY
* pCyOut
)
3614 pCyOut
->int64
= (LONG64
)boolIn
* CY_MULTIPLIER
;
3618 /************************************************************************
3619 * VarCyFromI1 (OLEAUT32.225)
3621 * Convert a VT_I1 to a VT_CY.
3625 * pCyOut [O] Destination
3629 * Failure: E_INVALIDARG, if the source value is invalid
3630 * DISP_E_OVERFLOW, if the value will not fit in the destination
3631 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3633 HRESULT WINAPI
VarCyFromI1(signed char cIn
, CY
* pCyOut
)
3635 pCyOut
->int64
= (LONG64
)cIn
* CY_MULTIPLIER
;
3639 /************************************************************************
3640 * VarCyFromUI2 (OLEAUT32.226)
3642 * Convert a VT_UI2 to a VT_CY.
3646 * pCyOut [O] Destination
3650 * Failure: E_INVALIDARG, if the source value is invalid
3651 * DISP_E_OVERFLOW, if the value will not fit in the destination
3652 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3654 HRESULT WINAPI
VarCyFromUI2(USHORT usIn
, CY
* pCyOut
)
3656 pCyOut
->int64
= (ULONG64
)usIn
* CY_MULTIPLIER
;
3660 /************************************************************************
3661 * VarCyFromUI4 (OLEAUT32.227)
3663 * Convert a VT_UI4 to a VT_CY.
3667 * pCyOut [O] Destination
3671 * Failure: E_INVALIDARG, if the source value is invalid
3672 * DISP_E_OVERFLOW, if the value will not fit in the destination
3673 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3675 HRESULT WINAPI
VarCyFromUI4(ULONG ulIn
, CY
* pCyOut
)
3677 pCyOut
->int64
= (ULONG64
)ulIn
* CY_MULTIPLIER
;
3681 /************************************************************************
3682 * VarCyFromDec (OLEAUT32.228)
3684 * Convert a VT_DECIMAL to a VT_CY.
3688 * pCyOut [O] Destination
3692 * Failure: E_INVALIDARG, if the source value is invalid
3693 * DISP_E_OVERFLOW, if the value will not fit in the destination
3694 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3696 HRESULT WINAPI
VarCyFromDec(DECIMAL
* pdecIn
, CY
* pCyOut
)
3701 hRet
= VarDecRound(pdecIn
, 4, &rounded
);
3703 if (SUCCEEDED(hRet
))
3707 if (DEC_HI32(&rounded
))
3708 return DISP_E_OVERFLOW
;
3710 /* Note: Without the casts this promotes to int64 which loses precision */
3711 d
= (double)DEC_LO64(&rounded
) / (double)CY_Divisors
[DEC_SCALE(&rounded
)];
3712 if (DEC_SIGN(&rounded
))
3714 return VarCyFromR8(d
, pCyOut
);
3719 /************************************************************************
3720 * VarCyFromI8 (OLEAUT32.366)
3722 * Convert a VT_I8 to a VT_CY.
3726 * pCyOut [O] Destination
3730 * Failure: E_INVALIDARG, if the source value is invalid
3731 * DISP_E_OVERFLOW, if the value will not fit in the destination
3732 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3734 HRESULT WINAPI
VarCyFromI8(LONG64 llIn
, CY
* pCyOut
)
3736 if (llIn
<= (I8_MIN
/CY_MULTIPLIER
) || llIn
>= (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3737 pCyOut
->int64
= llIn
* CY_MULTIPLIER
;
3741 /************************************************************************
3742 * VarCyFromUI8 (OLEAUT32.375)
3744 * Convert a VT_UI8 to a VT_CY.
3748 * pCyOut [O] Destination
3752 * Failure: E_INVALIDARG, if the source value is invalid
3753 * DISP_E_OVERFLOW, if the value will not fit in the destination
3754 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3756 HRESULT WINAPI
VarCyFromUI8(ULONG64 ullIn
, CY
* pCyOut
)
3758 if (ullIn
> (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3759 pCyOut
->int64
= ullIn
* CY_MULTIPLIER
;
3763 /************************************************************************
3764 * VarCyAdd (OLEAUT32.299)
3766 * Add one CY to another.
3770 * cyRight [I] Value to add
3771 * pCyOut [O] Destination
3775 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3777 HRESULT WINAPI
VarCyAdd(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3780 _VarR8FromCy(cyLeft
, &l
);
3781 _VarR8FromCy(cyRight
, &r
);
3783 return VarCyFromR8(l
, pCyOut
);
3786 /************************************************************************
3787 * VarCyMul (OLEAUT32.303)
3789 * Multiply one CY by another.
3793 * cyRight [I] Value to multiply by
3794 * pCyOut [O] Destination
3798 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3800 HRESULT WINAPI
VarCyMul(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3803 _VarR8FromCy(cyLeft
, &l
);
3804 _VarR8FromCy(cyRight
, &r
);
3806 return VarCyFromR8(l
, pCyOut
);
3809 /************************************************************************
3810 * VarCyMulI4 (OLEAUT32.304)
3812 * Multiply one CY by a VT_I4.
3816 * lRight [I] Value to multiply by
3817 * pCyOut [O] Destination
3821 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3823 HRESULT WINAPI
VarCyMulI4(const CY cyLeft
, LONG lRight
, CY
* pCyOut
)
3827 _VarR8FromCy(cyLeft
, &d
);
3829 return VarCyFromR8(d
, pCyOut
);
3832 /************************************************************************
3833 * VarCySub (OLEAUT32.305)
3835 * Subtract one CY from another.
3839 * cyRight [I] Value to subtract
3840 * pCyOut [O] Destination
3844 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3846 HRESULT WINAPI
VarCySub(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3849 _VarR8FromCy(cyLeft
, &l
);
3850 _VarR8FromCy(cyRight
, &r
);
3852 return VarCyFromR8(l
, pCyOut
);
3855 /************************************************************************
3856 * VarCyAbs (OLEAUT32.306)
3858 * Convert a VT_CY into its absolute value.
3862 * pCyOut [O] Destination
3865 * Success: S_OK. pCyOut contains the absolute value.
3866 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3868 HRESULT WINAPI
VarCyAbs(const CY cyIn
, CY
* pCyOut
)
3870 if (cyIn
.s
.Hi
== (int)0x80000000 && !cyIn
.s
.Lo
)
3871 return DISP_E_OVERFLOW
;
3873 pCyOut
->int64
= cyIn
.int64
< 0 ? -cyIn
.int64
: cyIn
.int64
;
3877 /************************************************************************
3878 * VarCyFix (OLEAUT32.307)
3880 * Return the integer part of a VT_CY.
3884 * pCyOut [O] Destination
3888 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3891 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3892 * negative numbers away from 0, while this function rounds them towards zero.
3894 HRESULT WINAPI
VarCyFix(const CY cyIn
, CY
* pCyOut
)
3896 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3897 pCyOut
->int64
*= CY_MULTIPLIER
;
3901 /************************************************************************
3902 * VarCyInt (OLEAUT32.308)
3904 * Return the integer part of a VT_CY.
3908 * pCyOut [O] Destination
3912 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3915 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3916 * negative numbers towards 0, while this function rounds them away from zero.
3918 HRESULT WINAPI
VarCyInt(const CY cyIn
, CY
* pCyOut
)
3920 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3921 pCyOut
->int64
*= CY_MULTIPLIER
;
3923 if (cyIn
.int64
< 0 && cyIn
.int64
% CY_MULTIPLIER
!= 0)
3925 pCyOut
->int64
-= CY_MULTIPLIER
;
3930 /************************************************************************
3931 * VarCyNeg (OLEAUT32.309)
3933 * Change the sign of a VT_CY.
3937 * pCyOut [O] Destination
3941 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3943 HRESULT WINAPI
VarCyNeg(const CY cyIn
, CY
* pCyOut
)
3945 if (cyIn
.s
.Hi
== (int)0x80000000 && !cyIn
.s
.Lo
)
3946 return DISP_E_OVERFLOW
;
3948 pCyOut
->int64
= -cyIn
.int64
;
3952 /************************************************************************
3953 * VarCyRound (OLEAUT32.310)
3955 * Change the precision of a VT_CY.
3959 * cDecimals [I] New number of decimals to keep
3960 * pCyOut [O] Destination
3964 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3966 HRESULT WINAPI
VarCyRound(const CY cyIn
, int cDecimals
, CY
* pCyOut
)
3969 return E_INVALIDARG
;
3973 /* Rounding to more precision than we have */
3979 double d
, div
= CY_Divisors
[cDecimals
];
3981 _VarR8FromCy(cyIn
, &d
);
3983 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
3984 d
= (double)pCyOut
->int64
/ div
* CY_MULTIPLIER_F
;
3985 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
3990 /************************************************************************
3991 * VarCyCmp (OLEAUT32.311)
3993 * Compare two VT_CY values.
3997 * cyRight [I] Value to compare
4000 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4001 * compare is less, equal or greater than source respectively.
4002 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4004 HRESULT WINAPI
VarCyCmp(const CY cyLeft
, const CY cyRight
)
4009 /* Subtract right from left, and compare the result to 0 */
4010 hRet
= VarCySub(cyLeft
, cyRight
, &result
);
4012 if (SUCCEEDED(hRet
))
4014 if (result
.int64
< 0)
4015 hRet
= (HRESULT
)VARCMP_LT
;
4016 else if (result
.int64
> 0)
4017 hRet
= (HRESULT
)VARCMP_GT
;
4019 hRet
= (HRESULT
)VARCMP_EQ
;
4024 /************************************************************************
4025 * VarCyCmpR8 (OLEAUT32.312)
4027 * Compare a VT_CY to a double
4030 * cyLeft [I] Currency Source
4031 * dblRight [I] double to compare to cyLeft
4034 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4035 * less than, equal to or greater than cyLeft respectively.
4036 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4038 HRESULT WINAPI
VarCyCmpR8(const CY cyLeft
, double dblRight
)
4043 hRet
= VarCyFromR8(dblRight
, &cyRight
);
4045 if (SUCCEEDED(hRet
))
4046 hRet
= VarCyCmp(cyLeft
, cyRight
);
4051 /************************************************************************
4052 * VarCyMulI8 (OLEAUT32.329)
4054 * Multiply a VT_CY by a VT_I8.
4058 * llRight [I] Value to multiply by
4059 * pCyOut [O] Destination
4063 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4065 HRESULT WINAPI
VarCyMulI8(const CY cyLeft
, LONG64 llRight
, CY
* pCyOut
)
4069 _VarR8FromCy(cyLeft
, &d
);
4070 d
= d
* (double)llRight
;
4071 return VarCyFromR8(d
, pCyOut
);
4077 /************************************************************************
4078 * VarDecFromUI1 (OLEAUT32.190)
4080 * Convert a VT_UI1 to a DECIMAL.
4084 * pDecOut [O] Destination
4089 HRESULT WINAPI
VarDecFromUI1(BYTE bIn
, DECIMAL
* pDecOut
)
4091 return VarDecFromUI4(bIn
, pDecOut
);
4094 /************************************************************************
4095 * VarDecFromI2 (OLEAUT32.191)
4097 * Convert a VT_I2 to a DECIMAL.
4101 * pDecOut [O] Destination
4106 HRESULT WINAPI
VarDecFromI2(SHORT sIn
, DECIMAL
* pDecOut
)
4108 return VarDecFromI4(sIn
, pDecOut
);
4111 /************************************************************************
4112 * VarDecFromI4 (OLEAUT32.192)
4114 * Convert a VT_I4 to a DECIMAL.
4118 * pDecOut [O] Destination
4123 HRESULT WINAPI
VarDecFromI4(LONG lIn
, DECIMAL
* pDecOut
)
4125 DEC_HI32(pDecOut
) = 0;
4126 DEC_MID32(pDecOut
) = 0;
4130 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4131 DEC_LO32(pDecOut
) = -lIn
;
4135 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4136 DEC_LO32(pDecOut
) = lIn
;
4141 /* internal representation of the value stored in a DECIMAL. The bytes are
4142 stored from LSB at index 0 to MSB at index 11
4144 typedef struct DECIMAL_internal
4146 DWORD bitsnum
[3]; /* 96 significant bits, unsigned */
4147 unsigned char scale
; /* number scaled * 10 ^ -(scale) */
4148 unsigned int sign
: 1; /* 0 - positive, 1 - negative */
4151 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
);
4152 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
);
4153 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
);
4154 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
);
4155 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
);
4156 static BOOL
VARIANT_int_iszero(const DWORD
* p
, unsigned int n
);
4158 /************************************************************************
4159 * VarDecFromR4 (OLEAUT32.193)
4161 * Convert a VT_R4 to a DECIMAL.
4165 * pDecOut [O] Destination
4170 HRESULT WINAPI
VarDecFromR4(FLOAT fltIn
, DECIMAL
* pDecOut
)
4175 hres
= VARIANT_DI_FromR4(fltIn
, &di
);
4176 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4180 /************************************************************************
4181 * VarDecFromR8 (OLEAUT32.194)
4183 * Convert a VT_R8 to a DECIMAL.
4187 * pDecOut [O] Destination
4192 HRESULT WINAPI
VarDecFromR8(double dblIn
, DECIMAL
* pDecOut
)
4197 hres
= VARIANT_DI_FromR8(dblIn
, &di
);
4198 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4202 /************************************************************************
4203 * VarDecFromDate (OLEAUT32.195)
4205 * Convert a VT_DATE to a DECIMAL.
4209 * pDecOut [O] Destination
4214 HRESULT WINAPI
VarDecFromDate(DATE dateIn
, DECIMAL
* pDecOut
)
4216 return VarDecFromR8(dateIn
, pDecOut
);
4219 /************************************************************************
4220 * VarDecFromCy (OLEAUT32.196)
4222 * Convert a VT_CY to a DECIMAL.
4226 * pDecOut [O] Destination
4231 HRESULT WINAPI
VarDecFromCy(CY cyIn
, DECIMAL
* pDecOut
)
4233 DEC_HI32(pDecOut
) = 0;
4235 /* Note: This assumes 2s complement integer representation */
4236 if (cyIn
.s
.Hi
& 0x80000000)
4238 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,4);
4239 DEC_LO64(pDecOut
) = -cyIn
.int64
;
4243 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,4);
4244 DEC_MID32(pDecOut
) = cyIn
.s
.Hi
;
4245 DEC_LO32(pDecOut
) = cyIn
.s
.Lo
;
4250 /************************************************************************
4251 * VarDecFromStr (OLEAUT32.197)
4253 * Convert a VT_BSTR to a DECIMAL.
4257 * lcid [I] LCID for the conversion
4258 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4259 * pDecOut [O] Destination
4263 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4265 HRESULT WINAPI
VarDecFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DECIMAL
* pDecOut
)
4267 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDecOut
, VT_DECIMAL
);
4270 /************************************************************************
4271 * VarDecFromDisp (OLEAUT32.198)
4273 * Convert a VT_DISPATCH to a DECIMAL.
4276 * pdispIn [I] Source
4277 * lcid [I] LCID for conversion
4278 * pDecOut [O] Destination
4282 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4284 HRESULT WINAPI
VarDecFromDisp(IDispatch
* pdispIn
, LCID lcid
, DECIMAL
* pDecOut
)
4286 return VARIANT_FromDisp(pdispIn
, lcid
, pDecOut
, VT_DECIMAL
, 0);
4289 /************************************************************************
4290 * VarDecFromBool (OLEAUT32.199)
4292 * Convert a VT_BOOL to a DECIMAL.
4296 * pDecOut [O] Destination
4302 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4304 HRESULT WINAPI
VarDecFromBool(VARIANT_BOOL bIn
, DECIMAL
* pDecOut
)
4306 DEC_HI32(pDecOut
) = 0;
4307 DEC_MID32(pDecOut
) = 0;
4310 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4311 DEC_LO32(pDecOut
) = 1;
4315 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4316 DEC_LO32(pDecOut
) = 0;
4321 /************************************************************************
4322 * VarDecFromI1 (OLEAUT32.241)
4324 * Convert a VT_I1 to a DECIMAL.
4328 * pDecOut [O] Destination
4333 HRESULT WINAPI
VarDecFromI1(signed char cIn
, DECIMAL
* pDecOut
)
4335 return VarDecFromI4(cIn
, pDecOut
);
4338 /************************************************************************
4339 * VarDecFromUI2 (OLEAUT32.242)
4341 * Convert a VT_UI2 to a DECIMAL.
4345 * pDecOut [O] Destination
4350 HRESULT WINAPI
VarDecFromUI2(USHORT usIn
, DECIMAL
* pDecOut
)
4352 return VarDecFromUI4(usIn
, pDecOut
);
4355 /************************************************************************
4356 * VarDecFromUI4 (OLEAUT32.243)
4358 * Convert a VT_UI4 to a DECIMAL.
4362 * pDecOut [O] Destination
4367 HRESULT WINAPI
VarDecFromUI4(ULONG ulIn
, DECIMAL
* pDecOut
)
4369 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4370 DEC_HI32(pDecOut
) = 0;
4371 DEC_MID32(pDecOut
) = 0;
4372 DEC_LO32(pDecOut
) = ulIn
;
4376 /************************************************************************
4377 * VarDecFromI8 (OLEAUT32.374)
4379 * Convert a VT_I8 to a DECIMAL.
4383 * pDecOut [O] Destination
4388 HRESULT WINAPI
VarDecFromI8(LONG64 llIn
, DECIMAL
* pDecOut
)
4390 PULARGE_INTEGER pLi
= (PULARGE_INTEGER
)&llIn
;
4392 DEC_HI32(pDecOut
) = 0;
4394 /* Note: This assumes 2s complement integer representation */
4395 if (pLi
->u
.HighPart
& 0x80000000)
4397 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4398 DEC_LO64(pDecOut
) = -pLi
->QuadPart
;
4402 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4403 DEC_MID32(pDecOut
) = pLi
->u
.HighPart
;
4404 DEC_LO32(pDecOut
) = pLi
->u
.LowPart
;
4409 /************************************************************************
4410 * VarDecFromUI8 (OLEAUT32.375)
4412 * Convert a VT_UI8 to a DECIMAL.
4416 * pDecOut [O] Destination
4421 HRESULT WINAPI
VarDecFromUI8(ULONG64 ullIn
, DECIMAL
* pDecOut
)
4423 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4424 DEC_HI32(pDecOut
) = 0;
4425 DEC_LO64(pDecOut
) = ullIn
;
4429 /* Make two DECIMALS the same scale; used by math functions below */
4430 static HRESULT
VARIANT_DecScale(const DECIMAL
** ppDecLeft
,
4431 const DECIMAL
** ppDecRight
,
4434 static DECIMAL scaleFactor
;
4435 unsigned char remainder
;
4440 if (DEC_SIGN(*ppDecLeft
) & ~DECIMAL_NEG
|| DEC_SIGN(*ppDecRight
) & ~DECIMAL_NEG
)
4441 return E_INVALIDARG
;
4443 DEC_LO32(&scaleFactor
) = 10;
4445 i
= scaleAmount
= DEC_SCALE(*ppDecLeft
) - DEC_SCALE(*ppDecRight
);
4448 return S_OK
; /* Same scale */
4450 if (scaleAmount
> 0)
4452 decTemp
= *(*ppDecRight
); /* Left is bigger - scale the right hand side */
4453 *ppDecRight
= &pDecOut
[0];
4457 decTemp
= *(*ppDecLeft
); /* Right is bigger - scale the left hand side */
4458 *ppDecLeft
= &pDecOut
[0];
4462 /* Multiply up the value to be scaled by the correct amount (if possible) */
4463 while (i
> 0 && SUCCEEDED(VarDecMul(&decTemp
, &scaleFactor
, &pDecOut
[0])))
4465 decTemp
= pDecOut
[0];
4471 DEC_SCALE(&pDecOut
[0]) += (scaleAmount
> 0) ? scaleAmount
: (-scaleAmount
);
4472 return S_OK
; /* Same scale */
4475 /* Scaling further not possible, reduce accuracy of other argument */
4476 pDecOut
[0] = decTemp
;
4477 if (scaleAmount
> 0)
4479 DEC_SCALE(&pDecOut
[0]) += scaleAmount
- i
;
4480 VARIANT_DIFromDec(*ppDecLeft
, &di
);
4481 *ppDecLeft
= &pDecOut
[1];
4485 DEC_SCALE(&pDecOut
[0]) += (-scaleAmount
) - i
;
4486 VARIANT_DIFromDec(*ppDecRight
, &di
);
4487 *ppDecRight
= &pDecOut
[1];
4492 while (i
-- > 0 && !VARIANT_int_iszero(di
.bitsnum
, sizeof(di
.bitsnum
)/sizeof(DWORD
)))
4494 remainder
= VARIANT_int_divbychar(di
.bitsnum
, sizeof(di
.bitsnum
)/sizeof(DWORD
), 10);
4495 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4498 /* round up the result - native oleaut32 does this */
4499 if (remainder
>= 5) {
4500 for (remainder
= 1, i
= 0; i
< sizeof(di
.bitsnum
)/sizeof(DWORD
) && remainder
; i
++) {
4501 ULONGLONG digit
= di
.bitsnum
[i
] + 1;
4502 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4503 di
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
4507 VARIANT_DecFromDI(&di
, &pDecOut
[1]);
4511 /* Add two unsigned 32 bit values with overflow */
4512 static ULONG
VARIANT_Add(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4514 ULARGE_INTEGER ul64
;
4516 ul64
.QuadPart
= (ULONG64
)ulLeft
+ (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4517 *pulHigh
= ul64
.u
.HighPart
;
4518 return ul64
.u
.LowPart
;
4521 /* Subtract two unsigned 32 bit values with underflow */
4522 static ULONG
VARIANT_Sub(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4524 BOOL invert
= FALSE
;
4525 ULARGE_INTEGER ul64
;
4527 ul64
.QuadPart
= (LONG64
)ulLeft
- (ULONG64
)ulRight
;
4528 if (ulLeft
< ulRight
)
4531 if (ul64
.QuadPart
> (ULONG64
)*pulHigh
)
4532 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4535 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4539 ul64
.u
.HighPart
= -ul64
.u
.HighPart
;
4541 *pulHigh
= ul64
.u
.HighPart
;
4542 return ul64
.u
.LowPart
;
4545 /* Multiply two unsigned 32 bit values with overflow */
4546 static ULONG
VARIANT_Mul(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4548 ULARGE_INTEGER ul64
;
4550 ul64
.QuadPart
= (ULONG64
)ulLeft
* (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4551 *pulHigh
= ul64
.u
.HighPart
;
4552 return ul64
.u
.LowPart
;
4555 /* Compare two decimals that have the same scale */
4556 static inline int VARIANT_DecCmp(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
)
4558 if ( DEC_HI32(pDecLeft
) < DEC_HI32(pDecRight
) ||
4559 (DEC_HI32(pDecLeft
) <= DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) < DEC_LO64(pDecRight
)))
4561 else if (DEC_HI32(pDecLeft
) == DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) == DEC_LO64(pDecRight
))
4566 /************************************************************************
4567 * VarDecAdd (OLEAUT32.177)
4569 * Add one DECIMAL to another.
4572 * pDecLeft [I] Source
4573 * pDecRight [I] Value to add
4574 * pDecOut [O] Destination
4578 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4580 HRESULT WINAPI
VarDecAdd(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
4585 hRet
= VARIANT_DecScale(&pDecLeft
, &pDecRight
, scaled
);
4587 if (SUCCEEDED(hRet
))
4589 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4591 BYTE sign
= DECIMAL_POS
;
4594 /* Correct for the sign of the result */
4595 if (DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4597 /* -x + -y : Negative */
4599 goto VarDecAdd_AsPositive
;
4601 else if (DEC_SIGN(pDecLeft
) && !DEC_SIGN(pDecRight
))
4603 cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4605 /* -x + y : Negative if x > y */
4609 VarDecAdd_AsNegative
:
4610 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4611 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4612 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4616 VarDecAdd_AsInvertedNegative
:
4617 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecRight
), DEC_LO32(pDecLeft
), &overflow
);
4618 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecRight
), DEC_MID32(pDecLeft
), &overflow
);
4619 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecRight
), DEC_HI32(pDecLeft
), &overflow
);
4622 else if (!DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4624 cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4626 /* x + -y : Negative if x <= y */
4630 goto VarDecAdd_AsInvertedNegative
;
4632 goto VarDecAdd_AsNegative
;
4636 /* x + y : Positive */
4637 VarDecAdd_AsPositive
:
4638 DEC_LO32(pDecOut
) = VARIANT_Add(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4639 DEC_MID32(pDecOut
) = VARIANT_Add(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4640 DEC_HI32(pDecOut
) = VARIANT_Add(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4644 return DISP_E_OVERFLOW
; /* overflowed */
4646 DEC_SCALE(pDecOut
) = DEC_SCALE(pDecLeft
);
4647 DEC_SIGN(pDecOut
) = sign
;
4652 /* translate from external DECIMAL format into an internal representation */
4653 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
)
4655 to
->scale
= DEC_SCALE(from
);
4656 to
->sign
= DEC_SIGN(from
) ? 1 : 0;
4658 to
->bitsnum
[0] = DEC_LO32(from
);
4659 to
->bitsnum
[1] = DEC_MID32(from
);
4660 to
->bitsnum
[2] = DEC_HI32(from
);
4663 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
)
4666 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_NEG
, from
->scale
);
4668 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_POS
, from
->scale
);
4671 DEC_LO32(to
) = from
->bitsnum
[0];
4672 DEC_MID32(to
) = from
->bitsnum
[1];
4673 DEC_HI32(to
) = from
->bitsnum
[2];
4676 /* clear an internal representation of a DECIMAL */
4677 static void VARIANT_DI_clear(VARIANT_DI
* i
)
4679 memset(i
, 0, sizeof(VARIANT_DI
));
4682 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4683 size is supported. The value in p is replaced by the quotient of the division, and
4684 the remainder is returned as a result. This routine is most often used with a divisor
4685 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4687 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
)
4692 } else if (divisor
== 1) {
4693 /* dividend remains unchanged */
4696 unsigned char remainder
= 0;
4697 ULONGLONG iTempDividend
;
4700 for (i
= n
- 1; i
>= 0 && !p
[i
]; i
--); /* skip leading zeros */
4701 for (; i
>= 0; i
--) {
4702 iTempDividend
= ((ULONGLONG
)remainder
<< 32) + p
[i
];
4703 remainder
= iTempDividend
% divisor
;
4704 p
[i
] = iTempDividend
/ divisor
;
4711 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4712 static BOOL
VARIANT_int_iszero(const DWORD
* p
, unsigned int n
)
4714 for (; n
> 0; n
--) if (*p
++ != 0) return FALSE
;
4718 /* multiply two DECIMALS, without changing either one, and place result in third
4719 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4720 digits when scale > 0 in order to fit an overflowing result. Final overflow
4723 static int VARIANT_DI_mul(const VARIANT_DI
* a
, const VARIANT_DI
* b
, VARIANT_DI
* result
)
4725 BOOL r_overflow
= FALSE
;
4727 signed int mulstart
;
4729 VARIANT_DI_clear(result
);
4730 result
->sign
= (a
->sign
^ b
->sign
) ? 1 : 0;
4732 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4733 of the result is formed by adding the scales of the operands.
4735 result
->scale
= a
->scale
+ b
->scale
;
4736 memset(running
, 0, sizeof(running
));
4738 /* count number of leading zero-bytes in operand A */
4739 for (mulstart
= sizeof(a
->bitsnum
)/sizeof(DWORD
) - 1; mulstart
>= 0 && !a
->bitsnum
[mulstart
]; mulstart
--);
4741 /* result is 0, because operand A is 0 */
4745 unsigned char remainder
= 0;
4748 /* perform actual multiplication */
4749 for (iA
= 0; iA
<= mulstart
; iA
++) {
4753 for (iOverflowMul
= 0, iB
= 0; iB
< sizeof(b
->bitsnum
)/sizeof(DWORD
); iB
++) {
4757 iRV
= VARIANT_Mul(b
->bitsnum
[iB
], a
->bitsnum
[iA
], &iOverflowMul
);
4760 running
[iR
] = VARIANT_Add(running
[iR
], 0, &iRV
);
4766 /* Too bad - native oleaut does not do this, so we should not either */
4768 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4769 This operation should not lose significant digits, and gives an
4770 opportunity to reduce the possibility of overflows in future
4771 operations issued by the application.
4773 while (result
->scale
> 0) {
4774 memcpy(quotient
, running
, sizeof(quotient
));
4775 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4776 if (remainder
> 0) break;
4777 memcpy(running
, quotient
, sizeof(quotient
));
4781 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4782 This operation *will* lose significant digits of the result because
4783 all the factors of 10 were consumed by the previous operation.
4785 while (result
->scale
> 0 && !VARIANT_int_iszero(
4786 running
+ sizeof(result
->bitsnum
) / sizeof(DWORD
),
4787 (sizeof(running
) - sizeof(result
->bitsnum
)) / sizeof(DWORD
))) {
4789 remainder
= VARIANT_int_divbychar(running
, sizeof(running
) / sizeof(DWORD
), 10);
4790 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4794 /* round up the result - native oleaut32 does this */
4795 if (remainder
>= 5) {
4797 for (remainder
= 1, i
= 0; i
< sizeof(running
)/sizeof(DWORD
) && remainder
; i
++) {
4798 ULONGLONG digit
= running
[i
] + 1;
4799 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4800 running
[i
] = digit
& 0xFFFFFFFF;
4804 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4805 and copy result bits into result structure
4807 r_overflow
= !VARIANT_int_iszero(
4808 running
+ sizeof(result
->bitsnum
)/sizeof(DWORD
),
4809 (sizeof(running
) - sizeof(result
->bitsnum
))/sizeof(DWORD
));
4810 memcpy(result
->bitsnum
, running
, sizeof(result
->bitsnum
));
4815 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4816 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4817 success, FALSE if insufficient space in output buffer.
4819 static BOOL
VARIANT_DI_tostringW(const VARIANT_DI
* a
, WCHAR
* s
, unsigned int n
)
4821 BOOL overflow
= FALSE
;
4823 unsigned char remainder
;
4826 /* place negative sign */
4827 if (!VARIANT_int_iszero(a
->bitsnum
, sizeof(a
->bitsnum
) / sizeof(DWORD
)) && a
->sign
) {
4832 else overflow
= TRUE
;
4835 /* prepare initial 0 */
4840 } else overflow
= TRUE
;
4844 memcpy(quotient
, a
->bitsnum
, sizeof(a
->bitsnum
));
4845 while (!overflow
&& !VARIANT_int_iszero(quotient
, sizeof(quotient
) / sizeof(DWORD
))) {
4846 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4850 s
[i
++] = '0' + remainder
;
4855 if (!overflow
&& !VARIANT_int_iszero(a
->bitsnum
, sizeof(a
->bitsnum
) / sizeof(DWORD
))) {
4857 /* reverse order of digits */
4858 WCHAR
* x
= s
; WCHAR
* y
= s
+ i
- 1;
4865 /* check for decimal point. "i" now has string length */
4866 if (i
<= a
->scale
) {
4867 unsigned int numzeroes
= a
->scale
+ 1 - i
;
4868 if (i
+ 1 + numzeroes
>= n
) {
4871 memmove(s
+ numzeroes
, s
, (i
+ 1) * sizeof(WCHAR
));
4873 while (numzeroes
> 0) {
4874 s
[--numzeroes
] = '0';
4879 /* place decimal point */
4881 unsigned int periodpos
= i
- a
->scale
;
4885 memmove(s
+ periodpos
+ 1, s
+ periodpos
, (i
+ 1 - periodpos
) * sizeof(WCHAR
));
4886 s
[periodpos
] = '.'; i
++;
4888 /* remove extra zeros at the end, if any */
4889 while (s
[i
- 1] == '0') s
[--i
] = '\0';
4890 if (s
[i
- 1] == '.') s
[--i
] = '\0';
4898 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4899 static void VARIANT_int_shiftleft(DWORD
* p
, unsigned int n
, unsigned int shift
)
4904 /* shift whole DWORDs to the left */
4907 memmove(p
+ 1, p
, (n
- 1) * sizeof(DWORD
));
4908 *p
= 0; shift
-= 32;
4911 /* shift remainder (1..31 bits) */
4913 if (shift
> 0) for (i
= 0; i
< n
; i
++)
4916 b
= p
[i
] >> (32 - shift
);
4917 p
[i
] = (p
[i
] << shift
) | shifted
;
4922 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4923 Value at v is incremented by the value at p. Any size is supported, provided
4924 that v is not shorter than p. Any unapplied carry is returned as a result.
4926 static unsigned char VARIANT_int_add(DWORD
* v
, unsigned int nv
, const DWORD
* p
,
4929 unsigned char carry
= 0;
4935 for (i
= 0; i
< np
; i
++) {
4936 sum
= (ULONGLONG
)v
[i
]
4939 v
[i
] = sum
& 0xffffffff;
4942 for (; i
< nv
&& carry
; i
++) {
4943 sum
= (ULONGLONG
)v
[i
]
4945 v
[i
] = sum
& 0xffffffff;
4952 /* perform integral division with operand p as dividend. Parameter n indicates
4953 number of available DWORDs in divisor p, but available space in p must be
4954 actually at least 2 * n DWORDs, because the remainder of the integral
4955 division is built in the next n DWORDs past the start of the quotient. This
4956 routine replaces the dividend in p with the quotient, and appends n
4957 additional DWORDs for the remainder.
4959 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4960 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4961 source code to the VLI (Very Large Integer) division operator. This algorithm
4962 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4963 variably-scaled integers such as the MS DECIMAL representation.
4965 static void VARIANT_int_div(DWORD
* p
, unsigned int n
, const DWORD
* divisor
,
4970 DWORD
* negdivisor
= tempsub
+ n
;
4972 /* build 2s-complement of divisor */
4973 for (i
= 0; i
< n
; i
++) negdivisor
[i
] = (i
< dn
) ? ~divisor
[i
] : 0xFFFFFFFF;
4975 VARIANT_int_add(negdivisor
, n
, p
+ n
, 1);
4976 memset(p
+ n
, 0, n
* sizeof(DWORD
));
4978 /* skip all leading zero DWORDs in quotient */
4979 for (i
= 0; i
< n
&& !p
[n
- 1]; i
++) VARIANT_int_shiftleft(p
, n
, 32);
4980 /* i is now number of DWORDs left to process */
4981 for (i
<<= 5; i
< (n
<< 5); i
++) {
4982 VARIANT_int_shiftleft(p
, n
<< 1, 1); /* shl quotient+remainder */
4984 /* trial subtraction */
4985 memcpy(tempsub
, p
+ n
, n
* sizeof(DWORD
));
4986 VARIANT_int_add(tempsub
, n
, negdivisor
, n
);
4988 /* check whether result of subtraction was negative */
4989 if ((tempsub
[n
- 1] & 0x80000000) == 0) {
4990 memcpy(p
+ n
, tempsub
, n
* sizeof(DWORD
));
4996 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4997 static unsigned char VARIANT_int_mulbychar(DWORD
* p
, unsigned int n
, unsigned char m
)
5002 for (iOverflowMul
= 0, i
= 0; i
< n
; i
++)
5003 p
[i
] = VARIANT_Mul(p
[i
], m
, &iOverflowMul
);
5004 return (unsigned char)iOverflowMul
;
5007 /* increment value in A by the value indicated in B, with scale adjusting.
5008 Modifies parameters by adjusting scales. Returns 0 if addition was
5009 successful, nonzero if a parameter underflowed before it could be
5010 successfully used in the addition.
5012 static int VARIANT_int_addlossy(
5013 DWORD
* a
, int * ascale
, unsigned int an
,
5014 DWORD
* b
, int * bscale
, unsigned int bn
)
5018 if (VARIANT_int_iszero(a
, an
)) {
5019 /* if A is zero, copy B into A, after removing digits */
5020 while (bn
> an
&& !VARIANT_int_iszero(b
+ an
, bn
- an
)) {
5021 VARIANT_int_divbychar(b
, bn
, 10);
5024 memcpy(a
, b
, an
* sizeof(DWORD
));
5026 } else if (!VARIANT_int_iszero(b
, bn
)) {
5027 unsigned int tn
= an
+ 1;
5030 if (bn
+ 1 > tn
) tn
= bn
+ 1;
5031 if (*ascale
!= *bscale
) {
5032 /* first (optimistic) try - try to scale down the one with the bigger
5033 scale, while this number is divisible by 10 */
5034 DWORD
* digitchosen
;
5035 unsigned int nchosen
;
5039 if (*ascale
< *bscale
) {
5040 targetscale
= *ascale
;
5041 scalechosen
= bscale
;
5045 targetscale
= *bscale
;
5046 scalechosen
= ascale
;
5050 memset(t
, 0, tn
* sizeof(DWORD
));
5051 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5053 /* divide by 10 until target scale is reached */
5054 while (*scalechosen
> targetscale
) {
5055 unsigned char remainder
= VARIANT_int_divbychar(t
, tn
, 10);
5058 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5063 if (*ascale
!= *bscale
) {
5064 DWORD
* digitchosen
;
5065 unsigned int nchosen
;
5069 /* try to scale up the one with the smaller scale */
5070 if (*ascale
> *bscale
) {
5071 targetscale
= *ascale
;
5072 scalechosen
= bscale
;
5076 targetscale
= *bscale
;
5077 scalechosen
= ascale
;
5081 memset(t
, 0, tn
* sizeof(DWORD
));
5082 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5084 /* multiply by 10 until target scale is reached, or
5085 significant bytes overflow the number
5087 while (*scalechosen
< targetscale
&& t
[nchosen
] == 0) {
5088 VARIANT_int_mulbychar(t
, tn
, 10);
5089 if (t
[nchosen
] == 0) {
5090 /* still does not overflow */
5092 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5097 if (*ascale
!= *bscale
) {
5098 /* still different? try to scale down the one with the bigger scale
5099 (this *will* lose significant digits) */
5100 DWORD
* digitchosen
;
5101 unsigned int nchosen
;
5105 if (*ascale
< *bscale
) {
5106 targetscale
= *ascale
;
5107 scalechosen
= bscale
;
5111 targetscale
= *bscale
;
5112 scalechosen
= ascale
;
5116 memset(t
, 0, tn
* sizeof(DWORD
));
5117 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5119 /* divide by 10 until target scale is reached */
5120 while (*scalechosen
> targetscale
) {
5121 VARIANT_int_divbychar(t
, tn
, 10);
5123 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5127 /* check whether any of the operands still has significant digits
5130 if (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
)) {
5133 /* at this step, both numbers have the same scale and can be added
5134 as integers. However, the result might not fit in A, so further
5135 scaling down might be necessary.
5137 while (!underflow
) {
5138 memset(t
, 0, tn
* sizeof(DWORD
));
5139 memcpy(t
, a
, an
* sizeof(DWORD
));
5141 VARIANT_int_add(t
, tn
, b
, bn
);
5142 if (VARIANT_int_iszero(t
+ an
, tn
- an
)) {
5143 /* addition was successful */
5144 memcpy(a
, t
, an
* sizeof(DWORD
));
5147 /* addition overflowed - remove significant digits
5148 from both operands and try again */
5149 VARIANT_int_divbychar(a
, an
, 10); (*ascale
)--;
5150 VARIANT_int_divbychar(b
, bn
, 10); (*bscale
)--;
5151 /* check whether any operand keeps significant digits after
5152 scaledown (underflow case 2)
5154 underflow
= (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
));
5162 /* perform complete DECIMAL division in the internal representation. Returns
5163 0 if the division was completed (even if quotient is set to 0), or nonzero
5164 in case of quotient overflow.
5166 static HRESULT
VARIANT_DI_div(const VARIANT_DI
* dividend
, const VARIANT_DI
* divisor
,
5167 VARIANT_DI
* quotient
, BOOL round_remainder
)
5169 HRESULT r_overflow
= S_OK
;
5171 if (VARIANT_int_iszero(divisor
->bitsnum
, sizeof(divisor
->bitsnum
)/sizeof(DWORD
))) {
5173 r_overflow
= DISP_E_DIVBYZERO
;
5174 } else if (VARIANT_int_iszero(dividend
->bitsnum
, sizeof(dividend
->bitsnum
)/sizeof(DWORD
))) {
5175 VARIANT_DI_clear(quotient
);
5177 int quotientscale
, remainderscale
, tempquotientscale
;
5178 DWORD remainderplusquotient
[8];
5181 quotientscale
= remainderscale
= (int)dividend
->scale
- (int)divisor
->scale
;
5182 tempquotientscale
= quotientscale
;
5183 VARIANT_DI_clear(quotient
);
5184 quotient
->sign
= (dividend
->sign
^ divisor
->sign
) ? 1 : 0;
5186 /* The following strategy is used for division
5187 1) if there was a nonzero remainder from previous iteration, use it as
5188 dividend for this iteration, else (for first iteration) use intended
5190 2) perform integer division in temporary buffer, develop quotient in
5191 low-order part, remainder in high-order part
5192 3) add quotient from step 2 to final result, with possible loss of
5194 4) multiply integer part of remainder by 10, while incrementing the
5195 scale of the remainder. This operation preserves the intended value
5197 5) loop to step 1 until one of the following is true:
5198 a) remainder is zero (exact division achieved)
5199 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5201 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5202 memcpy(remainderplusquotient
, dividend
->bitsnum
, sizeof(dividend
->bitsnum
));
5205 remainderplusquotient
, 4,
5206 divisor
->bitsnum
, sizeof(divisor
->bitsnum
)/sizeof(DWORD
));
5207 underflow
= VARIANT_int_addlossy(
5208 quotient
->bitsnum
, "ientscale
, sizeof(quotient
->bitsnum
) / sizeof(DWORD
),
5209 remainderplusquotient
, &tempquotientscale
, 4);
5210 if (round_remainder
) {
5211 if(remainderplusquotient
[4] >= 5){
5213 unsigned char remainder
= 1;
5214 for (i
= 0; i
< sizeof(quotient
->bitsnum
) / sizeof(DWORD
) && remainder
; i
++) {
5215 ULONGLONG digit
= quotient
->bitsnum
[i
] + 1;
5216 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5217 quotient
->bitsnum
[i
] = digit
& 0xFFFFFFFF;
5220 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5222 VARIANT_int_mulbychar(remainderplusquotient
+ 4, 4, 10);
5223 memcpy(remainderplusquotient
, remainderplusquotient
+ 4, 4 * sizeof(DWORD
));
5225 tempquotientscale
= ++remainderscale
;
5226 } while (!underflow
&& !VARIANT_int_iszero(remainderplusquotient
+ 4, 4));
5228 /* quotient scale might now be negative (extremely big number). If, so, try
5229 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5230 until scale is 0. If this cannot be done, it is a real overflow.
5232 while (r_overflow
== S_OK
&& quotientscale
< 0) {
5233 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5234 memcpy(remainderplusquotient
, quotient
->bitsnum
, sizeof(quotient
->bitsnum
));
5235 VARIANT_int_mulbychar(remainderplusquotient
, sizeof(remainderplusquotient
)/sizeof(DWORD
), 10);
5236 if (VARIANT_int_iszero(remainderplusquotient
+ sizeof(quotient
->bitsnum
)/sizeof(DWORD
),
5237 (sizeof(remainderplusquotient
) - sizeof(quotient
->bitsnum
))/sizeof(DWORD
))) {
5239 memcpy(quotient
->bitsnum
, remainderplusquotient
, sizeof(quotient
->bitsnum
));
5240 } else r_overflow
= DISP_E_OVERFLOW
;
5242 if (r_overflow
== S_OK
) {
5243 if (quotientscale
<= 255) quotient
->scale
= quotientscale
;
5244 else VARIANT_DI_clear(quotient
);
5250 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5251 with an undefined scale, which will be assigned to (if possible). It also
5252 receives an exponent of 2. This procedure will then manipulate the mantissa
5253 and calculate a corresponding scale, so that the exponent2 value is assimilated
5254 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5255 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5257 static HRESULT
VARIANT_DI_normalize(VARIANT_DI
* val
, int exponent2
, BOOL isDouble
)
5259 HRESULT hres
= S_OK
;
5260 int exponent5
, exponent10
;
5262 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5263 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5264 exponent10 might be used to set the VARIANT_DI scale directly. However,
5265 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5266 exponent5
= -exponent2
;
5267 exponent10
= exponent2
;
5269 /* Handle exponent5 > 0 */
5270 while (exponent5
> 0) {
5274 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5275 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5276 somehow the mantissa should be divided by 2. */
5277 if ((val
->bitsnum
[0] & 1) == 0) {
5278 /* The mantissa is divisible by 2. Therefore the division can be done
5279 without losing significant digits. */
5280 exponent10
++; exponent5
--;
5283 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5284 val
->bitsnum
[2] >>= 1;
5285 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5286 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5287 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5289 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5290 be multiplied by 5, unless the multiplication overflows. */
5291 DWORD temp_bitsnum
[3];
5295 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5296 if (0 == VARIANT_int_mulbychar(temp_bitsnum
, 3, 5)) {
5297 /* Multiplication succeeded without overflow, so copy result back
5299 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5301 /* Mask out 3 extraneous bits introduced by the multiply */
5303 /* Multiplication by 5 overflows. The mantissa should be divided
5304 by 2, and therefore will lose significant digits. */
5308 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5309 val
->bitsnum
[2] >>= 1;
5310 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5311 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5312 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5317 /* Handle exponent5 < 0 */
5318 while (exponent5
< 0) {
5319 /* In order to divide the value represented by the VARIANT_DI by 5, it
5320 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5321 and the mantissa should be multiplied by 2 */
5322 if ((val
->bitsnum
[2] & 0x80000000) == 0) {
5323 /* The mantissa can withstand a shift-left without overflowing */
5324 exponent10
--; exponent5
++;
5325 VARIANT_int_shiftleft(val
->bitsnum
, 3, 1);
5327 /* The mantissa would overflow if shifted. Therefore it should be
5328 directly divided by 5. This will lose significant digits, unless
5329 by chance the mantissa happens to be divisible by 5 */
5331 VARIANT_int_divbychar(val
->bitsnum
, 3, 5);
5335 /* At this point, the mantissa has assimilated the exponent5, but the
5336 exponent10 might not be suitable for assignment. The exponent10 must be
5337 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5338 down appropriately. */
5339 while (hres
== S_OK
&& exponent10
> 0) {
5340 /* In order to bring exponent10 down to 0, the mantissa should be
5341 multiplied by 10 to compensate. If the exponent10 is too big, this
5342 will cause the mantissa to overflow. */
5343 if (0 == VARIANT_int_mulbychar(val
->bitsnum
, 3, 10)) {
5346 hres
= DISP_E_OVERFLOW
;
5349 while (exponent10
< -DEC_MAX_SCALE
) {
5351 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5352 be divided by 10 to compensate. If the exponent10 is too small, this
5353 will cause the mantissa to underflow and become 0 */
5354 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5356 if (VARIANT_int_iszero(val
->bitsnum
, 3)) {
5357 /* Underflow, unable to keep dividing */
5359 } else if (rem10
>= 5) {
5361 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5364 /* This step is required in order to remove excess bits of precision from the
5365 end of the bit representation, down to the precision guaranteed by the
5366 floating point number. */
5368 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || (val
->bitsnum
[2] == 0 && (val
->bitsnum
[1] & 0xFFE00000) != 0))) {
5371 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5375 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5379 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || val
->bitsnum
[1] != 0 ||
5380 (val
->bitsnum
[2] == 0 && val
->bitsnum
[1] == 0 && (val
->bitsnum
[0] & 0xFF000000) != 0))) {
5383 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5387 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5391 /* Remove multiples of 10 from the representation */
5392 while (exponent10
< 0) {
5393 DWORD temp_bitsnum
[3];
5395 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5396 if (0 == VARIANT_int_divbychar(temp_bitsnum
, 3, 10)) {
5398 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5402 /* Scale assignment */
5403 if (hres
== S_OK
) val
->scale
= -exponent10
;
5412 unsigned int m
: 23;
5413 unsigned int exp_bias
: 8;
5414 unsigned int sign
: 1;
5419 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5420 intermediate string step. */
5421 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
)
5423 HRESULT hres
= S_OK
;
5428 /* Detect special cases */
5429 if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0) {
5430 /* Floating-point zero */
5431 VARIANT_DI_clear(dest
);
5432 } else if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0xFF) {
5433 /* Floating-point infinity */
5434 hres
= DISP_E_OVERFLOW
;
5435 } else if (fx
.i
.exp_bias
== 0xFF) {
5436 /* Floating-point NaN */
5437 hres
= DISP_E_BADVARTYPE
;
5440 VARIANT_DI_clear(dest
);
5442 exponent2
= fx
.i
.exp_bias
- 127; /* Get unbiased exponent */
5443 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5445 /* Copy significant bits to VARIANT_DI mantissa */
5446 dest
->bitsnum
[0] = fx
.i
.m
;
5447 dest
->bitsnum
[0] &= 0x007FFFFF;
5448 if (fx
.i
.exp_bias
== 0) {
5449 /* Denormalized number - correct exponent */
5452 /* Add hidden bit to mantissa */
5453 dest
->bitsnum
[0] |= 0x00800000;
5456 /* The act of copying a FP mantissa as integer bits is equivalent to
5457 shifting left the mantissa 23 bits. The exponent2 is reduced to
5461 hres
= VARIANT_DI_normalize(dest
, exponent2
, FALSE
);
5471 unsigned int m_lo
: 32; /* 52 bits of precision */
5472 unsigned int m_hi
: 20;
5473 unsigned int exp_bias
: 11; /* bias == 1023 */
5474 unsigned int sign
: 1;
5479 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5480 intermediate string step. */
5481 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
)
5483 HRESULT hres
= S_OK
;
5488 /* Detect special cases */
5489 if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0) {
5490 /* Floating-point zero */
5491 VARIANT_DI_clear(dest
);
5492 } else if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0x7FF) {
5493 /* Floating-point infinity */
5494 hres
= DISP_E_OVERFLOW
;
5495 } else if (fx
.i
.exp_bias
== 0x7FF) {
5496 /* Floating-point NaN */
5497 hres
= DISP_E_BADVARTYPE
;
5500 VARIANT_DI_clear(dest
);
5502 exponent2
= fx
.i
.exp_bias
- 1023; /* Get unbiased exponent */
5503 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5505 /* Copy significant bits to VARIANT_DI mantissa */
5506 dest
->bitsnum
[0] = fx
.i
.m_lo
;
5507 dest
->bitsnum
[1] = fx
.i
.m_hi
;
5508 dest
->bitsnum
[1] &= 0x000FFFFF;
5509 if (fx
.i
.exp_bias
== 0) {
5510 /* Denormalized number - correct exponent */
5513 /* Add hidden bit to mantissa */
5514 dest
->bitsnum
[1] |= 0x00100000;
5517 /* The act of copying a FP mantissa as integer bits is equivalent to
5518 shifting left the mantissa 52 bits. The exponent2 is reduced to
5522 hres
= VARIANT_DI_normalize(dest
, exponent2
, TRUE
);
5528 static HRESULT
VARIANT_do_division(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
, DECIMAL
*pDecOut
,
5531 HRESULT hRet
= S_OK
;
5532 VARIANT_DI di_left
, di_right
, di_result
;
5535 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5536 VARIANT_DIFromDec(pDecRight
, &di_right
);
5537 divresult
= VARIANT_DI_div(&di_left
, &di_right
, &di_result
, round
);
5538 if (divresult
!= S_OK
)
5540 /* division actually overflowed */
5547 if (di_result
.scale
> DEC_MAX_SCALE
)
5549 unsigned char remainder
= 0;
5551 /* division underflowed. In order to comply with the MSDN
5552 specifications for DECIMAL ranges, some significant digits
5555 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5557 while (di_result
.scale
> DEC_MAX_SCALE
&&
5558 !VARIANT_int_iszero(di_result
.bitsnum
, sizeof(di_result
.bitsnum
) / sizeof(DWORD
)))
5560 remainder
= VARIANT_int_divbychar(di_result
.bitsnum
, sizeof(di_result
.bitsnum
) / sizeof(DWORD
), 10);
5563 if (di_result
.scale
> DEC_MAX_SCALE
)
5565 WARN("result underflowed, setting to 0\n");
5566 di_result
.scale
= 0;
5569 else if (remainder
>= 5) /* round up result - native oleaut32 does this */
5572 for (remainder
= 1, i
= 0; i
< sizeof(di_result
.bitsnum
) / sizeof(DWORD
) && remainder
; i
++) {
5573 ULONGLONG digit
= di_result
.bitsnum
[i
] + 1;
5574 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5575 di_result
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
5579 VARIANT_DecFromDI(&di_result
, pDecOut
);
5584 /************************************************************************
5585 * VarDecDiv (OLEAUT32.178)
5587 * Divide one DECIMAL by another.
5590 * pDecLeft [I] Source
5591 * pDecRight [I] Value to divide by
5592 * pDecOut [O] Destination
5596 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5598 HRESULT WINAPI
VarDecDiv(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5600 if (!pDecLeft
|| !pDecRight
|| !pDecOut
) return E_INVALIDARG
;
5602 return VARIANT_do_division(pDecLeft
, pDecRight
, pDecOut
, FALSE
);
5605 /************************************************************************
5606 * VarDecMul (OLEAUT32.179)
5608 * Multiply one DECIMAL by another.
5611 * pDecLeft [I] Source
5612 * pDecRight [I] Value to multiply by
5613 * pDecOut [O] Destination
5617 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5619 HRESULT WINAPI
VarDecMul(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5621 HRESULT hRet
= S_OK
;
5622 VARIANT_DI di_left
, di_right
, di_result
;
5625 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5626 VARIANT_DIFromDec(pDecRight
, &di_right
);
5627 mulresult
= VARIANT_DI_mul(&di_left
, &di_right
, &di_result
);
5630 /* multiplication actually overflowed */
5631 hRet
= DISP_E_OVERFLOW
;
5635 if (di_result
.scale
> DEC_MAX_SCALE
)
5637 /* multiplication underflowed. In order to comply with the MSDN
5638 specifications for DECIMAL ranges, some significant digits
5641 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5643 while (di_result
.scale
> DEC_MAX_SCALE
&&
5644 !VARIANT_int_iszero(di_result
.bitsnum
, sizeof(di_result
.bitsnum
)/sizeof(DWORD
)))
5646 VARIANT_int_divbychar(di_result
.bitsnum
, sizeof(di_result
.bitsnum
)/sizeof(DWORD
), 10);
5649 if (di_result
.scale
> DEC_MAX_SCALE
)
5651 WARN("result underflowed, setting to 0\n");
5652 di_result
.scale
= 0;
5656 VARIANT_DecFromDI(&di_result
, pDecOut
);
5661 /************************************************************************
5662 * VarDecSub (OLEAUT32.181)
5664 * Subtract one DECIMAL from another.
5667 * pDecLeft [I] Source
5668 * pDecRight [I] DECIMAL to subtract from pDecLeft
5669 * pDecOut [O] Destination
5672 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5674 HRESULT WINAPI
VarDecSub(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5678 /* Implement as addition of the negative */
5679 VarDecNeg(pDecRight
, &decRight
);
5680 return VarDecAdd(pDecLeft
, &decRight
, pDecOut
);
5683 /************************************************************************
5684 * VarDecAbs (OLEAUT32.182)
5686 * Convert a DECIMAL into its absolute value.
5690 * pDecOut [O] Destination
5693 * S_OK. This function does not fail.
5695 HRESULT WINAPI
VarDecAbs(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5698 DEC_SIGN(pDecOut
) &= ~DECIMAL_NEG
;
5702 /************************************************************************
5703 * VarDecFix (OLEAUT32.187)
5705 * Return the integer portion of a DECIMAL.
5709 * pDecOut [O] Destination
5713 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5716 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5717 * negative numbers away from 0, while this function rounds them towards zero.
5719 HRESULT WINAPI
VarDecFix(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5724 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5725 return E_INVALIDARG
;
5727 if (!DEC_SCALE(pDecIn
))
5729 *pDecOut
= *pDecIn
; /* Already an integer */
5733 hr
= VarR8FromDec(pDecIn
, &dbl
);
5734 if (SUCCEEDED(hr
)) {
5735 LONGLONG rounded
= dbl
;
5737 hr
= VarDecFromI8(rounded
, pDecOut
);
5742 /************************************************************************
5743 * VarDecInt (OLEAUT32.188)
5745 * Return the integer portion of a DECIMAL.
5749 * pDecOut [O] Destination
5753 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5756 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5757 * negative numbers towards 0, while this function rounds them away from zero.
5759 HRESULT WINAPI
VarDecInt(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5764 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5765 return E_INVALIDARG
;
5767 if (!(DEC_SIGN(pDecIn
) & DECIMAL_NEG
) || !DEC_SCALE(pDecIn
))
5768 return VarDecFix(pDecIn
, pDecOut
); /* The same, if +ve or no fractionals */
5770 hr
= VarR8FromDec(pDecIn
, &dbl
);
5771 if (SUCCEEDED(hr
)) {
5772 LONGLONG rounded
= dbl
>= 0.0 ? dbl
+ 0.5 : dbl
- 0.5;
5774 hr
= VarDecFromI8(rounded
, pDecOut
);
5779 /************************************************************************
5780 * VarDecNeg (OLEAUT32.189)
5782 * Change the sign of a DECIMAL.
5786 * pDecOut [O] Destination
5789 * S_OK. This function does not fail.
5791 HRESULT WINAPI
VarDecNeg(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5794 DEC_SIGN(pDecOut
) ^= DECIMAL_NEG
;
5798 /************************************************************************
5799 * VarDecRound (OLEAUT32.203)
5801 * Change the precision of a DECIMAL.
5805 * cDecimals [I] New number of decimals to keep
5806 * pDecOut [O] Destination
5809 * Success: S_OK. pDecOut contains the rounded value.
5810 * Failure: E_INVALIDARG if any argument is invalid.
5812 HRESULT WINAPI
VarDecRound(const DECIMAL
* pDecIn
, int cDecimals
, DECIMAL
* pDecOut
)
5814 DECIMAL divisor
, tmp
;
5818 if (cDecimals
< 0 || (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
) || DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
)
5819 return E_INVALIDARG
;
5821 if (cDecimals
>= DEC_SCALE(pDecIn
))
5823 *pDecOut
= *pDecIn
; /* More precision than we have */
5827 /* truncate significant digits and rescale */
5828 memset(&divisor
, 0, sizeof(divisor
));
5829 DEC_LO64(&divisor
) = 1;
5831 memset(&tmp
, 0, sizeof(tmp
));
5832 DEC_LO64(&tmp
) = 10;
5833 for (i
= 0; i
< DEC_SCALE(pDecIn
) - cDecimals
; ++i
)
5835 hr
= VarDecMul(&divisor
, &tmp
, &divisor
);
5840 hr
= VARIANT_do_division(pDecIn
, &divisor
, pDecOut
, TRUE
);
5844 DEC_SCALE(pDecOut
) = cDecimals
;
5849 /************************************************************************
5850 * VarDecCmp (OLEAUT32.204)
5852 * Compare two DECIMAL values.
5855 * pDecLeft [I] Source
5856 * pDecRight [I] Value to compare
5859 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5860 * is less than, equal to or greater than pDecRight respectively.
5861 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5863 HRESULT WINAPI
VarDecCmp(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
)
5868 if (!pDecLeft
|| !pDecRight
)
5871 if ((!(DEC_SIGN(pDecLeft
) & DECIMAL_NEG
)) && (DEC_SIGN(pDecRight
) & DECIMAL_NEG
) &&
5872 (DEC_HI32(pDecLeft
) | DEC_MID32(pDecLeft
) | DEC_LO32(pDecLeft
)))
5874 else if ((DEC_SIGN(pDecLeft
) & DECIMAL_NEG
) && (!(DEC_SIGN(pDecRight
) & DECIMAL_NEG
)) &&
5875 (DEC_HI32(pDecLeft
) | DEC_MID32(pDecLeft
) | DEC_LO32(pDecLeft
)))
5878 /* Subtract right from left, and compare the result to 0 */
5879 hRet
= VarDecSub(pDecLeft
, pDecRight
, &result
);
5881 if (SUCCEEDED(hRet
))
5883 int non_zero
= DEC_HI32(&result
) | DEC_MID32(&result
) | DEC_LO32(&result
);
5885 if ((DEC_SIGN(&result
) & DECIMAL_NEG
) && non_zero
)
5886 hRet
= (HRESULT
)VARCMP_LT
;
5888 hRet
= (HRESULT
)VARCMP_GT
;
5890 hRet
= (HRESULT
)VARCMP_EQ
;
5895 /************************************************************************
5896 * VarDecCmpR8 (OLEAUT32.298)
5898 * Compare a DECIMAL to a double
5901 * pDecLeft [I] DECIMAL Source
5902 * dblRight [I] double to compare to pDecLeft
5905 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5906 * is less than, equal to or greater than pDecLeft respectively.
5907 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5909 HRESULT WINAPI
VarDecCmpR8(const DECIMAL
* pDecLeft
, double dblRight
)
5914 hRet
= VarDecFromR8(dblRight
, &decRight
);
5916 if (SUCCEEDED(hRet
))
5917 hRet
= VarDecCmp(pDecLeft
, &decRight
);
5925 /************************************************************************
5926 * VarBoolFromUI1 (OLEAUT32.118)
5928 * Convert a VT_UI1 to a VT_BOOL.
5932 * pBoolOut [O] Destination
5937 HRESULT WINAPI
VarBoolFromUI1(BYTE bIn
, VARIANT_BOOL
*pBoolOut
)
5939 *pBoolOut
= bIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5943 /************************************************************************
5944 * VarBoolFromI2 (OLEAUT32.119)
5946 * Convert a VT_I2 to a VT_BOOL.
5950 * pBoolOut [O] Destination
5955 HRESULT WINAPI
VarBoolFromI2(SHORT sIn
, VARIANT_BOOL
*pBoolOut
)
5957 *pBoolOut
= sIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5961 /************************************************************************
5962 * VarBoolFromI4 (OLEAUT32.120)
5964 * Convert a VT_I4 to a VT_BOOL.
5968 * pBoolOut [O] Destination
5973 HRESULT WINAPI
VarBoolFromI4(LONG lIn
, VARIANT_BOOL
*pBoolOut
)
5975 *pBoolOut
= lIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5979 /************************************************************************
5980 * VarBoolFromR4 (OLEAUT32.121)
5982 * Convert a VT_R4 to a VT_BOOL.
5986 * pBoolOut [O] Destination
5991 HRESULT WINAPI
VarBoolFromR4(FLOAT fltIn
, VARIANT_BOOL
*pBoolOut
)
5993 *pBoolOut
= fltIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5997 /************************************************************************
5998 * VarBoolFromR8 (OLEAUT32.122)
6000 * Convert a VT_R8 to a VT_BOOL.
6004 * pBoolOut [O] Destination
6009 HRESULT WINAPI
VarBoolFromR8(double dblIn
, VARIANT_BOOL
*pBoolOut
)
6011 *pBoolOut
= dblIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6015 /************************************************************************
6016 * VarBoolFromDate (OLEAUT32.123)
6018 * Convert a VT_DATE to a VT_BOOL.
6022 * pBoolOut [O] Destination
6027 HRESULT WINAPI
VarBoolFromDate(DATE dateIn
, VARIANT_BOOL
*pBoolOut
)
6029 *pBoolOut
= dateIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6033 /************************************************************************
6034 * VarBoolFromCy (OLEAUT32.124)
6036 * Convert a VT_CY to a VT_BOOL.
6040 * pBoolOut [O] Destination
6045 HRESULT WINAPI
VarBoolFromCy(CY cyIn
, VARIANT_BOOL
*pBoolOut
)
6047 *pBoolOut
= cyIn
.int64
? VARIANT_TRUE
: VARIANT_FALSE
;
6051 /************************************************************************
6052 * VARIANT_GetLocalisedText [internal]
6054 * Get a localized string from the resources
6057 BOOL
VARIANT_GetLocalisedText(LANGID langId
, DWORD dwId
, WCHAR
*lpszDest
)
6061 hrsrc
= FindResourceExW( hProxyDll
, (LPWSTR
)RT_STRING
,
6062 MAKEINTRESOURCEW((dwId
>> 4) + 1), langId
);
6065 HGLOBAL hmem
= LoadResource( hProxyDll
, hrsrc
);
6072 p
= LockResource( hmem
);
6073 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
6075 memcpy( lpszDest
, p
+ 1, *p
* sizeof(WCHAR
) );
6076 lpszDest
[*p
] = '\0';
6077 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest
), langId
);
6084 /************************************************************************
6085 * VarBoolFromStr (OLEAUT32.125)
6087 * Convert a VT_BSTR to a VT_BOOL.
6091 * lcid [I] LCID for the conversion
6092 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6093 * pBoolOut [O] Destination
6097 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6098 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6101 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6102 * it may contain (in any case mapping) the text "true" or "false".
6103 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6104 * localised text of "True" or "False" in the language specified by lcid.
6105 * - If none of these matches occur, the string is treated as a numeric string
6106 * and the boolean pBoolOut will be set according to whether the number is zero
6107 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6108 * - If the text is not numeric and does not match any of the above, then
6109 * DISP_E_TYPEMISMATCH is returned.
6111 HRESULT WINAPI
VarBoolFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, VARIANT_BOOL
*pBoolOut
)
6113 /* Any VB/VBA programmers out there should recognise these strings... */
6114 static const WCHAR szFalse
[] = { '#','F','A','L','S','E','#','\0' };
6115 static const WCHAR szTrue
[] = { '#','T','R','U','E','#','\0' };
6117 LANGID langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6118 HRESULT hRes
= S_OK
;
6120 if (!strIn
|| !pBoolOut
)
6121 return DISP_E_TYPEMISMATCH
;
6123 /* Check if we should be comparing against localised text */
6124 if (dwFlags
& VAR_LOCALBOOL
)
6126 /* Convert our LCID into a usable value */
6127 lcid
= ConvertDefaultLocale(lcid
);
6129 langId
= LANGIDFROMLCID(lcid
);
6131 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6132 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6134 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6135 * I don't think this is needed unless any of the localised text strings
6136 * contain characters that can be so mapped. In the event that this is
6137 * true for a given language (possibly some Asian languages), then strIn
6138 * should be mapped here _only_ if langId is an Id for which this can occur.
6142 /* Note that if we are not comparing against localised strings, langId
6143 * will have its default value of LANG_ENGLISH. This allows us to mimic
6144 * the native behaviour of always checking against English strings even
6145 * after we've checked for localised ones.
6147 VarBoolFromStr_CheckLocalised
:
6148 if (VARIANT_GetLocalisedText(langId
, IDS_TRUE
, szBuff
))
6150 /* Compare against localised strings, ignoring case */
6151 if (!strcmpiW(strIn
, szBuff
))
6153 *pBoolOut
= VARIANT_TRUE
; /* Matched localised 'true' text */
6156 VARIANT_GetLocalisedText(langId
, IDS_FALSE
, szBuff
);
6157 if (!strcmpiW(strIn
, szBuff
))
6159 *pBoolOut
= VARIANT_FALSE
; /* Matched localised 'false' text */
6164 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6166 /* We have checked the localised text, now check English */
6167 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6168 goto VarBoolFromStr_CheckLocalised
;
6171 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6172 if (!strcmpW(strIn
, szFalse
))
6173 *pBoolOut
= VARIANT_FALSE
;
6174 else if (!strcmpW(strIn
, szTrue
))
6175 *pBoolOut
= VARIANT_TRUE
;
6180 /* If this string is a number, convert it as one */
6181 hRes
= VarR8FromStr(strIn
, lcid
, dwFlags
, &d
);
6182 if (SUCCEEDED(hRes
)) *pBoolOut
= d
? VARIANT_TRUE
: VARIANT_FALSE
;
6187 /************************************************************************
6188 * VarBoolFromDisp (OLEAUT32.126)
6190 * Convert a VT_DISPATCH to a VT_BOOL.
6193 * pdispIn [I] Source
6194 * lcid [I] LCID for conversion
6195 * pBoolOut [O] Destination
6199 * Failure: E_INVALIDARG, if the source value is invalid
6200 * DISP_E_OVERFLOW, if the value will not fit in the destination
6201 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6203 HRESULT WINAPI
VarBoolFromDisp(IDispatch
* pdispIn
, LCID lcid
, VARIANT_BOOL
*pBoolOut
)
6205 return VARIANT_FromDisp(pdispIn
, lcid
, pBoolOut
, VT_BOOL
, 0);
6208 /************************************************************************
6209 * VarBoolFromI1 (OLEAUT32.233)
6211 * Convert a VT_I1 to a VT_BOOL.
6215 * pBoolOut [O] Destination
6220 HRESULT WINAPI
VarBoolFromI1(signed char cIn
, VARIANT_BOOL
*pBoolOut
)
6222 *pBoolOut
= cIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6226 /************************************************************************
6227 * VarBoolFromUI2 (OLEAUT32.234)
6229 * Convert a VT_UI2 to a VT_BOOL.
6233 * pBoolOut [O] Destination
6238 HRESULT WINAPI
VarBoolFromUI2(USHORT usIn
, VARIANT_BOOL
*pBoolOut
)
6240 *pBoolOut
= usIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6244 /************************************************************************
6245 * VarBoolFromUI4 (OLEAUT32.235)
6247 * Convert a VT_UI4 to a VT_BOOL.
6251 * pBoolOut [O] Destination
6256 HRESULT WINAPI
VarBoolFromUI4(ULONG ulIn
, VARIANT_BOOL
*pBoolOut
)
6258 *pBoolOut
= ulIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6262 /************************************************************************
6263 * VarBoolFromDec (OLEAUT32.236)
6265 * Convert a VT_DECIMAL to a VT_BOOL.
6269 * pBoolOut [O] Destination
6273 * Failure: E_INVALIDARG, if pDecIn is invalid.
6275 HRESULT WINAPI
VarBoolFromDec(DECIMAL
* pDecIn
, VARIANT_BOOL
*pBoolOut
)
6277 if (DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
|| (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
))
6278 return E_INVALIDARG
;
6280 if (DEC_HI32(pDecIn
) || DEC_MID32(pDecIn
) || DEC_LO32(pDecIn
))
6281 *pBoolOut
= VARIANT_TRUE
;
6283 *pBoolOut
= VARIANT_FALSE
;
6287 /************************************************************************
6288 * VarBoolFromI8 (OLEAUT32.370)
6290 * Convert a VT_I8 to a VT_BOOL.
6294 * pBoolOut [O] Destination
6299 HRESULT WINAPI
VarBoolFromI8(LONG64 llIn
, VARIANT_BOOL
*pBoolOut
)
6301 *pBoolOut
= llIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6305 /************************************************************************
6306 * VarBoolFromUI8 (OLEAUT32.371)
6308 * Convert a VT_UI8 to a VT_BOOL.
6312 * pBoolOut [O] Destination
6317 HRESULT WINAPI
VarBoolFromUI8(ULONG64 ullIn
, VARIANT_BOOL
*pBoolOut
)
6319 *pBoolOut
= ullIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6326 /* Write a number from a UI8 and sign */
6327 static WCHAR
*VARIANT_WriteNumber(ULONG64 ulVal
, WCHAR
* szOut
)
6331 WCHAR ulNextDigit
= ulVal
% 10;
6333 *szOut
-- = '0' + ulNextDigit
;
6334 ulVal
= (ulVal
- ulNextDigit
) / 10;
6341 /* Create a (possibly localised) BSTR from a UI8 and sign */
6342 static BSTR
VARIANT_MakeBstr(LCID lcid
, DWORD dwFlags
, WCHAR
*szOut
)
6344 WCHAR szConverted
[256];
6346 if (dwFlags
& VAR_NEGATIVE
)
6349 if (dwFlags
& LOCALE_USE_NLS
)
6351 /* Format the number for the locale */
6352 szConverted
[0] = '\0';
6353 GetNumberFormatW(lcid
,
6354 dwFlags
& LOCALE_NOUSEROVERRIDE
,
6355 szOut
, NULL
, szConverted
, sizeof(szConverted
)/sizeof(WCHAR
));
6356 szOut
= szConverted
;
6358 return SysAllocStringByteLen((LPCSTR
)szOut
, strlenW(szOut
) * sizeof(WCHAR
));
6361 /* Create a (possibly localised) BSTR from a UI8 and sign */
6362 static HRESULT
VARIANT_BstrFromUInt(ULONG64 ulVal
, LCID lcid
, DWORD dwFlags
, BSTR
*pbstrOut
)
6364 WCHAR szBuff
[64], *szOut
= szBuff
+ sizeof(szBuff
)/sizeof(WCHAR
) - 1;
6367 return E_INVALIDARG
;
6369 /* Create the basic number string */
6371 szOut
= VARIANT_WriteNumber(ulVal
, szOut
);
6373 *pbstrOut
= VARIANT_MakeBstr(lcid
, dwFlags
, szOut
);
6374 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6375 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6378 /******************************************************************************
6379 * VarBstrFromUI1 (OLEAUT32.108)
6381 * Convert a VT_UI1 to a VT_BSTR.
6385 * lcid [I] LCID for the conversion
6386 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6387 * pbstrOut [O] Destination
6391 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6392 * E_OUTOFMEMORY, if memory allocation fails.
6394 HRESULT WINAPI
VarBstrFromUI1(BYTE bIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6396 return VARIANT_BstrFromUInt(bIn
, lcid
, dwFlags
, pbstrOut
);
6399 /******************************************************************************
6400 * VarBstrFromI2 (OLEAUT32.109)
6402 * Convert a VT_I2 to a VT_BSTR.
6406 * lcid [I] LCID for the conversion
6407 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6408 * pbstrOut [O] Destination
6412 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6413 * E_OUTOFMEMORY, if memory allocation fails.
6415 HRESULT WINAPI
VarBstrFromI2(short sIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6422 dwFlags
|= VAR_NEGATIVE
;
6424 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6427 /******************************************************************************
6428 * VarBstrFromI4 (OLEAUT32.110)
6430 * Convert a VT_I4 to a VT_BSTR.
6434 * lcid [I] LCID for the conversion
6435 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6436 * pbstrOut [O] Destination
6440 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6441 * E_OUTOFMEMORY, if memory allocation fails.
6443 HRESULT WINAPI
VarBstrFromI4(LONG lIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6450 dwFlags
|= VAR_NEGATIVE
;
6452 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6455 static BSTR
VARIANT_BstrReplaceDecimal(const WCHAR
* buff
, LCID lcid
, ULONG dwFlags
)
6458 WCHAR lpDecimalSep
[16];
6460 /* Native oleaut32 uses the locale-specific decimal separator even in the
6461 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6462 American locales will see "one thousand and one tenth" as "1000,1"
6463 instead of "1000.1" (notice the comma). The following code checks for
6464 the need to replace the decimal separator, and if so, will prepare an
6465 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6467 GetLocaleInfoW(lcid
, LOCALE_SDECIMAL
| (dwFlags
& LOCALE_NOUSEROVERRIDE
),
6468 lpDecimalSep
, sizeof(lpDecimalSep
) / sizeof(WCHAR
));
6469 if (lpDecimalSep
[0] == '.' && lpDecimalSep
[1] == '\0')
6471 /* locale is compatible with English - return original string */
6472 bstrOut
= SysAllocString(buff
);
6478 WCHAR empty
[] = {'\0'};
6479 NUMBERFMTW minFormat
;
6481 minFormat
.NumDigits
= 0;
6482 minFormat
.LeadingZero
= 0;
6483 minFormat
.Grouping
= 0;
6484 minFormat
.lpDecimalSep
= lpDecimalSep
;
6485 minFormat
.lpThousandSep
= empty
;
6486 minFormat
.NegativeOrder
= 1; /* NLS_NEG_LEFT */
6488 /* count number of decimal digits in string */
6489 p
= strchrW( buff
, '.' );
6490 if (p
) minFormat
.NumDigits
= strlenW(p
+ 1);
6493 if (!GetNumberFormatW(lcid
, 0, buff
, &minFormat
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
)))
6495 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6496 bstrOut
= SysAllocString(buff
);
6500 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff
));
6501 bstrOut
= SysAllocString(numbuff
);
6507 static HRESULT
VARIANT_BstrFromReal(DOUBLE dblIn
, LCID lcid
, ULONG dwFlags
,
6508 BSTR
* pbstrOut
, LPCWSTR lpszFormat
)
6513 return E_INVALIDARG
;
6515 sprintfW( buff
, lpszFormat
, dblIn
);
6517 /* Negative zeroes are disallowed (some applications depend on this).
6518 If buff starts with a minus, and then nothing follows but zeroes
6519 and/or a period, it is a negative zero and is replaced with a
6520 canonical zero. This duplicates native oleaut32 behavior.
6524 const WCHAR szAccept
[] = {'0', '.', '\0'};
6525 if (strlenW(buff
+ 1) == strspnW(buff
+ 1, szAccept
))
6526 { buff
[0] = '0'; buff
[1] = '\0'; }
6529 TRACE("created string %s\n", debugstr_w(buff
));
6530 if (dwFlags
& LOCALE_USE_NLS
)
6534 /* Format the number for the locale */
6536 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6537 buff
, NULL
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
));
6538 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
6539 *pbstrOut
= SysAllocString(numbuff
);
6543 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
6545 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6548 /******************************************************************************
6549 * VarBstrFromR4 (OLEAUT32.111)
6551 * Convert a VT_R4 to a VT_BSTR.
6555 * lcid [I] LCID for the conversion
6556 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6557 * pbstrOut [O] Destination
6561 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6562 * E_OUTOFMEMORY, if memory allocation fails.
6564 HRESULT WINAPI
VarBstrFromR4(FLOAT fltIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6566 return VARIANT_BstrFromReal(fltIn
, lcid
, dwFlags
, pbstrOut
, szFloatFormatW
);
6569 /******************************************************************************
6570 * VarBstrFromR8 (OLEAUT32.112)
6572 * Convert a VT_R8 to a VT_BSTR.
6576 * lcid [I] LCID for the conversion
6577 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6578 * pbstrOut [O] Destination
6582 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6583 * E_OUTOFMEMORY, if memory allocation fails.
6585 HRESULT WINAPI
VarBstrFromR8(double dblIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6587 return VARIANT_BstrFromReal(dblIn
, lcid
, dwFlags
, pbstrOut
, szDoubleFormatW
);
6590 /******************************************************************************
6591 * VarBstrFromCy [OLEAUT32.113]
6593 * Convert a VT_CY to a VT_BSTR.
6597 * lcid [I] LCID for the conversion
6598 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6599 * pbstrOut [O] Destination
6603 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6604 * E_OUTOFMEMORY, if memory allocation fails.
6606 HRESULT WINAPI
VarBstrFromCy(CY cyIn
, LCID lcid
, ULONG dwFlags
, BSTR
*pbstrOut
)
6612 return E_INVALIDARG
;
6616 decVal
.bitsnum
[0] = cyIn
.s
.Lo
;
6617 decVal
.bitsnum
[1] = cyIn
.s
.Hi
;
6618 if (cyIn
.s
.Hi
& 0x80000000UL
) {
6621 /* Negative number! */
6623 decVal
.bitsnum
[0] = ~decVal
.bitsnum
[0];
6624 decVal
.bitsnum
[1] = ~decVal
.bitsnum
[1];
6625 VARIANT_int_add(decVal
.bitsnum
, 3, &one
, 1);
6627 decVal
.bitsnum
[2] = 0;
6628 VARIANT_DI_tostringW(&decVal
, buff
, sizeof(buff
)/sizeof(buff
[0]));
6630 if (dwFlags
& LOCALE_USE_NLS
)
6634 /* Format the currency for the locale */
6636 GetCurrencyFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6637 buff
, NULL
, cybuff
, sizeof(cybuff
) / sizeof(WCHAR
));
6638 *pbstrOut
= SysAllocString(cybuff
);
6641 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
,lcid
,dwFlags
);
6643 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6646 static inline int output_int_len(int o
, int min_len
, WCHAR
*date
, int date_len
)
6650 if(min_len
>= date_len
)
6653 for(len
=0, tmp
=o
; tmp
; tmp
/=10) len
++;
6658 for(tmp
=min_len
-len
; tmp
>0; tmp
--)
6660 for(tmp
=len
; tmp
>0; tmp
--, o
/=10)
6661 date
[tmp
-1] = '0' + o
%10;
6662 return min_len
>len
? min_len
: len
;
6665 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6666 BOOL
get_date_format(LCID lcid
, DWORD flags
, const SYSTEMTIME
*st
,
6667 const WCHAR
*fmt
, WCHAR
*date
, int date_len
)
6669 static const LCTYPE dayname
[] = {
6670 LOCALE_SDAYNAME7
, LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
,
6671 LOCALE_SDAYNAME4
, LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
6673 static const LCTYPE sdayname
[] = {
6674 LOCALE_SABBREVDAYNAME7
, LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
,
6675 LOCALE_SABBREVDAYNAME3
, LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
,
6676 LOCALE_SABBREVDAYNAME6
6678 static const LCTYPE monthname
[] = {
6679 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
6680 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
6681 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
6683 static const LCTYPE smonthname
[] = {
6684 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
6685 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
6686 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
6687 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
6690 if(flags
& ~(LOCALE_NOUSEROVERRIDE
|VAR_DATEVALUEONLY
))
6691 FIXME("ignoring flags %x\n", flags
);
6692 flags
&= LOCALE_NOUSEROVERRIDE
;
6694 while(*fmt
&& date_len
) {
6702 while(*fmt
== *(fmt
+count
))
6710 count
= GetLocaleInfoW(lcid
, dayname
[st
->wDayOfWeek
] | flags
, date
, date_len
)-1;
6712 count
= GetLocaleInfoW(lcid
, sdayname
[st
->wDayOfWeek
] | flags
, date
, date_len
)-1;
6714 count
= output_int_len(st
->wDay
, count
, date
, date_len
);
6718 count
= GetLocaleInfoW(lcid
, monthname
[st
->wMonth
-1] | flags
, date
, date_len
)-1;
6720 count
= GetLocaleInfoW(lcid
, smonthname
[st
->wMonth
-1] | flags
, date
, date_len
)-1;
6722 count
= output_int_len(st
->wMonth
, count
, date
, date_len
);
6726 count
= output_int_len(st
->wYear
, 0, date
, date_len
);
6728 count
= output_int_len(st
->wYear
%100, count
, date
, date_len
);
6732 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6760 /******************************************************************************
6761 * VarBstrFromDate [OLEAUT32.114]
6763 * Convert a VT_DATE to a VT_BSTR.
6767 * lcid [I] LCID for the conversion
6768 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6769 * pbstrOut [O] Destination
6773 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6774 * E_OUTOFMEMORY, if memory allocation fails.
6776 HRESULT WINAPI
VarBstrFromDate(DATE dateIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6779 DWORD dwFormatFlags
= dwFlags
& LOCALE_NOUSEROVERRIDE
;
6780 WCHAR date
[128], fmt_buff
[80], *time
;
6782 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn
, lcid
, dwFlags
, pbstrOut
);
6784 if (!pbstrOut
|| !VariantTimeToSystemTime(dateIn
, &st
))
6785 return E_INVALIDARG
;
6789 if (dwFlags
& VAR_CALENDAR_THAI
)
6790 st
.wYear
+= 553; /* Use the Thai buddhist calendar year */
6791 else if (dwFlags
& (VAR_CALENDAR_HIJRI
|VAR_CALENDAR_GREGORIAN
))
6792 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6794 if (dwFlags
& LOCALE_USE_NLS
)
6795 dwFlags
&= ~(VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
);
6798 double whole
= dateIn
< 0 ? ceil(dateIn
) : floor(dateIn
);
6799 double partial
= dateIn
- whole
;
6802 dwFlags
|= VAR_TIMEVALUEONLY
;
6803 else if (partial
> -1e-12 && partial
< 1e-12)
6804 dwFlags
|= VAR_DATEVALUEONLY
;
6807 if (dwFlags
& VAR_TIMEVALUEONLY
)
6810 if (!GetLocaleInfoW(lcid
, LOCALE_SSHORTDATE
, fmt_buff
, sizeof(fmt_buff
)/sizeof(WCHAR
)) ||
6811 !get_date_format(lcid
, dwFlags
, &st
, fmt_buff
, date
, sizeof(date
)/sizeof(WCHAR
)))
6812 return E_INVALIDARG
;
6814 if (!(dwFlags
& VAR_DATEVALUEONLY
))
6816 time
= date
+ strlenW(date
);
6819 if (!GetTimeFormatW(lcid
, dwFormatFlags
, &st
, NULL
, time
,
6820 sizeof(date
)/sizeof(WCHAR
)-(time
-date
)))
6821 return E_INVALIDARG
;
6824 *pbstrOut
= SysAllocString(date
);
6826 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6827 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6830 /******************************************************************************
6831 * VarBstrFromBool (OLEAUT32.116)
6833 * Convert a VT_BOOL to a VT_BSTR.
6837 * lcid [I] LCID for the conversion
6838 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6839 * pbstrOut [O] Destination
6843 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6844 * E_OUTOFMEMORY, if memory allocation fails.
6847 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6848 * localised text of "True" or "False". To convert a bool into a
6849 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6851 HRESULT WINAPI
VarBstrFromBool(VARIANT_BOOL boolIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6854 DWORD dwResId
= IDS_TRUE
;
6857 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn
, lcid
, dwFlags
, pbstrOut
);
6860 return E_INVALIDARG
;
6862 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6863 * for variant formatting */
6864 switch (dwFlags
& (VAR_LOCALBOOL
|VAR_BOOLONOFF
|VAR_BOOLYESNO
))
6875 lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
),SORT_DEFAULT
);
6878 lcid
= ConvertDefaultLocale(lcid
);
6879 langId
= LANGIDFROMLCID(lcid
);
6880 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6881 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6883 if (boolIn
== VARIANT_FALSE
)
6884 dwResId
++; /* Use negative form */
6886 VarBstrFromBool_GetLocalised
:
6887 if (VARIANT_GetLocalisedText(langId
, dwResId
, szBuff
))
6889 *pbstrOut
= SysAllocString(szBuff
);
6890 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6893 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6895 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6896 goto VarBstrFromBool_GetLocalised
;
6899 /* Should never get here */
6900 WARN("Failed to load bool text!\n");
6901 return E_OUTOFMEMORY
;
6904 /******************************************************************************
6905 * VarBstrFromI1 (OLEAUT32.229)
6907 * Convert a VT_I1 to a VT_BSTR.
6911 * lcid [I] LCID for the conversion
6912 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6913 * pbstrOut [O] Destination
6917 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6918 * E_OUTOFMEMORY, if memory allocation fails.
6920 HRESULT WINAPI
VarBstrFromI1(signed char cIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6927 dwFlags
|= VAR_NEGATIVE
;
6929 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6932 /******************************************************************************
6933 * VarBstrFromUI2 (OLEAUT32.230)
6935 * Convert a VT_UI2 to a VT_BSTR.
6939 * lcid [I] LCID for the conversion
6940 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6941 * pbstrOut [O] Destination
6945 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6946 * E_OUTOFMEMORY, if memory allocation fails.
6948 HRESULT WINAPI
VarBstrFromUI2(USHORT usIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6950 return VARIANT_BstrFromUInt(usIn
, lcid
, dwFlags
, pbstrOut
);
6953 /******************************************************************************
6954 * VarBstrFromUI4 (OLEAUT32.231)
6956 * Convert a VT_UI4 to a VT_BSTR.
6960 * lcid [I] LCID for the conversion
6961 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6962 * pbstrOut [O] Destination
6966 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6967 * E_OUTOFMEMORY, if memory allocation fails.
6969 HRESULT WINAPI
VarBstrFromUI4(ULONG ulIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6971 return VARIANT_BstrFromUInt(ulIn
, lcid
, dwFlags
, pbstrOut
);
6974 /******************************************************************************
6975 * VarBstrFromDec (OLEAUT32.232)
6977 * Convert a VT_DECIMAL to a VT_BSTR.
6981 * lcid [I] LCID for the conversion
6982 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6983 * pbstrOut [O] Destination
6987 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6988 * E_OUTOFMEMORY, if memory allocation fails.
6990 HRESULT WINAPI
VarBstrFromDec(DECIMAL
* pDecIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6996 return E_INVALIDARG
;
6998 VARIANT_DIFromDec(pDecIn
, &temp
);
6999 VARIANT_DI_tostringW(&temp
, buff
, 256);
7001 if (dwFlags
& LOCALE_USE_NLS
)
7005 /* Format the number for the locale */
7007 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
7008 buff
, NULL
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
));
7009 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
7010 *pbstrOut
= SysAllocString(numbuff
);
7014 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
7017 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
7018 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
7021 /************************************************************************
7022 * VarBstrFromI8 (OLEAUT32.370)
7024 * Convert a VT_I8 to a VT_BSTR.
7028 * lcid [I] LCID for the conversion
7029 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7030 * pbstrOut [O] Destination
7034 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7035 * E_OUTOFMEMORY, if memory allocation fails.
7037 HRESULT WINAPI
VarBstrFromI8(LONG64 llIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7039 ULONG64 ul64
= llIn
;
7044 dwFlags
|= VAR_NEGATIVE
;
7046 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
7049 /************************************************************************
7050 * VarBstrFromUI8 (OLEAUT32.371)
7052 * Convert a VT_UI8 to a VT_BSTR.
7056 * lcid [I] LCID for the conversion
7057 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7058 * pbstrOut [O] Destination
7062 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7063 * E_OUTOFMEMORY, if memory allocation fails.
7065 HRESULT WINAPI
VarBstrFromUI8(ULONG64 ullIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7067 return VARIANT_BstrFromUInt(ullIn
, lcid
, dwFlags
, pbstrOut
);
7070 /************************************************************************
7071 * VarBstrFromDisp (OLEAUT32.115)
7073 * Convert a VT_DISPATCH to a BSTR.
7076 * pdispIn [I] Source
7077 * lcid [I] LCID for conversion
7078 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7079 * pbstrOut [O] Destination
7083 * Failure: E_INVALIDARG, if the source value is invalid
7084 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7086 HRESULT WINAPI
VarBstrFromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7088 return VARIANT_FromDisp(pdispIn
, lcid
, pbstrOut
, VT_BSTR
, dwFlags
);
7091 /**********************************************************************
7092 * VarBstrCat (OLEAUT32.313)
7094 * Concatenate two BSTR values.
7097 * pbstrLeft [I] Source
7098 * pbstrRight [I] Value to concatenate
7099 * pbstrOut [O] Destination
7103 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7104 * E_OUTOFMEMORY, if memory allocation fails.
7106 HRESULT WINAPI
VarBstrCat(BSTR pbstrLeft
, BSTR pbstrRight
, BSTR
*pbstrOut
)
7108 unsigned int lenLeft
, lenRight
;
7111 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
7112 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), pbstrOut
);
7115 return E_INVALIDARG
;
7117 /* use byte length here to properly handle ansi-allocated BSTRs */
7118 lenLeft
= pbstrLeft
? SysStringByteLen(pbstrLeft
) : 0;
7119 lenRight
= pbstrRight
? SysStringByteLen(pbstrRight
) : 0;
7121 *pbstrOut
= SysAllocStringByteLen(NULL
, lenLeft
+ lenRight
);
7123 return E_OUTOFMEMORY
;
7125 (*pbstrOut
)[0] = '\0';
7128 memcpy(*pbstrOut
, pbstrLeft
, lenLeft
);
7131 memcpy((CHAR
*)*pbstrOut
+ lenLeft
, pbstrRight
, lenRight
);
7133 TRACE("%s\n", debugstr_wn(*pbstrOut
, SysStringLen(*pbstrOut
)));
7137 /**********************************************************************
7138 * VarBstrCmp (OLEAUT32.314)
7140 * Compare two BSTR values.
7143 * pbstrLeft [I] Source
7144 * pbstrRight [I] Value to compare
7145 * lcid [I] LCID for the comparison
7146 * dwFlags [I] Flags to pass directly to CompareStringW().
7149 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7150 * than, equal to or greater than pbstrRight respectively.
7153 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7154 * states. A NULL BSTR pointer is equivalent to an empty string.
7155 * If LCID is equal to 0, a byte by byte comparison is performed.
7157 HRESULT WINAPI
VarBstrCmp(BSTR pbstrLeft
, BSTR pbstrRight
, LCID lcid
, DWORD dwFlags
)
7162 TRACE("%s,%s,%d,%08x\n",
7163 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
7164 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), lcid
, dwFlags
);
7166 if (!pbstrLeft
|| !*pbstrLeft
)
7168 if (pbstrRight
&& *pbstrRight
)
7171 else if (!pbstrRight
|| !*pbstrRight
)
7176 unsigned int lenLeft
= SysStringByteLen(pbstrLeft
);
7177 unsigned int lenRight
= SysStringByteLen(pbstrRight
);
7178 ret
= memcmp(pbstrLeft
, pbstrRight
, min(lenLeft
, lenRight
));
7183 if (lenLeft
< lenRight
)
7185 if (lenLeft
> lenRight
)
7191 unsigned int lenLeft
= SysStringLen(pbstrLeft
);
7192 unsigned int lenRight
= SysStringLen(pbstrRight
);
7194 if (lenLeft
== 0 || lenRight
== 0)
7196 if (lenLeft
== 0 && lenRight
== 0) return VARCMP_EQ
;
7197 return lenLeft
< lenRight
? VARCMP_LT
: VARCMP_GT
;
7200 hres
= CompareStringW(lcid
, dwFlags
, pbstrLeft
, lenLeft
,
7201 pbstrRight
, lenRight
) - CSTR_LESS_THAN
;
7202 TRACE("%d\n", hres
);
7211 /******************************************************************************
7212 * VarDateFromUI1 (OLEAUT32.88)
7214 * Convert a VT_UI1 to a VT_DATE.
7218 * pdateOut [O] Destination
7223 HRESULT WINAPI
VarDateFromUI1(BYTE bIn
, DATE
* pdateOut
)
7225 return VarR8FromUI1(bIn
, pdateOut
);
7228 /******************************************************************************
7229 * VarDateFromI2 (OLEAUT32.89)
7231 * Convert a VT_I2 to a VT_DATE.
7235 * pdateOut [O] Destination
7240 HRESULT WINAPI
VarDateFromI2(short sIn
, DATE
* pdateOut
)
7242 return VarR8FromI2(sIn
, pdateOut
);
7245 /******************************************************************************
7246 * VarDateFromI4 (OLEAUT32.90)
7248 * Convert a VT_I4 to a VT_DATE.
7252 * pdateOut [O] Destination
7257 HRESULT WINAPI
VarDateFromI4(LONG lIn
, DATE
* pdateOut
)
7259 return VarDateFromR8(lIn
, pdateOut
);
7262 /******************************************************************************
7263 * VarDateFromR4 (OLEAUT32.91)
7265 * Convert a VT_R4 to a VT_DATE.
7269 * pdateOut [O] Destination
7274 HRESULT WINAPI
VarDateFromR4(FLOAT fltIn
, DATE
* pdateOut
)
7276 return VarR8FromR4(fltIn
, pdateOut
);
7279 /******************************************************************************
7280 * VarDateFromR8 (OLEAUT32.92)
7282 * Convert a VT_R8 to a VT_DATE.
7286 * pdateOut [O] Destination
7291 HRESULT WINAPI
VarDateFromR8(double dblIn
, DATE
* pdateOut
)
7293 if (dblIn
<= (DATE_MIN
- 1.0) || dblIn
>= (DATE_MAX
+ 1.0)) return DISP_E_OVERFLOW
;
7294 *pdateOut
= (DATE
)dblIn
;
7298 /**********************************************************************
7299 * VarDateFromDisp (OLEAUT32.95)
7301 * Convert a VT_DISPATCH to a VT_DATE.
7304 * pdispIn [I] Source
7305 * lcid [I] LCID for conversion
7306 * pdateOut [O] Destination
7310 * Failure: E_INVALIDARG, if the source value is invalid
7311 * DISP_E_OVERFLOW, if the value will not fit in the destination
7312 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7314 HRESULT WINAPI
VarDateFromDisp(IDispatch
* pdispIn
, LCID lcid
, DATE
* pdateOut
)
7316 return VARIANT_FromDisp(pdispIn
, lcid
, pdateOut
, VT_DATE
, 0);
7319 /******************************************************************************
7320 * VarDateFromBool (OLEAUT32.96)
7322 * Convert a VT_BOOL to a VT_DATE.
7326 * pdateOut [O] Destination
7331 HRESULT WINAPI
VarDateFromBool(VARIANT_BOOL boolIn
, DATE
* pdateOut
)
7333 return VarR8FromBool(boolIn
, pdateOut
);
7336 /**********************************************************************
7337 * VarDateFromCy (OLEAUT32.93)
7339 * Convert a VT_CY to a VT_DATE.
7343 * pdateOut [O] Destination
7348 HRESULT WINAPI
VarDateFromCy(CY cyIn
, DATE
* pdateOut
)
7350 return VarR8FromCy(cyIn
, pdateOut
);
7353 /* Date string parsing */
7354 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7355 #define DP_DATESEP 0x02 /* Date separator */
7356 #define DP_MONTH 0x04 /* Month name */
7357 #define DP_AM 0x08 /* AM */
7358 #define DP_PM 0x10 /* PM */
7360 typedef struct tagDATEPARSE
7362 DWORD dwCount
; /* Number of fields found so far (maximum 6) */
7363 DWORD dwParseFlags
; /* Global parse flags (DP_ Flags above) */
7364 DWORD dwFlags
[6]; /* Flags for each field */
7365 DWORD dwValues
[6]; /* Value of each field */
7368 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7370 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7372 /* Determine if a day is valid in a given month of a given year */
7373 static BOOL
VARIANT_IsValidMonthDay(DWORD day
, DWORD month
, DWORD year
)
7375 static const BYTE days
[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7377 if (day
&& month
&& month
< 13)
7379 if (day
<= days
[month
] || (month
== 2 && day
== 29 && IsLeapYear(year
)))
7385 /* Possible orders for 3 numbers making up a date */
7386 #define ORDER_MDY 0x01
7387 #define ORDER_YMD 0x02
7388 #define ORDER_YDM 0x04
7389 #define ORDER_DMY 0x08
7390 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7392 /* Determine a date for a particular locale, from 3 numbers */
7393 static inline HRESULT
VARIANT_MakeDate(DATEPARSE
*dp
, DWORD iDate
,
7394 DWORD offset
, SYSTEMTIME
*st
)
7396 DWORD dwAllOrders
, dwTry
, dwCount
= 0, v1
, v2
, v3
;
7400 v1
= 30; /* Default to (Variant) 0 date part */
7403 goto VARIANT_MakeDate_OK
;
7406 v1
= dp
->dwValues
[offset
+ 0];
7407 v2
= dp
->dwValues
[offset
+ 1];
7408 if (dp
->dwCount
== 2)
7411 GetSystemTime(¤t
);
7415 v3
= dp
->dwValues
[offset
+ 2];
7417 TRACE("(%d,%d,%d,%d,%d)\n", v1
, v2
, v3
, iDate
, offset
);
7419 /* If one number must be a month (Because a month name was given), then only
7420 * consider orders with the month in that position.
7421 * If we took the current year as 'v3', then only allow a year in that position.
7423 if (dp
->dwFlags
[offset
+ 0] & DP_MONTH
)
7425 dwAllOrders
= ORDER_MDY
;
7427 else if (dp
->dwFlags
[offset
+ 1] & DP_MONTH
)
7429 dwAllOrders
= ORDER_DMY
;
7430 if (dp
->dwCount
> 2)
7431 dwAllOrders
|= ORDER_YMD
;
7433 else if (dp
->dwCount
> 2 && dp
->dwFlags
[offset
+ 2] & DP_MONTH
)
7435 dwAllOrders
= ORDER_YDM
;
7439 dwAllOrders
= ORDER_MDY
|ORDER_DMY
;
7440 if (dp
->dwCount
> 2)
7441 dwAllOrders
|= (ORDER_YMD
|ORDER_YDM
);
7444 VARIANT_MakeDate_Start
:
7445 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders
);
7453 /* First: Try the order given by iDate */
7456 case 0: dwTry
= dwAllOrders
& ORDER_MDY
; break;
7457 case 1: dwTry
= dwAllOrders
& ORDER_DMY
; break;
7458 default: dwTry
= dwAllOrders
& ORDER_YMD
; break;
7461 else if (dwCount
== 1)
7463 /* Second: Try all the orders compatible with iDate */
7466 case 0: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7467 case 1: dwTry
= dwAllOrders
& ~(ORDER_MDY
|ORDER_YDM
|ORDER_MYD
); break;
7468 default: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7473 /* Finally: Try any remaining orders */
7474 dwTry
= dwAllOrders
;
7477 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount
, dwTry
);
7483 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7485 if (dwTry
& ORDER_MDY
)
7487 if (VARIANT_IsValidMonthDay(v2
,v1
,v3
))
7490 goto VARIANT_MakeDate_OK
;
7492 dwAllOrders
&= ~ORDER_MDY
;
7494 if (dwTry
& ORDER_YMD
)
7496 if (VARIANT_IsValidMonthDay(v3
,v2
,v1
))
7499 goto VARIANT_MakeDate_OK
;
7501 dwAllOrders
&= ~ORDER_YMD
;
7503 if (dwTry
& ORDER_YDM
)
7505 if (VARIANT_IsValidMonthDay(v2
,v3
,v1
))
7509 goto VARIANT_MakeDate_OK
;
7511 dwAllOrders
&= ~ORDER_YDM
;
7513 if (dwTry
& ORDER_DMY
)
7515 if (VARIANT_IsValidMonthDay(v1
,v2
,v3
))
7516 goto VARIANT_MakeDate_OK
;
7517 dwAllOrders
&= ~ORDER_DMY
;
7519 if (dwTry
& ORDER_MYD
)
7521 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7522 if (VARIANT_IsValidMonthDay(v3
,v1
,v2
))
7526 goto VARIANT_MakeDate_OK
;
7528 dwAllOrders
&= ~ORDER_MYD
;
7532 if (dp
->dwCount
== 2)
7534 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7535 v3
= 1; /* 1st of the month */
7536 dwAllOrders
= ORDER_YMD
|ORDER_MYD
;
7537 dp
->dwCount
= 0; /* Don't return to this code path again */
7539 goto VARIANT_MakeDate_Start
;
7542 /* No valid dates were able to be constructed */
7543 return DISP_E_TYPEMISMATCH
;
7545 VARIANT_MakeDate_OK
:
7547 /* Check that the time part is ok */
7548 if (st
->wHour
> 23 || st
->wMinute
> 59 || st
->wSecond
> 59)
7549 return DISP_E_TYPEMISMATCH
;
7551 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7552 if (st
->wHour
< 12 && (dp
->dwParseFlags
& DP_PM
))
7554 else if (st
->wHour
== 12 && (dp
->dwParseFlags
& DP_AM
))
7556 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7560 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7561 * be retrieved from:
7562 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7563 * But Wine doesn't have/use that key as at the time of writing.
7565 st
->wYear
= v3
< 30 ? 2000 + v3
: v3
< 100 ? 1900 + v3
: v3
;
7566 TRACE("Returning date %d/%d/%d\n", v1
, v2
, st
->wYear
);
7570 /******************************************************************************
7571 * VarDateFromStr [OLEAUT32.94]
7573 * Convert a VT_BSTR to at VT_DATE.
7576 * strIn [I] String to convert
7577 * lcid [I] Locale identifier for the conversion
7578 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7579 * pdateOut [O] Destination for the converted value
7582 * Success: S_OK. pdateOut contains the converted value.
7583 * FAILURE: An HRESULT error code indicating the problem.
7586 * Any date format that can be created using the date formats from lcid
7587 * (Either from kernel Nls functions, variant conversion or formatting) is a
7588 * valid input to this function. In addition, a few more esoteric formats are
7589 * also supported for compatibility with the native version. The date is
7590 * interpreted according to the date settings in the control panel, unless
7591 * the date is invalid in that format, in which the most compatible format
7592 * that produces a valid date will be used.
7594 HRESULT WINAPI
VarDateFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DATE
* pdateOut
)
7596 static const USHORT ParseDateTokens
[] =
7598 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
7599 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
7600 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
,
7601 LOCALE_SMONTHNAME13
,
7602 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
7603 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
7604 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
7605 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
,
7606 LOCALE_SABBREVMONTHNAME13
,
7607 LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
, LOCALE_SDAYNAME4
,
7608 LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
, LOCALE_SDAYNAME7
,
7609 LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
, LOCALE_SABBREVDAYNAME3
,
7610 LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
, LOCALE_SABBREVDAYNAME6
,
7611 LOCALE_SABBREVDAYNAME7
,
7612 LOCALE_S1159
, LOCALE_S2359
,
7615 static const BYTE ParseDateMonths
[] =
7617 1,2,3,4,5,6,7,8,9,10,11,12,13,
7618 1,2,3,4,5,6,7,8,9,10,11,12,13
7621 BSTR tokens
[sizeof(ParseDateTokens
)/sizeof(ParseDateTokens
[0])];
7623 DWORD dwDateSeps
= 0, iDate
= 0;
7624 HRESULT hRet
= S_OK
;
7626 if ((dwFlags
& (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
)) ==
7627 (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
))
7628 return E_INVALIDARG
;
7631 return DISP_E_TYPEMISMATCH
;
7635 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn
), lcid
, dwFlags
, pdateOut
);
7637 memset(&dp
, 0, sizeof(dp
));
7639 GetLocaleInfoW(lcid
, LOCALE_IDATE
|LOCALE_RETURN_NUMBER
|(dwFlags
& LOCALE_NOUSEROVERRIDE
),
7640 (LPWSTR
)&iDate
, sizeof(iDate
)/sizeof(WCHAR
));
7641 TRACE("iDate is %d\n", iDate
);
7643 /* Get the month/day/am/pm tokens for this locale */
7644 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7647 LCTYPE lctype
= ParseDateTokens
[i
] | (dwFlags
& LOCALE_NOUSEROVERRIDE
);
7649 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7650 * GetAltMonthNames(). We should really cache these strings too.
7653 GetLocaleInfoW(lcid
, lctype
, buff
, sizeof(buff
)/sizeof(WCHAR
));
7654 tokens
[i
] = SysAllocString(buff
);
7655 TRACE("token %d is %s\n", i
, debugstr_w(tokens
[i
]));
7658 /* Parse the string into our structure */
7661 if (dp
.dwCount
>= 6)
7664 if (isdigitW(*strIn
))
7666 dp
.dwValues
[dp
.dwCount
] = strtoulW(strIn
, &strIn
, 10);
7670 else if (isalpha(*strIn
))
7672 BOOL bFound
= FALSE
;
7674 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7676 DWORD dwLen
= strlenW(tokens
[i
]);
7677 if (dwLen
&& !strncmpiW(strIn
, tokens
[i
], dwLen
))
7681 dp
.dwValues
[dp
.dwCount
] = ParseDateMonths
[i
];
7682 dp
.dwFlags
[dp
.dwCount
] |= (DP_MONTH
|DP_DATESEP
);
7685 else if (i
> 39 && i
< 42)
7687 if (!dp
.dwCount
|| dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7688 hRet
= DISP_E_TYPEMISMATCH
;
7691 dp
.dwFlags
[dp
.dwCount
- 1] |= (i
== 40 ? DP_AM
: DP_PM
);
7692 dp
.dwParseFlags
|= (i
== 40 ? DP_AM
: DP_PM
);
7695 strIn
+= (dwLen
- 1);
7703 if ((*strIn
== 'a' || *strIn
== 'A' || *strIn
== 'p' || *strIn
== 'P') &&
7704 (dp
.dwCount
&& !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7706 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7707 if (*strIn
== 'a' || *strIn
== 'A')
7709 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_AM
;
7710 dp
.dwParseFlags
|= DP_AM
;
7714 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_PM
;
7715 dp
.dwParseFlags
|= DP_PM
;
7721 TRACE("No matching token for %s\n", debugstr_w(strIn
));
7722 hRet
= DISP_E_TYPEMISMATCH
;
7727 else if (*strIn
== ':' || *strIn
== '.')
7729 if (!dp
.dwCount
|| !strIn
[1])
7730 hRet
= DISP_E_TYPEMISMATCH
;
7732 if (tokens
[42][0] == *strIn
)
7736 hRet
= DISP_E_TYPEMISMATCH
;
7738 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7741 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_TIMESEP
;
7743 else if (*strIn
== '-' || *strIn
== '/')
7746 if (dwDateSeps
> 2 || !dp
.dwCount
|| !strIn
[1])
7747 hRet
= DISP_E_TYPEMISMATCH
;
7749 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7751 else if (*strIn
== ',' || isspaceW(*strIn
))
7753 if (*strIn
== ',' && !strIn
[1])
7754 hRet
= DISP_E_TYPEMISMATCH
;
7758 hRet
= DISP_E_TYPEMISMATCH
;
7763 if (!dp
.dwCount
|| dp
.dwCount
> 6 ||
7764 (dp
.dwCount
== 1 && !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7765 hRet
= DISP_E_TYPEMISMATCH
;
7767 if (SUCCEEDED(hRet
))
7770 DWORD dwOffset
= 0; /* Start of date fields in dp.dwValues */
7772 st
.wDayOfWeek
= st
.wHour
= st
.wMinute
= st
.wSecond
= st
.wMilliseconds
= 0;
7774 /* Figure out which numbers correspond to which fields.
7776 * This switch statement works based on the fact that native interprets any
7777 * fields that are not joined with a time separator ('.' or ':') as date
7778 * fields. Thus we construct a value from 0-32 where each set bit indicates
7779 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7780 * For valid permutations, we set dwOffset to point to the first date field
7781 * and shorten dp.dwCount by the number of time fields found. The real
7782 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7783 * each date number must represent in the context of iDate.
7785 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7787 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7789 case 0x1: /* TT TTDD TTDDD */
7790 if (dp
.dwCount
> 3 &&
7791 ((dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) ||
7792 (dp
.dwFlags
[4] & (DP_AM
|DP_PM
))))
7793 hRet
= DISP_E_TYPEMISMATCH
;
7794 else if (dp
.dwCount
!= 2 && dp
.dwCount
!= 4 && dp
.dwCount
!= 5)
7795 hRet
= DISP_E_TYPEMISMATCH
;
7796 st
.wHour
= dp
.dwValues
[0];
7797 st
.wMinute
= dp
.dwValues
[1];
7802 case 0x3: /* TTT TTTDD TTTDDD */
7803 if (dp
.dwCount
> 4 &&
7804 ((dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[4] & (DP_AM
|DP_PM
)) ||
7805 (dp
.dwFlags
[5] & (DP_AM
|DP_PM
))))
7806 hRet
= DISP_E_TYPEMISMATCH
;
7807 else if (dp
.dwCount
!= 3 && dp
.dwCount
!= 5 && dp
.dwCount
!= 6)
7808 hRet
= DISP_E_TYPEMISMATCH
;
7809 st
.wHour
= dp
.dwValues
[0];
7810 st
.wMinute
= dp
.dwValues
[1];
7811 st
.wSecond
= dp
.dwValues
[2];
7816 case 0x4: /* DDTT */
7817 if (dp
.dwCount
!= 4 ||
7818 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7819 hRet
= DISP_E_TYPEMISMATCH
;
7821 st
.wHour
= dp
.dwValues
[2];
7822 st
.wMinute
= dp
.dwValues
[3];
7826 case 0x0: /* T DD DDD TDDD TDDD */
7827 if (dp
.dwCount
== 1 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7829 st
.wHour
= dp
.dwValues
[0]; /* T */
7833 else if (dp
.dwCount
> 4 || (dp
.dwCount
< 3 && dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7835 hRet
= DISP_E_TYPEMISMATCH
;
7837 else if (dp
.dwCount
== 3)
7839 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDD */
7842 st
.wHour
= dp
.dwValues
[0];
7846 if (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) /* DDT */
7849 st
.wHour
= dp
.dwValues
[2];
7852 else if (dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7853 hRet
= DISP_E_TYPEMISMATCH
;
7855 else if (dp
.dwCount
== 4)
7858 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDDD */
7860 st
.wHour
= dp
.dwValues
[0];
7863 else if (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) /* DDDT */
7865 st
.wHour
= dp
.dwValues
[3];
7868 hRet
= DISP_E_TYPEMISMATCH
;
7871 /* .. fall through .. */
7873 case 0x8: /* DDDTT */
7874 if ((dp
.dwCount
== 2 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
))) ||
7875 (dp
.dwCount
== 5 && ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) ||
7876 (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))) ||
7877 dp
.dwCount
== 4 || dp
.dwCount
== 6)
7878 hRet
= DISP_E_TYPEMISMATCH
;
7879 st
.wHour
= dp
.dwValues
[3];
7880 st
.wMinute
= dp
.dwValues
[4];
7881 if (dp
.dwCount
== 5)
7885 case 0xC: /* DDTTT */
7886 if (dp
.dwCount
!= 5 ||
7887 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7888 hRet
= DISP_E_TYPEMISMATCH
;
7889 st
.wHour
= dp
.dwValues
[2];
7890 st
.wMinute
= dp
.dwValues
[3];
7891 st
.wSecond
= dp
.dwValues
[4];
7895 case 0x18: /* DDDTTT */
7896 if ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) ||
7897 (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))
7898 hRet
= DISP_E_TYPEMISMATCH
;
7899 st
.wHour
= dp
.dwValues
[3];
7900 st
.wMinute
= dp
.dwValues
[4];
7901 st
.wSecond
= dp
.dwValues
[5];
7906 hRet
= DISP_E_TYPEMISMATCH
;
7910 if (SUCCEEDED(hRet
))
7912 hRet
= VARIANT_MakeDate(&dp
, iDate
, dwOffset
, &st
);
7914 if (dwFlags
& VAR_TIMEVALUEONLY
)
7920 else if (dwFlags
& VAR_DATEVALUEONLY
)
7921 st
.wHour
= st
.wMinute
= st
.wSecond
= 0;
7923 /* Finally, convert the value to a VT_DATE */
7924 if (SUCCEEDED(hRet
))
7925 hRet
= SystemTimeToVariantTime(&st
, pdateOut
) ? S_OK
: DISP_E_TYPEMISMATCH
;
7929 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7930 SysFreeString(tokens
[i
]);
7934 /******************************************************************************
7935 * VarDateFromI1 (OLEAUT32.221)
7937 * Convert a VT_I1 to a VT_DATE.
7941 * pdateOut [O] Destination
7946 HRESULT WINAPI
VarDateFromI1(signed char cIn
, DATE
* pdateOut
)
7948 return VarR8FromI1(cIn
, pdateOut
);
7951 /******************************************************************************
7952 * VarDateFromUI2 (OLEAUT32.222)
7954 * Convert a VT_UI2 to a VT_DATE.
7958 * pdateOut [O] Destination
7963 HRESULT WINAPI
VarDateFromUI2(USHORT uiIn
, DATE
* pdateOut
)
7965 return VarR8FromUI2(uiIn
, pdateOut
);
7968 /******************************************************************************
7969 * VarDateFromUI4 (OLEAUT32.223)
7971 * Convert a VT_UI4 to a VT_DATE.
7975 * pdateOut [O] Destination
7980 HRESULT WINAPI
VarDateFromUI4(ULONG ulIn
, DATE
* pdateOut
)
7982 return VarDateFromR8(ulIn
, pdateOut
);
7985 /**********************************************************************
7986 * VarDateFromDec (OLEAUT32.224)
7988 * Convert a VT_DECIMAL to a VT_DATE.
7992 * pdateOut [O] Destination
7997 HRESULT WINAPI
VarDateFromDec(DECIMAL
*pdecIn
, DATE
* pdateOut
)
7999 return VarR8FromDec(pdecIn
, pdateOut
);
8002 /******************************************************************************
8003 * VarDateFromI8 (OLEAUT32.364)
8005 * Convert a VT_I8 to a VT_DATE.
8009 * pdateOut [O] Destination
8013 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8015 HRESULT WINAPI
VarDateFromI8(LONG64 llIn
, DATE
* pdateOut
)
8017 if (llIn
< DATE_MIN
|| llIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
8018 *pdateOut
= (DATE
)llIn
;
8022 /******************************************************************************
8023 * VarDateFromUI8 (OLEAUT32.365)
8025 * Convert a VT_UI8 to a VT_DATE.
8029 * pdateOut [O] Destination
8033 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8035 HRESULT WINAPI
VarDateFromUI8(ULONG64 ullIn
, DATE
* pdateOut
)
8037 if (ullIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
8038 *pdateOut
= (DATE
)ullIn
;