2 * Low level variant functions
4 * Copyright 2003 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
25 #include "wine/debug.h"
26 #include "wine/unicode.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(variant
);
35 extern HMODULE hProxyDll DECLSPEC_HIDDEN
;
37 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
38 #define CY_MULTIPLIER_F 10000.0
39 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
40 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
42 static const WCHAR szFloatFormatW
[] = { '%','.','7','G','\0' };
43 static const WCHAR szDoubleFormatW
[] = { '%','.','1','5','G','\0' };
45 /* Copy data from one variant to another. */
46 static inline void VARIANT_CopyData(const VARIANT
*srcVar
, VARTYPE vt
, void *pOut
)
51 case VT_UI1
: memcpy(pOut
, &V_UI1(srcVar
), sizeof(BYTE
)); break;
54 case VT_UI2
: memcpy(pOut
, &V_UI2(srcVar
), sizeof(SHORT
)); break;
59 case VT_UI4
: memcpy(pOut
, &V_UI4(srcVar
), sizeof (LONG
)); break;
64 case VT_UI8
: memcpy(pOut
, &V_UI8(srcVar
), sizeof (LONG64
)); break;
65 case VT_INT_PTR
: memcpy(pOut
, &V_INT_PTR(srcVar
), sizeof (INT_PTR
)); break;
66 case VT_DECIMAL
: memcpy(pOut
, &V_DECIMAL(srcVar
), sizeof (DECIMAL
)); break;
67 case VT_BSTR
: memcpy(pOut
, &V_BSTR(srcVar
), sizeof(BSTR
)); break;
69 FIXME("VT_ type %d unhandled, please report!\n", vt
);
73 /* Macro to inline conversion from a float or double to any integer type,
74 * rounding according to the 'dutch' convention.
76 #define VARIANT_DutchRound(typ, value, res) do { \
77 double whole = value < 0 ? ceil(value) : floor(value); \
78 double fract = value - whole; \
79 if (fract > 0.5) res = (typ)whole + (typ)1; \
80 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
81 else if (fract >= 0.0) res = (typ)whole; \
82 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
83 else if (fract > -0.5) res = (typ)whole; \
84 else res = (typ)whole - (typ)1; \
88 /* Coerce VT_BSTR to a numeric type */
89 static HRESULT
VARIANT_NumberFromBstr(OLECHAR
* pStrIn
, LCID lcid
, ULONG ulFlags
,
90 void* pOut
, VARTYPE vt
)
97 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
98 np
.cDig
= sizeof(rgb
) / sizeof(BYTE
);
99 np
.dwInFlags
= NUMPRS_STD
;
101 hRet
= VarParseNumFromStr(pStrIn
, lcid
, ulFlags
, &np
, rgb
);
105 /* 1 << vt gives us the VTBIT constant for the destination number type */
106 hRet
= VarNumFromParseNum(&np
, rgb
, 1 << vt
, &dstVar
);
108 VARIANT_CopyData(&dstVar
, vt
, pOut
);
113 /* Coerce VT_DISPATCH to another type */
114 static HRESULT
VARIANT_FromDisp(IDispatch
* pdispIn
, LCID lcid
, void* pOut
,
115 VARTYPE vt
, DWORD dwFlags
)
117 static DISPPARAMS emptyParams
= { NULL
, NULL
, 0, 0 };
118 VARIANTARG srcVar
, dstVar
;
122 return DISP_E_BADVARTYPE
;
124 /* Get the default 'value' property from the IDispatch */
125 VariantInit(&srcVar
);
126 hRet
= IDispatch_Invoke(pdispIn
, DISPID_VALUE
, &IID_NULL
, lcid
, DISPATCH_PROPERTYGET
,
127 &emptyParams
, &srcVar
, NULL
, NULL
);
131 /* Convert the property to the requested type */
132 V_VT(&dstVar
) = VT_EMPTY
;
133 hRet
= VariantChangeTypeEx(&dstVar
, &srcVar
, lcid
, dwFlags
, vt
);
134 VariantClear(&srcVar
);
138 VARIANT_CopyData(&dstVar
, vt
, pOut
);
139 VariantClear(&srcVar
);
143 hRet
= DISP_E_TYPEMISMATCH
;
147 /* Inline return type */
148 #define RETTYP static inline HRESULT
151 /* Simple compiler cast from one type to another */
152 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
153 *out = in; return S_OK; }
155 /* Compiler cast where input cannot be negative */
156 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
157 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
159 /* Compiler cast where input cannot be > some number */
160 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
161 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
163 /* Compiler cast where input cannot be < some number or >= some other number */
164 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
165 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
168 POSTST(signed char, BYTE
, VarI1FromUI1
, I1_MAX
)
169 BOTHTST(signed char, SHORT
, VarI1FromI2
, I1_MIN
, I1_MAX
)
170 BOTHTST(signed char, LONG
, VarI1FromI4
, I1_MIN
, I1_MAX
)
171 SIMPLE(signed char, VARIANT_BOOL
, VarI1FromBool
)
172 POSTST(signed char, USHORT
, VarI1FromUI2
, I1_MAX
)
173 POSTST(signed char, ULONG
, VarI1FromUI4
, I1_MAX
)
174 BOTHTST(signed char, LONG64
, VarI1FromI8
, I1_MIN
, I1_MAX
)
175 POSTST(signed char, ULONG64
, VarI1FromUI8
, I1_MAX
)
178 BOTHTST(BYTE
, SHORT
, VarUI1FromI2
, UI1_MIN
, UI1_MAX
)
179 SIMPLE(BYTE
, VARIANT_BOOL
, VarUI1FromBool
)
180 NEGTST(BYTE
, signed char, VarUI1FromI1
)
181 POSTST(BYTE
, USHORT
, VarUI1FromUI2
, UI1_MAX
)
182 BOTHTST(BYTE
, LONG
, VarUI1FromI4
, UI1_MIN
, UI1_MAX
)
183 POSTST(BYTE
, ULONG
, VarUI1FromUI4
, UI1_MAX
)
184 BOTHTST(BYTE
, LONG64
, VarUI1FromI8
, UI1_MIN
, UI1_MAX
)
185 POSTST(BYTE
, ULONG64
, VarUI1FromUI8
, UI1_MAX
)
188 SIMPLE(SHORT
, BYTE
, VarI2FromUI1
)
189 BOTHTST(SHORT
, LONG
, VarI2FromI4
, I2_MIN
, I2_MAX
)
190 SIMPLE(SHORT
, VARIANT_BOOL
, VarI2FromBool
)
191 SIMPLE(SHORT
, signed char, VarI2FromI1
)
192 POSTST(SHORT
, USHORT
, VarI2FromUI2
, I2_MAX
)
193 POSTST(SHORT
, ULONG
, VarI2FromUI4
, I2_MAX
)
194 BOTHTST(SHORT
, LONG64
, VarI2FromI8
, I2_MIN
, I2_MAX
)
195 POSTST(SHORT
, ULONG64
, VarI2FromUI8
, I2_MAX
)
198 SIMPLE(USHORT
, BYTE
, VarUI2FromUI1
)
199 NEGTST(USHORT
, SHORT
, VarUI2FromI2
)
200 BOTHTST(USHORT
, LONG
, VarUI2FromI4
, UI2_MIN
, UI2_MAX
)
201 SIMPLE(USHORT
, VARIANT_BOOL
, VarUI2FromBool
)
202 NEGTST(USHORT
, signed char, VarUI2FromI1
)
203 POSTST(USHORT
, ULONG
, VarUI2FromUI4
, UI2_MAX
)
204 BOTHTST(USHORT
, LONG64
, VarUI2FromI8
, UI2_MIN
, UI2_MAX
)
205 POSTST(USHORT
, ULONG64
, VarUI2FromUI8
, UI2_MAX
)
208 SIMPLE(LONG
, BYTE
, VarI4FromUI1
)
209 SIMPLE(LONG
, SHORT
, VarI4FromI2
)
210 SIMPLE(LONG
, VARIANT_BOOL
, VarI4FromBool
)
211 SIMPLE(LONG
, signed char, VarI4FromI1
)
212 SIMPLE(LONG
, USHORT
, VarI4FromUI2
)
213 POSTST(LONG
, ULONG
, VarI4FromUI4
, I4_MAX
)
214 BOTHTST(LONG
, LONG64
, VarI4FromI8
, I4_MIN
, I4_MAX
)
215 POSTST(LONG
, ULONG64
, VarI4FromUI8
, I4_MAX
)
218 SIMPLE(ULONG
, BYTE
, VarUI4FromUI1
)
219 NEGTST(ULONG
, SHORT
, VarUI4FromI2
)
220 NEGTST(ULONG
, LONG
, VarUI4FromI4
)
221 SIMPLE(ULONG
, VARIANT_BOOL
, VarUI4FromBool
)
222 NEGTST(ULONG
, signed char, VarUI4FromI1
)
223 SIMPLE(ULONG
, USHORT
, VarUI4FromUI2
)
224 BOTHTST(ULONG
, LONG64
, VarUI4FromI8
, UI4_MIN
, UI4_MAX
)
225 POSTST(ULONG
, ULONG64
, VarUI4FromUI8
, UI4_MAX
)
228 SIMPLE(LONG64
, BYTE
, VarI8FromUI1
)
229 SIMPLE(LONG64
, SHORT
, VarI8FromI2
)
230 SIMPLE(LONG64
, signed char, VarI8FromI1
)
231 SIMPLE(LONG64
, USHORT
, VarI8FromUI2
)
232 SIMPLE(LONG64
, ULONG
, VarI8FromUI4
)
233 POSTST(LONG64
, ULONG64
, VarI8FromUI8
, I8_MAX
)
236 SIMPLE(ULONG64
, BYTE
, VarUI8FromUI1
)
237 NEGTST(ULONG64
, SHORT
, VarUI8FromI2
)
238 NEGTST(ULONG64
, signed char, VarUI8FromI1
)
239 SIMPLE(ULONG64
, USHORT
, VarUI8FromUI2
)
240 SIMPLE(ULONG64
, ULONG
, VarUI8FromUI4
)
241 NEGTST(ULONG64
, LONG64
, VarUI8FromI8
)
244 SIMPLE(float, BYTE
, VarR4FromUI1
)
245 SIMPLE(float, SHORT
, VarR4FromI2
)
246 SIMPLE(float, signed char, VarR4FromI1
)
247 SIMPLE(float, USHORT
, VarR4FromUI2
)
248 SIMPLE(float, LONG
, VarR4FromI4
)
249 SIMPLE(float, ULONG
, VarR4FromUI4
)
250 SIMPLE(float, LONG64
, VarR4FromI8
)
251 SIMPLE(float, ULONG64
, VarR4FromUI8
)
254 SIMPLE(double, BYTE
, VarR8FromUI1
)
255 SIMPLE(double, SHORT
, VarR8FromI2
)
256 SIMPLE(double, float, VarR8FromR4
)
257 RETTYP
_VarR8FromCy(CY i
, double* o
) { *o
= (double)i
.int64
/ CY_MULTIPLIER_F
; return S_OK
; }
258 SIMPLE(double, DATE
, VarR8FromDate
)
259 SIMPLE(double, signed char, VarR8FromI1
)
260 SIMPLE(double, USHORT
, VarR8FromUI2
)
261 SIMPLE(double, LONG
, VarR8FromI4
)
262 SIMPLE(double, ULONG
, VarR8FromUI4
)
263 SIMPLE(double, LONG64
, VarR8FromI8
)
264 SIMPLE(double, ULONG64
, VarR8FromUI8
)
270 /************************************************************************
271 * VarI1FromUI1 (OLEAUT32.244)
273 * Convert a VT_UI1 to a VT_I1.
277 * pcOut [O] Destination
281 * Failure: E_INVALIDARG, if the source value is invalid
282 * DISP_E_OVERFLOW, if the value will not fit in the destination
284 HRESULT WINAPI
VarI1FromUI1(BYTE bIn
, signed char* pcOut
)
286 return _VarI1FromUI1(bIn
, pcOut
);
289 /************************************************************************
290 * VarI1FromI2 (OLEAUT32.245)
292 * Convert a VT_I2 to a VT_I1.
296 * pcOut [O] Destination
300 * Failure: E_INVALIDARG, if the source value is invalid
301 * DISP_E_OVERFLOW, if the value will not fit in the destination
303 HRESULT WINAPI
VarI1FromI2(SHORT sIn
, signed char* pcOut
)
305 return _VarI1FromI2(sIn
, pcOut
);
308 /************************************************************************
309 * VarI1FromI4 (OLEAUT32.246)
311 * Convert a VT_I4 to a VT_I1.
315 * pcOut [O] Destination
319 * Failure: E_INVALIDARG, if the source value is invalid
320 * DISP_E_OVERFLOW, if the value will not fit in the destination
322 HRESULT WINAPI
VarI1FromI4(LONG iIn
, signed char* pcOut
)
324 return _VarI1FromI4(iIn
, pcOut
);
327 /************************************************************************
328 * VarI1FromR4 (OLEAUT32.247)
330 * Convert a VT_R4 to a VT_I1.
334 * pcOut [O] Destination
338 * Failure: E_INVALIDARG, if the source value is invalid
339 * DISP_E_OVERFLOW, if the value will not fit in the destination
341 HRESULT WINAPI
VarI1FromR4(FLOAT fltIn
, signed char* pcOut
)
343 return VarI1FromR8(fltIn
, pcOut
);
346 /************************************************************************
347 * VarI1FromR8 (OLEAUT32.248)
349 * Convert a VT_R8 to a VT_I1.
353 * pcOut [O] Destination
357 * Failure: E_INVALIDARG, if the source value is invalid
358 * DISP_E_OVERFLOW, if the value will not fit in the destination
361 * See VarI8FromR8() for details concerning rounding.
363 HRESULT WINAPI
VarI1FromR8(double dblIn
, signed char* pcOut
)
365 if (dblIn
< I1_MIN
- 0.5 || dblIn
>= I1_MAX
+ 0.5)
366 return DISP_E_OVERFLOW
;
367 VARIANT_DutchRound(CHAR
, dblIn
, *pcOut
);
371 /************************************************************************
372 * VarI1FromDate (OLEAUT32.249)
374 * Convert a VT_DATE to a VT_I1.
378 * pcOut [O] Destination
382 * Failure: E_INVALIDARG, if the source value is invalid
383 * DISP_E_OVERFLOW, if the value will not fit in the destination
385 HRESULT WINAPI
VarI1FromDate(DATE dateIn
, signed char* pcOut
)
387 return VarI1FromR8(dateIn
, pcOut
);
390 /************************************************************************
391 * VarI1FromCy (OLEAUT32.250)
393 * Convert a VT_CY to a VT_I1.
397 * pcOut [O] Destination
401 * Failure: E_INVALIDARG, if the source value is invalid
402 * DISP_E_OVERFLOW, if the value will not fit in the destination
404 HRESULT WINAPI
VarI1FromCy(CY cyIn
, signed char* pcOut
)
408 VarI4FromCy(cyIn
, &i
);
409 return _VarI1FromI4(i
, pcOut
);
412 /************************************************************************
413 * VarI1FromStr (OLEAUT32.251)
415 * Convert a VT_BSTR to a VT_I1.
419 * lcid [I] LCID for the conversion
420 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
421 * pcOut [O] Destination
425 * Failure: E_INVALIDARG, if the source value is invalid
426 * DISP_E_OVERFLOW, if the value will not fit in the destination
427 * DISP_E_TYPEMISMATCH, if the type cannot be converted
429 HRESULT WINAPI
VarI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, signed char* pcOut
)
431 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pcOut
, VT_I1
);
434 /************************************************************************
435 * VarI1FromDisp (OLEAUT32.252)
437 * Convert a VT_DISPATCH to a VT_I1.
441 * lcid [I] LCID for conversion
442 * pcOut [O] Destination
446 * Failure: E_INVALIDARG, if the source value is invalid
447 * DISP_E_OVERFLOW, if the value will not fit in the destination
448 * DISP_E_TYPEMISMATCH, if the type cannot be converted
450 HRESULT WINAPI
VarI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, signed char* pcOut
)
452 return VARIANT_FromDisp(pdispIn
, lcid
, pcOut
, VT_I1
, 0);
455 /************************************************************************
456 * VarI1FromBool (OLEAUT32.253)
458 * Convert a VT_BOOL to a VT_I1.
462 * pcOut [O] Destination
467 HRESULT WINAPI
VarI1FromBool(VARIANT_BOOL boolIn
, signed char* pcOut
)
469 return _VarI1FromBool(boolIn
, pcOut
);
472 /************************************************************************
473 * VarI1FromUI2 (OLEAUT32.254)
475 * Convert a VT_UI2 to a VT_I1.
479 * pcOut [O] Destination
483 * Failure: E_INVALIDARG, if the source value is invalid
484 * DISP_E_OVERFLOW, if the value will not fit in the destination
486 HRESULT WINAPI
VarI1FromUI2(USHORT usIn
, signed char* pcOut
)
488 return _VarI1FromUI2(usIn
, pcOut
);
491 /************************************************************************
492 * VarI1FromUI4 (OLEAUT32.255)
494 * Convert a VT_UI4 to a VT_I1.
498 * pcOut [O] Destination
502 * Failure: E_INVALIDARG, if the source value is invalid
503 * DISP_E_OVERFLOW, if the value will not fit in the destination
504 * DISP_E_TYPEMISMATCH, if the type cannot be converted
506 HRESULT WINAPI
VarI1FromUI4(ULONG ulIn
, signed char* pcOut
)
508 return _VarI1FromUI4(ulIn
, pcOut
);
511 /************************************************************************
512 * VarI1FromDec (OLEAUT32.256)
514 * Convert a VT_DECIMAL to a VT_I1.
518 * pcOut [O] Destination
522 * Failure: E_INVALIDARG, if the source value is invalid
523 * DISP_E_OVERFLOW, if the value will not fit in the destination
525 HRESULT WINAPI
VarI1FromDec(DECIMAL
*pdecIn
, signed char* pcOut
)
530 hRet
= VarI8FromDec(pdecIn
, &i64
);
533 hRet
= _VarI1FromI8(i64
, pcOut
);
537 /************************************************************************
538 * VarI1FromI8 (OLEAUT32.376)
540 * Convert a VT_I8 to a VT_I1.
544 * pcOut [O] Destination
548 * Failure: E_INVALIDARG, if the source value is invalid
549 * DISP_E_OVERFLOW, if the value will not fit in the destination
551 HRESULT WINAPI
VarI1FromI8(LONG64 llIn
, signed char* pcOut
)
553 return _VarI1FromI8(llIn
, pcOut
);
556 /************************************************************************
557 * VarI1FromUI8 (OLEAUT32.377)
559 * Convert a VT_UI8 to a VT_I1.
563 * pcOut [O] Destination
567 * Failure: E_INVALIDARG, if the source value is invalid
568 * DISP_E_OVERFLOW, if the value will not fit in the destination
570 HRESULT WINAPI
VarI1FromUI8(ULONG64 ullIn
, signed char* pcOut
)
572 return _VarI1FromUI8(ullIn
, pcOut
);
578 /************************************************************************
579 * VarUI1FromI2 (OLEAUT32.130)
581 * Convert a VT_I2 to a VT_UI1.
585 * pbOut [O] Destination
589 * Failure: E_INVALIDARG, if the source value is invalid
590 * DISP_E_OVERFLOW, if the value will not fit in the destination
592 HRESULT WINAPI
VarUI1FromI2(SHORT sIn
, BYTE
* pbOut
)
594 return _VarUI1FromI2(sIn
, pbOut
);
597 /************************************************************************
598 * VarUI1FromI4 (OLEAUT32.131)
600 * Convert a VT_I4 to a VT_UI1.
604 * pbOut [O] Destination
608 * Failure: E_INVALIDARG, if the source value is invalid
609 * DISP_E_OVERFLOW, if the value will not fit in the destination
611 HRESULT WINAPI
VarUI1FromI4(LONG iIn
, BYTE
* pbOut
)
613 return _VarUI1FromI4(iIn
, pbOut
);
616 /************************************************************************
617 * VarUI1FromR4 (OLEAUT32.132)
619 * Convert a VT_R4 to a VT_UI1.
623 * pbOut [O] Destination
627 * Failure: E_INVALIDARG, if the source value is invalid
628 * DISP_E_OVERFLOW, if the value will not fit in the destination
629 * DISP_E_TYPEMISMATCH, if the type cannot be converted
631 HRESULT WINAPI
VarUI1FromR4(FLOAT fltIn
, BYTE
* pbOut
)
633 return VarUI1FromR8(fltIn
, pbOut
);
636 /************************************************************************
637 * VarUI1FromR8 (OLEAUT32.133)
639 * Convert a VT_R8 to a VT_UI1.
643 * pbOut [O] Destination
647 * Failure: E_INVALIDARG, if the source value is invalid
648 * DISP_E_OVERFLOW, if the value will not fit in the destination
651 * See VarI8FromR8() for details concerning rounding.
653 HRESULT WINAPI
VarUI1FromR8(double dblIn
, BYTE
* pbOut
)
655 if (dblIn
< -0.5 || dblIn
>= UI1_MAX
+ 0.5)
656 return DISP_E_OVERFLOW
;
657 VARIANT_DutchRound(BYTE
, dblIn
, *pbOut
);
661 /************************************************************************
662 * VarUI1FromCy (OLEAUT32.134)
664 * Convert a VT_CY to a VT_UI1.
668 * pbOut [O] Destination
672 * Failure: E_INVALIDARG, if the source value is invalid
673 * DISP_E_OVERFLOW, if the value will not fit in the destination
676 * Negative values >= -5000 will be converted to 0.
678 HRESULT WINAPI
VarUI1FromCy(CY cyIn
, BYTE
* pbOut
)
680 ULONG i
= UI1_MAX
+ 1;
682 VarUI4FromCy(cyIn
, &i
);
683 return _VarUI1FromUI4(i
, pbOut
);
686 /************************************************************************
687 * VarUI1FromDate (OLEAUT32.135)
689 * Convert a VT_DATE to a VT_UI1.
693 * pbOut [O] Destination
697 * Failure: E_INVALIDARG, if the source value is invalid
698 * DISP_E_OVERFLOW, if the value will not fit in the destination
700 HRESULT WINAPI
VarUI1FromDate(DATE dateIn
, BYTE
* pbOut
)
702 return VarUI1FromR8(dateIn
, pbOut
);
705 /************************************************************************
706 * VarUI1FromStr (OLEAUT32.136)
708 * Convert a VT_BSTR to a VT_UI1.
712 * lcid [I] LCID for the conversion
713 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
714 * pbOut [O] Destination
718 * Failure: E_INVALIDARG, if the source value is invalid
719 * DISP_E_OVERFLOW, if the value will not fit in the destination
720 * DISP_E_TYPEMISMATCH, if the type cannot be converted
722 HRESULT WINAPI
VarUI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, BYTE
* pbOut
)
724 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pbOut
, VT_UI1
);
727 /************************************************************************
728 * VarUI1FromDisp (OLEAUT32.137)
730 * Convert a VT_DISPATCH to a VT_UI1.
734 * lcid [I] LCID for conversion
735 * pbOut [O] Destination
739 * Failure: E_INVALIDARG, if the source value is invalid
740 * DISP_E_OVERFLOW, if the value will not fit in the destination
741 * DISP_E_TYPEMISMATCH, if the type cannot be converted
743 HRESULT WINAPI
VarUI1FromDisp(IDispatch
* pdispIn
, LCID lcid
, BYTE
* pbOut
)
745 return VARIANT_FromDisp(pdispIn
, lcid
, pbOut
, VT_UI1
, 0);
748 /************************************************************************
749 * VarUI1FromBool (OLEAUT32.138)
751 * Convert a VT_BOOL to a VT_UI1.
755 * pbOut [O] Destination
760 HRESULT WINAPI
VarUI1FromBool(VARIANT_BOOL boolIn
, BYTE
* pbOut
)
762 return _VarUI1FromBool(boolIn
, pbOut
);
765 /************************************************************************
766 * VarUI1FromI1 (OLEAUT32.237)
768 * Convert a VT_I1 to a VT_UI1.
772 * pbOut [O] Destination
776 * Failure: E_INVALIDARG, if the source value is invalid
777 * DISP_E_OVERFLOW, if the value will not fit in the destination
779 HRESULT WINAPI
VarUI1FromI1(signed char cIn
, BYTE
* pbOut
)
781 return _VarUI1FromI1(cIn
, pbOut
);
784 /************************************************************************
785 * VarUI1FromUI2 (OLEAUT32.238)
787 * Convert a VT_UI2 to a VT_UI1.
791 * pbOut [O] Destination
795 * Failure: E_INVALIDARG, if the source value is invalid
796 * DISP_E_OVERFLOW, if the value will not fit in the destination
798 HRESULT WINAPI
VarUI1FromUI2(USHORT usIn
, BYTE
* pbOut
)
800 return _VarUI1FromUI2(usIn
, pbOut
);
803 /************************************************************************
804 * VarUI1FromUI4 (OLEAUT32.239)
806 * Convert a VT_UI4 to a VT_UI1.
810 * pbOut [O] Destination
814 * Failure: E_INVALIDARG, if the source value is invalid
815 * DISP_E_OVERFLOW, if the value will not fit in the destination
817 HRESULT WINAPI
VarUI1FromUI4(ULONG ulIn
, BYTE
* pbOut
)
819 return _VarUI1FromUI4(ulIn
, pbOut
);
822 /************************************************************************
823 * VarUI1FromDec (OLEAUT32.240)
825 * Convert a VT_DECIMAL to a VT_UI1.
829 * pbOut [O] Destination
833 * Failure: E_INVALIDARG, if the source value is invalid
834 * DISP_E_OVERFLOW, if the value will not fit in the destination
836 HRESULT WINAPI
VarUI1FromDec(DECIMAL
*pdecIn
, BYTE
* pbOut
)
841 hRet
= VarI8FromDec(pdecIn
, &i64
);
844 hRet
= _VarUI1FromI8(i64
, pbOut
);
848 /************************************************************************
849 * VarUI1FromI8 (OLEAUT32.372)
851 * Convert a VT_I8 to a VT_UI1.
855 * pbOut [O] Destination
859 * Failure: E_INVALIDARG, if the source value is invalid
860 * DISP_E_OVERFLOW, if the value will not fit in the destination
862 HRESULT WINAPI
VarUI1FromI8(LONG64 llIn
, BYTE
* pbOut
)
864 return _VarUI1FromI8(llIn
, pbOut
);
867 /************************************************************************
868 * VarUI1FromUI8 (OLEAUT32.373)
870 * Convert a VT_UI8 to a VT_UI1.
874 * pbOut [O] Destination
878 * Failure: E_INVALIDARG, if the source value is invalid
879 * DISP_E_OVERFLOW, if the value will not fit in the destination
881 HRESULT WINAPI
VarUI1FromUI8(ULONG64 ullIn
, BYTE
* pbOut
)
883 return _VarUI1FromUI8(ullIn
, pbOut
);
890 /************************************************************************
891 * VarI2FromUI1 (OLEAUT32.48)
893 * Convert a VT_UI2 to a VT_I2.
897 * psOut [O] Destination
902 HRESULT WINAPI
VarI2FromUI1(BYTE bIn
, SHORT
* psOut
)
904 return _VarI2FromUI1(bIn
, psOut
);
907 /************************************************************************
908 * VarI2FromI4 (OLEAUT32.49)
910 * Convert a VT_I4 to a VT_I2.
914 * psOut [O] Destination
918 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
920 HRESULT WINAPI
VarI2FromI4(LONG iIn
, SHORT
* psOut
)
922 return _VarI2FromI4(iIn
, psOut
);
925 /************************************************************************
926 * VarI2FromR4 (OLEAUT32.50)
928 * Convert a VT_R4 to a VT_I2.
932 * psOut [O] Destination
936 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
938 HRESULT WINAPI
VarI2FromR4(FLOAT fltIn
, SHORT
* psOut
)
940 return VarI2FromR8(fltIn
, psOut
);
943 /************************************************************************
944 * VarI2FromR8 (OLEAUT32.51)
946 * Convert a VT_R8 to a VT_I2.
950 * psOut [O] Destination
954 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
957 * See VarI8FromR8() for details concerning rounding.
959 HRESULT WINAPI
VarI2FromR8(double dblIn
, SHORT
* psOut
)
961 if (dblIn
< I2_MIN
- 0.5 || dblIn
>= I2_MAX
+ 0.5)
962 return DISP_E_OVERFLOW
;
963 VARIANT_DutchRound(SHORT
, dblIn
, *psOut
);
967 /************************************************************************
968 * VarI2FromCy (OLEAUT32.52)
970 * Convert a VT_CY to a VT_I2.
974 * psOut [O] Destination
978 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
980 HRESULT WINAPI
VarI2FromCy(CY cyIn
, SHORT
* psOut
)
984 VarI4FromCy(cyIn
, &i
);
985 return _VarI2FromI4(i
, psOut
);
988 /************************************************************************
989 * VarI2FromDate (OLEAUT32.53)
991 * Convert a VT_DATE to a VT_I2.
995 * psOut [O] Destination
999 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1001 HRESULT WINAPI
VarI2FromDate(DATE dateIn
, SHORT
* psOut
)
1003 return VarI2FromR8(dateIn
, psOut
);
1006 /************************************************************************
1007 * VarI2FromStr (OLEAUT32.54)
1009 * Convert a VT_BSTR to a VT_I2.
1013 * lcid [I] LCID for the conversion
1014 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1015 * psOut [O] Destination
1019 * Failure: E_INVALIDARG, if any parameter is invalid
1020 * DISP_E_OVERFLOW, if the value will not fit in the destination
1021 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1023 HRESULT WINAPI
VarI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, SHORT
* psOut
)
1025 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, psOut
, VT_I2
);
1028 /************************************************************************
1029 * VarI2FromDisp (OLEAUT32.55)
1031 * Convert a VT_DISPATCH to a VT_I2.
1034 * pdispIn [I] Source
1035 * lcid [I] LCID for conversion
1036 * psOut [O] Destination
1040 * Failure: E_INVALIDARG, if pdispIn is invalid,
1041 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1042 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1044 HRESULT WINAPI
VarI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, SHORT
* psOut
)
1046 return VARIANT_FromDisp(pdispIn
, lcid
, psOut
, VT_I2
, 0);
1049 /************************************************************************
1050 * VarI2FromBool (OLEAUT32.56)
1052 * Convert a VT_BOOL to a VT_I2.
1056 * psOut [O] Destination
1061 HRESULT WINAPI
VarI2FromBool(VARIANT_BOOL boolIn
, SHORT
* psOut
)
1063 return _VarI2FromBool(boolIn
, psOut
);
1066 /************************************************************************
1067 * VarI2FromI1 (OLEAUT32.205)
1069 * Convert a VT_I1 to a VT_I2.
1073 * psOut [O] Destination
1078 HRESULT WINAPI
VarI2FromI1(signed char cIn
, SHORT
* psOut
)
1080 return _VarI2FromI1(cIn
, psOut
);
1083 /************************************************************************
1084 * VarI2FromUI2 (OLEAUT32.206)
1086 * Convert a VT_UI2 to a VT_I2.
1090 * psOut [O] Destination
1094 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1096 HRESULT WINAPI
VarI2FromUI2(USHORT usIn
, SHORT
* psOut
)
1098 return _VarI2FromUI2(usIn
, psOut
);
1101 /************************************************************************
1102 * VarI2FromUI4 (OLEAUT32.207)
1104 * Convert a VT_UI4 to a VT_I2.
1108 * psOut [O] Destination
1112 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1114 HRESULT WINAPI
VarI2FromUI4(ULONG ulIn
, SHORT
* psOut
)
1116 return _VarI2FromUI4(ulIn
, psOut
);
1119 /************************************************************************
1120 * VarI2FromDec (OLEAUT32.208)
1122 * Convert a VT_DECIMAL to a VT_I2.
1126 * psOut [O] Destination
1130 * Failure: E_INVALIDARG, if the source value is invalid
1131 * DISP_E_OVERFLOW, if the value will not fit in the destination
1133 HRESULT WINAPI
VarI2FromDec(DECIMAL
*pdecIn
, SHORT
* psOut
)
1138 hRet
= VarI8FromDec(pdecIn
, &i64
);
1140 if (SUCCEEDED(hRet
))
1141 hRet
= _VarI2FromI8(i64
, psOut
);
1145 /************************************************************************
1146 * VarI2FromI8 (OLEAUT32.346)
1148 * Convert a VT_I8 to a VT_I2.
1152 * psOut [O] Destination
1156 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1158 HRESULT WINAPI
VarI2FromI8(LONG64 llIn
, SHORT
* psOut
)
1160 return _VarI2FromI8(llIn
, psOut
);
1163 /************************************************************************
1164 * VarI2FromUI8 (OLEAUT32.347)
1166 * Convert a VT_UI8 to a VT_I2.
1170 * psOut [O] Destination
1174 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1176 HRESULT WINAPI
VarI2FromUI8(ULONG64 ullIn
, SHORT
* psOut
)
1178 return _VarI2FromUI8(ullIn
, psOut
);
1184 /************************************************************************
1185 * VarUI2FromUI1 (OLEAUT32.257)
1187 * Convert a VT_UI1 to a VT_UI2.
1191 * pusOut [O] Destination
1196 HRESULT WINAPI
VarUI2FromUI1(BYTE bIn
, USHORT
* pusOut
)
1198 return _VarUI2FromUI1(bIn
, pusOut
);
1201 /************************************************************************
1202 * VarUI2FromI2 (OLEAUT32.258)
1204 * Convert a VT_I2 to a VT_UI2.
1208 * pusOut [O] Destination
1212 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1214 HRESULT WINAPI
VarUI2FromI2(SHORT sIn
, USHORT
* pusOut
)
1216 return _VarUI2FromI2(sIn
, pusOut
);
1219 /************************************************************************
1220 * VarUI2FromI4 (OLEAUT32.259)
1222 * Convert a VT_I4 to a VT_UI2.
1226 * pusOut [O] Destination
1230 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1232 HRESULT WINAPI
VarUI2FromI4(LONG iIn
, USHORT
* pusOut
)
1234 return _VarUI2FromI4(iIn
, pusOut
);
1237 /************************************************************************
1238 * VarUI2FromR4 (OLEAUT32.260)
1240 * Convert a VT_R4 to a VT_UI2.
1244 * pusOut [O] Destination
1248 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1250 HRESULT WINAPI
VarUI2FromR4(FLOAT fltIn
, USHORT
* pusOut
)
1252 return VarUI2FromR8(fltIn
, pusOut
);
1255 /************************************************************************
1256 * VarUI2FromR8 (OLEAUT32.261)
1258 * Convert a VT_R8 to a VT_UI2.
1262 * pusOut [O] Destination
1266 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1269 * See VarI8FromR8() for details concerning rounding.
1271 HRESULT WINAPI
VarUI2FromR8(double dblIn
, USHORT
* pusOut
)
1273 if (dblIn
< -0.5 || dblIn
>= UI2_MAX
+ 0.5)
1274 return DISP_E_OVERFLOW
;
1275 VARIANT_DutchRound(USHORT
, dblIn
, *pusOut
);
1279 /************************************************************************
1280 * VarUI2FromDate (OLEAUT32.262)
1282 * Convert a VT_DATE to a VT_UI2.
1286 * pusOut [O] Destination
1290 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1292 HRESULT WINAPI
VarUI2FromDate(DATE dateIn
, USHORT
* pusOut
)
1294 return VarUI2FromR8(dateIn
, pusOut
);
1297 /************************************************************************
1298 * VarUI2FromCy (OLEAUT32.263)
1300 * Convert a VT_CY to a VT_UI2.
1304 * pusOut [O] Destination
1308 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1311 * Negative values >= -5000 will be converted to 0.
1313 HRESULT WINAPI
VarUI2FromCy(CY cyIn
, USHORT
* pusOut
)
1315 ULONG i
= UI2_MAX
+ 1;
1317 VarUI4FromCy(cyIn
, &i
);
1318 return _VarUI2FromUI4(i
, pusOut
);
1321 /************************************************************************
1322 * VarUI2FromStr (OLEAUT32.264)
1324 * Convert a VT_BSTR to a VT_UI2.
1328 * lcid [I] LCID for the conversion
1329 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1330 * pusOut [O] Destination
1334 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1335 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1337 HRESULT WINAPI
VarUI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, USHORT
* pusOut
)
1339 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pusOut
, VT_UI2
);
1342 /************************************************************************
1343 * VarUI2FromDisp (OLEAUT32.265)
1345 * Convert a VT_DISPATCH to a VT_UI2.
1348 * pdispIn [I] Source
1349 * lcid [I] LCID for conversion
1350 * pusOut [O] Destination
1354 * Failure: E_INVALIDARG, if the source value is invalid
1355 * DISP_E_OVERFLOW, if the value will not fit in the destination
1356 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1358 HRESULT WINAPI
VarUI2FromDisp(IDispatch
* pdispIn
, LCID lcid
, USHORT
* pusOut
)
1360 return VARIANT_FromDisp(pdispIn
, lcid
, pusOut
, VT_UI2
, 0);
1363 /************************************************************************
1364 * VarUI2FromBool (OLEAUT32.266)
1366 * Convert a VT_BOOL to a VT_UI2.
1370 * pusOut [O] Destination
1375 HRESULT WINAPI
VarUI2FromBool(VARIANT_BOOL boolIn
, USHORT
* pusOut
)
1377 return _VarUI2FromBool(boolIn
, pusOut
);
1380 /************************************************************************
1381 * VarUI2FromI1 (OLEAUT32.267)
1383 * Convert a VT_I1 to a VT_UI2.
1387 * pusOut [O] Destination
1391 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1393 HRESULT WINAPI
VarUI2FromI1(signed char cIn
, USHORT
* pusOut
)
1395 return _VarUI2FromI1(cIn
, pusOut
);
1398 /************************************************************************
1399 * VarUI2FromUI4 (OLEAUT32.268)
1401 * Convert a VT_UI4 to a VT_UI2.
1405 * pusOut [O] Destination
1409 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1411 HRESULT WINAPI
VarUI2FromUI4(ULONG ulIn
, USHORT
* pusOut
)
1413 return _VarUI2FromUI4(ulIn
, pusOut
);
1416 /************************************************************************
1417 * VarUI2FromDec (OLEAUT32.269)
1419 * Convert a VT_DECIMAL to a VT_UI2.
1423 * pusOut [O] Destination
1427 * Failure: E_INVALIDARG, if the source value is invalid
1428 * DISP_E_OVERFLOW, if the value will not fit in the destination
1430 HRESULT WINAPI
VarUI2FromDec(DECIMAL
*pdecIn
, USHORT
* pusOut
)
1435 hRet
= VarI8FromDec(pdecIn
, &i64
);
1437 if (SUCCEEDED(hRet
))
1438 hRet
= _VarUI2FromI8(i64
, pusOut
);
1442 /************************************************************************
1443 * VarUI2FromI8 (OLEAUT32.378)
1445 * Convert a VT_I8 to a VT_UI2.
1449 * pusOut [O] Destination
1453 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1455 HRESULT WINAPI
VarUI2FromI8(LONG64 llIn
, USHORT
* pusOut
)
1457 return _VarUI2FromI8(llIn
, pusOut
);
1460 /************************************************************************
1461 * VarUI2FromUI8 (OLEAUT32.379)
1463 * Convert a VT_UI8 to a VT_UI2.
1467 * pusOut [O] Destination
1471 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1473 HRESULT WINAPI
VarUI2FromUI8(ULONG64 ullIn
, USHORT
* pusOut
)
1475 return _VarUI2FromUI8(ullIn
, pusOut
);
1481 /************************************************************************
1482 * VarI4FromUI1 (OLEAUT32.58)
1484 * Convert a VT_UI1 to a VT_I4.
1488 * piOut [O] Destination
1493 HRESULT WINAPI
VarI4FromUI1(BYTE bIn
, LONG
*piOut
)
1495 return _VarI4FromUI1(bIn
, piOut
);
1498 /************************************************************************
1499 * VarI4FromI2 (OLEAUT32.59)
1501 * Convert a VT_I2 to a VT_I4.
1505 * piOut [O] Destination
1509 * Failure: E_INVALIDARG, if the source value is invalid
1510 * DISP_E_OVERFLOW, if the value will not fit in the destination
1512 HRESULT WINAPI
VarI4FromI2(SHORT sIn
, LONG
*piOut
)
1514 return _VarI4FromI2(sIn
, piOut
);
1517 /************************************************************************
1518 * VarI4FromR4 (OLEAUT32.60)
1520 * Convert a VT_R4 to a VT_I4.
1524 * piOut [O] Destination
1528 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1530 HRESULT WINAPI
VarI4FromR4(FLOAT fltIn
, LONG
*piOut
)
1532 return VarI4FromR8(fltIn
, piOut
);
1535 /************************************************************************
1536 * VarI4FromR8 (OLEAUT32.61)
1538 * Convert a VT_R8 to a VT_I4.
1542 * piOut [O] Destination
1546 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1549 * See VarI8FromR8() for details concerning rounding.
1551 HRESULT WINAPI
VarI4FromR8(double dblIn
, LONG
*piOut
)
1553 if (dblIn
< I4_MIN
- 0.5 || dblIn
>= I4_MAX
+ 0.5)
1554 return DISP_E_OVERFLOW
;
1555 VARIANT_DutchRound(LONG
, dblIn
, *piOut
);
1559 /************************************************************************
1560 * VarI4FromCy (OLEAUT32.62)
1562 * Convert a VT_CY to a VT_I4.
1566 * piOut [O] Destination
1570 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1572 HRESULT WINAPI
VarI4FromCy(CY cyIn
, LONG
*piOut
)
1574 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1575 return VarI4FromR8(d
, piOut
);
1578 /************************************************************************
1579 * VarI4FromDate (OLEAUT32.63)
1581 * Convert a VT_DATE to a VT_I4.
1585 * piOut [O] Destination
1589 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1591 HRESULT WINAPI
VarI4FromDate(DATE dateIn
, LONG
*piOut
)
1593 return VarI4FromR8(dateIn
, piOut
);
1596 /************************************************************************
1597 * VarI4FromStr (OLEAUT32.64)
1599 * Convert a VT_BSTR to a VT_I4.
1603 * lcid [I] LCID for the conversion
1604 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1605 * piOut [O] Destination
1609 * Failure: E_INVALIDARG, if any parameter is invalid
1610 * DISP_E_OVERFLOW, if the value will not fit in the destination
1611 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1613 HRESULT WINAPI
VarI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG
*piOut
)
1615 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, piOut
, VT_I4
);
1618 /************************************************************************
1619 * VarI4FromDisp (OLEAUT32.65)
1621 * Convert a VT_DISPATCH to a VT_I4.
1624 * pdispIn [I] Source
1625 * lcid [I] LCID for conversion
1626 * piOut [O] Destination
1630 * Failure: E_INVALIDARG, if the source value is invalid
1631 * DISP_E_OVERFLOW, if the value will not fit in the destination
1632 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1634 HRESULT WINAPI
VarI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG
*piOut
)
1636 return VARIANT_FromDisp(pdispIn
, lcid
, piOut
, VT_I4
, 0);
1639 /************************************************************************
1640 * VarI4FromBool (OLEAUT32.66)
1642 * Convert a VT_BOOL to a VT_I4.
1646 * piOut [O] Destination
1651 HRESULT WINAPI
VarI4FromBool(VARIANT_BOOL boolIn
, LONG
*piOut
)
1653 return _VarI4FromBool(boolIn
, piOut
);
1656 /************************************************************************
1657 * VarI4FromI1 (OLEAUT32.209)
1659 * Convert a VT_I1 to a VT_I4.
1663 * piOut [O] Destination
1668 HRESULT WINAPI
VarI4FromI1(signed char cIn
, LONG
*piOut
)
1670 return _VarI4FromI1(cIn
, piOut
);
1673 /************************************************************************
1674 * VarI4FromUI2 (OLEAUT32.210)
1676 * Convert a VT_UI2 to a VT_I4.
1680 * piOut [O] Destination
1685 HRESULT WINAPI
VarI4FromUI2(USHORT usIn
, LONG
*piOut
)
1687 return _VarI4FromUI2(usIn
, piOut
);
1690 /************************************************************************
1691 * VarI4FromUI4 (OLEAUT32.211)
1693 * Convert a VT_UI4 to a VT_I4.
1697 * piOut [O] Destination
1701 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1703 HRESULT WINAPI
VarI4FromUI4(ULONG ulIn
, LONG
*piOut
)
1705 return _VarI4FromUI4(ulIn
, piOut
);
1708 /************************************************************************
1709 * VarI4FromDec (OLEAUT32.212)
1711 * Convert a VT_DECIMAL to a VT_I4.
1715 * piOut [O] Destination
1719 * Failure: E_INVALIDARG, if pdecIn is invalid
1720 * DISP_E_OVERFLOW, if the value will not fit in the destination
1722 HRESULT WINAPI
VarI4FromDec(DECIMAL
*pdecIn
, LONG
*piOut
)
1727 hRet
= VarI8FromDec(pdecIn
, &i64
);
1729 if (SUCCEEDED(hRet
))
1730 hRet
= _VarI4FromI8(i64
, piOut
);
1734 /************************************************************************
1735 * VarI4FromI8 (OLEAUT32.348)
1737 * Convert a VT_I8 to a VT_I4.
1741 * piOut [O] Destination
1745 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1747 HRESULT WINAPI
VarI4FromI8(LONG64 llIn
, LONG
*piOut
)
1749 return _VarI4FromI8(llIn
, piOut
);
1752 /************************************************************************
1753 * VarI4FromUI8 (OLEAUT32.349)
1755 * Convert a VT_UI8 to a VT_I4.
1759 * piOut [O] Destination
1763 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1765 HRESULT WINAPI
VarI4FromUI8(ULONG64 ullIn
, LONG
*piOut
)
1767 return _VarI4FromUI8(ullIn
, piOut
);
1773 /************************************************************************
1774 * VarUI4FromUI1 (OLEAUT32.270)
1776 * Convert a VT_UI1 to a VT_UI4.
1780 * pulOut [O] Destination
1785 HRESULT WINAPI
VarUI4FromUI1(BYTE bIn
, ULONG
*pulOut
)
1787 return _VarUI4FromUI1(bIn
, pulOut
);
1790 /************************************************************************
1791 * VarUI4FromI2 (OLEAUT32.271)
1793 * Convert a VT_I2 to a VT_UI4.
1797 * pulOut [O] Destination
1801 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1803 HRESULT WINAPI
VarUI4FromI2(SHORT sIn
, ULONG
*pulOut
)
1805 return _VarUI4FromI2(sIn
, pulOut
);
1808 /************************************************************************
1809 * VarUI4FromI4 (OLEAUT32.272)
1811 * Convert a VT_I4 to a VT_UI4.
1815 * pulOut [O] Destination
1819 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1821 HRESULT WINAPI
VarUI4FromI4(LONG iIn
, ULONG
*pulOut
)
1823 return _VarUI4FromI4(iIn
, pulOut
);
1826 /************************************************************************
1827 * VarUI4FromR4 (OLEAUT32.273)
1829 * Convert a VT_R4 to a VT_UI4.
1833 * pulOut [O] Destination
1837 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1839 HRESULT WINAPI
VarUI4FromR4(FLOAT fltIn
, ULONG
*pulOut
)
1841 return VarUI4FromR8(fltIn
, pulOut
);
1844 /************************************************************************
1845 * VarUI4FromR8 (OLEAUT32.274)
1847 * Convert a VT_R8 to a VT_UI4.
1851 * pulOut [O] Destination
1855 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1858 * See VarI8FromR8() for details concerning rounding.
1860 HRESULT WINAPI
VarUI4FromR8(double dblIn
, ULONG
*pulOut
)
1862 if (dblIn
< -0.5 || dblIn
>= UI4_MAX
+ 0.5)
1863 return DISP_E_OVERFLOW
;
1864 VARIANT_DutchRound(ULONG
, dblIn
, *pulOut
);
1868 /************************************************************************
1869 * VarUI4FromDate (OLEAUT32.275)
1871 * Convert a VT_DATE to a VT_UI4.
1875 * pulOut [O] Destination
1879 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1881 HRESULT WINAPI
VarUI4FromDate(DATE dateIn
, ULONG
*pulOut
)
1883 return VarUI4FromR8(dateIn
, pulOut
);
1886 /************************************************************************
1887 * VarUI4FromCy (OLEAUT32.276)
1889 * Convert a VT_CY to a VT_UI4.
1893 * pulOut [O] Destination
1897 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1899 HRESULT WINAPI
VarUI4FromCy(CY cyIn
, ULONG
*pulOut
)
1901 double d
= cyIn
.int64
/ CY_MULTIPLIER_F
;
1902 return VarUI4FromR8(d
, pulOut
);
1905 /************************************************************************
1906 * VarUI4FromStr (OLEAUT32.277)
1908 * Convert a VT_BSTR to a VT_UI4.
1912 * lcid [I] LCID for the conversion
1913 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1914 * pulOut [O] Destination
1918 * Failure: E_INVALIDARG, if any parameter is invalid
1919 * DISP_E_OVERFLOW, if the value will not fit in the destination
1920 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1922 HRESULT WINAPI
VarUI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG
*pulOut
)
1924 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pulOut
, VT_UI4
);
1927 /************************************************************************
1928 * VarUI4FromDisp (OLEAUT32.278)
1930 * Convert a VT_DISPATCH to a VT_UI4.
1933 * pdispIn [I] Source
1934 * lcid [I] LCID for conversion
1935 * pulOut [O] Destination
1939 * Failure: E_INVALIDARG, if the source value is invalid
1940 * DISP_E_OVERFLOW, if the value will not fit in the destination
1941 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1943 HRESULT WINAPI
VarUI4FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG
*pulOut
)
1945 return VARIANT_FromDisp(pdispIn
, lcid
, pulOut
, VT_UI4
, 0);
1948 /************************************************************************
1949 * VarUI4FromBool (OLEAUT32.279)
1951 * Convert a VT_BOOL to a VT_UI4.
1955 * pulOut [O] Destination
1960 HRESULT WINAPI
VarUI4FromBool(VARIANT_BOOL boolIn
, ULONG
*pulOut
)
1962 return _VarUI4FromBool(boolIn
, pulOut
);
1965 /************************************************************************
1966 * VarUI4FromI1 (OLEAUT32.280)
1968 * Convert a VT_I1 to a VT_UI4.
1972 * pulOut [O] Destination
1976 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1978 HRESULT WINAPI
VarUI4FromI1(signed char cIn
, ULONG
*pulOut
)
1980 return _VarUI4FromI1(cIn
, pulOut
);
1983 /************************************************************************
1984 * VarUI4FromUI2 (OLEAUT32.281)
1986 * Convert a VT_UI2 to a VT_UI4.
1990 * pulOut [O] Destination
1995 HRESULT WINAPI
VarUI4FromUI2(USHORT usIn
, ULONG
*pulOut
)
1997 return _VarUI4FromUI2(usIn
, pulOut
);
2000 /************************************************************************
2001 * VarUI4FromDec (OLEAUT32.282)
2003 * Convert a VT_DECIMAL to a VT_UI4.
2007 * pulOut [O] Destination
2011 * Failure: E_INVALIDARG, if pdecIn is invalid
2012 * DISP_E_OVERFLOW, if the value will not fit in the destination
2014 HRESULT WINAPI
VarUI4FromDec(DECIMAL
*pdecIn
, ULONG
*pulOut
)
2019 hRet
= VarI8FromDec(pdecIn
, &i64
);
2021 if (SUCCEEDED(hRet
))
2022 hRet
= _VarUI4FromI8(i64
, pulOut
);
2026 /************************************************************************
2027 * VarUI4FromI8 (OLEAUT32.425)
2029 * Convert a VT_I8 to a VT_UI4.
2033 * pulOut [O] Destination
2037 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2039 HRESULT WINAPI
VarUI4FromI8(LONG64 llIn
, ULONG
*pulOut
)
2041 return _VarUI4FromI8(llIn
, pulOut
);
2044 /************************************************************************
2045 * VarUI4FromUI8 (OLEAUT32.426)
2047 * Convert a VT_UI8 to a VT_UI4.
2051 * pulOut [O] Destination
2055 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2057 HRESULT WINAPI
VarUI4FromUI8(ULONG64 ullIn
, ULONG
*pulOut
)
2059 return _VarUI4FromUI8(ullIn
, pulOut
);
2065 /************************************************************************
2066 * VarI8FromUI1 (OLEAUT32.333)
2068 * Convert a VT_UI1 to a VT_I8.
2072 * pi64Out [O] Destination
2077 HRESULT WINAPI
VarI8FromUI1(BYTE bIn
, LONG64
* pi64Out
)
2079 return _VarI8FromUI1(bIn
, pi64Out
);
2083 /************************************************************************
2084 * VarI8FromI2 (OLEAUT32.334)
2086 * Convert a VT_I2 to a VT_I8.
2090 * pi64Out [O] Destination
2095 HRESULT WINAPI
VarI8FromI2(SHORT sIn
, LONG64
* pi64Out
)
2097 return _VarI8FromI2(sIn
, pi64Out
);
2100 /************************************************************************
2101 * VarI8FromR4 (OLEAUT32.335)
2103 * Convert a VT_R4 to a VT_I8.
2107 * pi64Out [O] Destination
2111 * Failure: E_INVALIDARG, if the source value is invalid
2112 * DISP_E_OVERFLOW, if the value will not fit in the destination
2114 HRESULT WINAPI
VarI8FromR4(FLOAT fltIn
, LONG64
* pi64Out
)
2116 return VarI8FromR8(fltIn
, pi64Out
);
2119 /************************************************************************
2120 * VarI8FromR8 (OLEAUT32.336)
2122 * Convert a VT_R8 to a VT_I8.
2126 * pi64Out [O] Destination
2130 * Failure: E_INVALIDARG, if the source value is invalid
2131 * DISP_E_OVERFLOW, if the value will not fit in the destination
2134 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2135 * very high or low values will not be accurately converted.
2137 * Numbers are rounded using Dutch rounding, as follows:
2139 *| Fractional Part Sign Direction Example
2140 *| --------------- ---- --------- -------
2141 *| < 0.5 + Down 0.4 -> 0.0
2142 *| < 0.5 - Up -0.4 -> 0.0
2143 *| > 0.5 + Up 0.6 -> 1.0
2144 *| < 0.5 - Up -0.6 -> -1.0
2145 *| = 0.5 + Up/Down Down if even, Up if odd
2146 *| = 0.5 - Up/Down Up if even, Down if odd
2148 * This system is often used in supermarkets.
2150 HRESULT WINAPI
VarI8FromR8(double dblIn
, LONG64
* pi64Out
)
2152 if ( dblIn
< -4611686018427387904.0 || dblIn
>= 4611686018427387904.0)
2153 return DISP_E_OVERFLOW
;
2154 VARIANT_DutchRound(LONG64
, dblIn
, *pi64Out
);
2158 /************************************************************************
2159 * VarI8FromCy (OLEAUT32.337)
2161 * Convert a VT_CY to a VT_I8.
2165 * pi64Out [O] Destination
2171 * All negative numbers are rounded down by 1, including those that are
2172 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2173 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2176 HRESULT WINAPI
VarI8FromCy(CY cyIn
, LONG64
* pi64Out
)
2178 *pi64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2181 (*pi64Out
)--; /* Mimic Win32 bug */
2184 cyIn
.int64
-= *pi64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2186 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pi64Out
& 0x1)))
2192 /************************************************************************
2193 * VarI8FromDate (OLEAUT32.338)
2195 * Convert a VT_DATE to a VT_I8.
2199 * pi64Out [O] Destination
2203 * Failure: E_INVALIDARG, if the source value is invalid
2204 * DISP_E_OVERFLOW, if the value will not fit in the destination
2205 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2207 HRESULT WINAPI
VarI8FromDate(DATE dateIn
, LONG64
* pi64Out
)
2209 return VarI8FromR8(dateIn
, pi64Out
);
2212 /************************************************************************
2213 * VarI8FromStr (OLEAUT32.339)
2215 * Convert a VT_BSTR to a VT_I8.
2219 * lcid [I] LCID for the conversion
2220 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2221 * pi64Out [O] Destination
2225 * Failure: E_INVALIDARG, if the source value is invalid
2226 * DISP_E_OVERFLOW, if the value will not fit in the destination
2227 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2229 HRESULT WINAPI
VarI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG64
* pi64Out
)
2231 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pi64Out
, VT_I8
);
2234 /************************************************************************
2235 * VarI8FromDisp (OLEAUT32.340)
2237 * Convert a VT_DISPATCH to a VT_I8.
2240 * pdispIn [I] Source
2241 * lcid [I] LCID for conversion
2242 * pi64Out [O] Destination
2246 * Failure: E_INVALIDARG, if the source value is invalid
2247 * DISP_E_OVERFLOW, if the value will not fit in the destination
2248 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2250 HRESULT WINAPI
VarI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, LONG64
* pi64Out
)
2252 return VARIANT_FromDisp(pdispIn
, lcid
, pi64Out
, VT_I8
, 0);
2255 /************************************************************************
2256 * VarI8FromBool (OLEAUT32.341)
2258 * Convert a VT_BOOL to a VT_I8.
2262 * pi64Out [O] Destination
2267 HRESULT WINAPI
VarI8FromBool(VARIANT_BOOL boolIn
, LONG64
* pi64Out
)
2269 return VarI8FromI2(boolIn
, pi64Out
);
2272 /************************************************************************
2273 * VarI8FromI1 (OLEAUT32.342)
2275 * Convert a VT_I1 to a VT_I8.
2279 * pi64Out [O] Destination
2284 HRESULT WINAPI
VarI8FromI1(signed char cIn
, LONG64
* pi64Out
)
2286 return _VarI8FromI1(cIn
, pi64Out
);
2289 /************************************************************************
2290 * VarI8FromUI2 (OLEAUT32.343)
2292 * Convert a VT_UI2 to a VT_I8.
2296 * pi64Out [O] Destination
2301 HRESULT WINAPI
VarI8FromUI2(USHORT usIn
, LONG64
* pi64Out
)
2303 return _VarI8FromUI2(usIn
, pi64Out
);
2306 /************************************************************************
2307 * VarI8FromUI4 (OLEAUT32.344)
2309 * Convert a VT_UI4 to a VT_I8.
2313 * pi64Out [O] Destination
2318 HRESULT WINAPI
VarI8FromUI4(ULONG ulIn
, LONG64
* pi64Out
)
2320 return _VarI8FromUI4(ulIn
, pi64Out
);
2323 /************************************************************************
2324 * VarI8FromDec (OLEAUT32.345)
2326 * Convert a VT_DECIMAL to a VT_I8.
2330 * pi64Out [O] Destination
2334 * Failure: E_INVALIDARG, if the source value is invalid
2335 * DISP_E_OVERFLOW, if the value will not fit in the destination
2337 HRESULT WINAPI
VarI8FromDec(DECIMAL
*pdecIn
, LONG64
* pi64Out
)
2339 if (!DEC_SCALE(pdecIn
))
2341 /* This decimal is just a 96 bit integer */
2342 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2343 return E_INVALIDARG
;
2345 if (DEC_HI32(pdecIn
) || DEC_MID32(pdecIn
) & 0x80000000)
2346 return DISP_E_OVERFLOW
;
2348 if (DEC_SIGN(pdecIn
))
2349 *pi64Out
= -DEC_LO64(pdecIn
);
2351 *pi64Out
= DEC_LO64(pdecIn
);
2356 /* Decimal contains a floating point number */
2360 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2361 if (SUCCEEDED(hRet
))
2362 hRet
= VarI8FromR8(dbl
, pi64Out
);
2367 /************************************************************************
2368 * VarI8FromUI8 (OLEAUT32.427)
2370 * Convert a VT_UI8 to a VT_I8.
2374 * pi64Out [O] Destination
2378 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2380 HRESULT WINAPI
VarI8FromUI8(ULONG64 ullIn
, LONG64
* pi64Out
)
2382 return _VarI8FromUI8(ullIn
, pi64Out
);
2388 /************************************************************************
2389 * VarUI8FromI8 (OLEAUT32.428)
2391 * Convert a VT_I8 to a VT_UI8.
2395 * pui64Out [O] Destination
2399 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2401 HRESULT WINAPI
VarUI8FromI8(LONG64 llIn
, ULONG64
* pui64Out
)
2403 return _VarUI8FromI8(llIn
, pui64Out
);
2406 /************************************************************************
2407 * VarUI8FromUI1 (OLEAUT32.429)
2409 * Convert a VT_UI1 to a VT_UI8.
2413 * pui64Out [O] Destination
2418 HRESULT WINAPI
VarUI8FromUI1(BYTE bIn
, ULONG64
* pui64Out
)
2420 return _VarUI8FromUI1(bIn
, pui64Out
);
2423 /************************************************************************
2424 * VarUI8FromI2 (OLEAUT32.430)
2426 * Convert a VT_I2 to a VT_UI8.
2430 * pui64Out [O] Destination
2435 HRESULT WINAPI
VarUI8FromI2(SHORT sIn
, ULONG64
* pui64Out
)
2437 return _VarUI8FromI2(sIn
, pui64Out
);
2440 /************************************************************************
2441 * VarUI8FromR4 (OLEAUT32.431)
2443 * Convert a VT_R4 to a VT_UI8.
2447 * pui64Out [O] Destination
2451 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2453 HRESULT WINAPI
VarUI8FromR4(FLOAT fltIn
, ULONG64
* pui64Out
)
2455 return VarUI8FromR8(fltIn
, pui64Out
);
2458 /************************************************************************
2459 * VarUI8FromR8 (OLEAUT32.432)
2461 * Convert a VT_R8 to a VT_UI8.
2465 * pui64Out [O] Destination
2469 * Failure: E_INVALIDARG, if the source value is invalid
2470 * DISP_E_OVERFLOW, if the value will not fit in the destination
2473 * See VarI8FromR8() for details concerning rounding.
2475 HRESULT WINAPI
VarUI8FromR8(double dblIn
, ULONG64
* pui64Out
)
2477 if (dblIn
< -0.5 || dblIn
> 1.844674407370955e19
)
2478 return DISP_E_OVERFLOW
;
2479 VARIANT_DutchRound(ULONG64
, dblIn
, *pui64Out
);
2483 /************************************************************************
2484 * VarUI8FromCy (OLEAUT32.433)
2486 * Convert a VT_CY to a VT_UI8.
2490 * pui64Out [O] Destination
2494 * Failure: E_INVALIDARG, if the source value is invalid
2495 * DISP_E_OVERFLOW, if the value will not fit in the destination
2498 * Negative values >= -5000 will be converted to 0.
2500 HRESULT WINAPI
VarUI8FromCy(CY cyIn
, ULONG64
* pui64Out
)
2504 if (cyIn
.int64
< -CY_HALF
)
2505 return DISP_E_OVERFLOW
;
2510 *pui64Out
= cyIn
.int64
/ CY_MULTIPLIER
;
2512 cyIn
.int64
-= *pui64Out
* CY_MULTIPLIER
; /* cyIn.s.Lo now holds fractional remainder */
2514 if (cyIn
.s
.Lo
> CY_HALF
|| (cyIn
.s
.Lo
== CY_HALF
&& (*pui64Out
& 0x1)))
2520 /************************************************************************
2521 * VarUI8FromDate (OLEAUT32.434)
2523 * Convert a VT_DATE to a VT_UI8.
2527 * pui64Out [O] Destination
2531 * Failure: E_INVALIDARG, if the source value is invalid
2532 * DISP_E_OVERFLOW, if the value will not fit in the destination
2533 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2535 HRESULT WINAPI
VarUI8FromDate(DATE dateIn
, ULONG64
* pui64Out
)
2537 return VarUI8FromR8(dateIn
, pui64Out
);
2540 /************************************************************************
2541 * VarUI8FromStr (OLEAUT32.435)
2543 * Convert a VT_BSTR to a VT_UI8.
2547 * lcid [I] LCID for the conversion
2548 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2549 * pui64Out [O] Destination
2553 * Failure: E_INVALIDARG, if the source value is invalid
2554 * DISP_E_OVERFLOW, if the value will not fit in the destination
2555 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2557 HRESULT WINAPI
VarUI8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG64
* pui64Out
)
2559 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pui64Out
, VT_UI8
);
2562 /************************************************************************
2563 * VarUI8FromDisp (OLEAUT32.436)
2565 * Convert a VT_DISPATCH to a VT_UI8.
2568 * pdispIn [I] Source
2569 * lcid [I] LCID for conversion
2570 * pui64Out [O] Destination
2574 * Failure: E_INVALIDARG, if the source value is invalid
2575 * DISP_E_OVERFLOW, if the value will not fit in the destination
2576 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2578 HRESULT WINAPI
VarUI8FromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG64
* pui64Out
)
2580 return VARIANT_FromDisp(pdispIn
, lcid
, pui64Out
, VT_UI8
, 0);
2583 /************************************************************************
2584 * VarUI8FromBool (OLEAUT32.437)
2586 * Convert a VT_BOOL to a VT_UI8.
2590 * pui64Out [O] Destination
2594 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2596 HRESULT WINAPI
VarUI8FromBool(VARIANT_BOOL boolIn
, ULONG64
* pui64Out
)
2598 return VarI8FromI2(boolIn
, (LONG64
*)pui64Out
);
2600 /************************************************************************
2601 * VarUI8FromI1 (OLEAUT32.438)
2603 * Convert a VT_I1 to a VT_UI8.
2607 * pui64Out [O] Destination
2611 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2613 HRESULT WINAPI
VarUI8FromI1(signed char cIn
, ULONG64
* pui64Out
)
2615 return _VarUI8FromI1(cIn
, pui64Out
);
2618 /************************************************************************
2619 * VarUI8FromUI2 (OLEAUT32.439)
2621 * Convert a VT_UI2 to a VT_UI8.
2625 * pui64Out [O] Destination
2630 HRESULT WINAPI
VarUI8FromUI2(USHORT usIn
, ULONG64
* pui64Out
)
2632 return _VarUI8FromUI2(usIn
, pui64Out
);
2635 /************************************************************************
2636 * VarUI8FromUI4 (OLEAUT32.440)
2638 * Convert a VT_UI4 to a VT_UI8.
2642 * pui64Out [O] Destination
2647 HRESULT WINAPI
VarUI8FromUI4(ULONG ulIn
, ULONG64
* pui64Out
)
2649 return _VarUI8FromUI4(ulIn
, pui64Out
);
2652 /************************************************************************
2653 * VarUI8FromDec (OLEAUT32.441)
2655 * Convert a VT_DECIMAL to a VT_UI8.
2659 * pui64Out [O] Destination
2663 * Failure: E_INVALIDARG, if the source value is invalid
2664 * DISP_E_OVERFLOW, if the value will not fit in the destination
2667 * Under native Win32, if the source value has a scale of 0, its sign is
2668 * ignored, i.e. this function takes the absolute value rather than fail
2669 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2670 * (use VarAbs() on pDecIn first if you really want this behaviour).
2672 HRESULT WINAPI
VarUI8FromDec(DECIMAL
*pdecIn
, ULONG64
* pui64Out
)
2674 if (!DEC_SCALE(pdecIn
))
2676 /* This decimal is just a 96 bit integer */
2677 if (DEC_SIGN(pdecIn
) & ~DECIMAL_NEG
)
2678 return E_INVALIDARG
;
2680 if (DEC_HI32(pdecIn
))
2681 return DISP_E_OVERFLOW
;
2683 if (DEC_SIGN(pdecIn
))
2685 WARN("Sign would be ignored under Win32!\n");
2686 return DISP_E_OVERFLOW
;
2689 *pui64Out
= DEC_LO64(pdecIn
);
2694 /* Decimal contains a floating point number */
2698 hRet
= VarR8FromDec(pdecIn
, &dbl
);
2699 if (SUCCEEDED(hRet
))
2700 hRet
= VarUI8FromR8(dbl
, pui64Out
);
2708 /************************************************************************
2709 * VarR4FromUI1 (OLEAUT32.68)
2711 * Convert a VT_UI1 to a VT_R4.
2715 * pFltOut [O] Destination
2720 HRESULT WINAPI
VarR4FromUI1(BYTE bIn
, float *pFltOut
)
2722 return _VarR4FromUI1(bIn
, pFltOut
);
2725 /************************************************************************
2726 * VarR4FromI2 (OLEAUT32.69)
2728 * Convert a VT_I2 to a VT_R4.
2732 * pFltOut [O] Destination
2737 HRESULT WINAPI
VarR4FromI2(SHORT sIn
, float *pFltOut
)
2739 return _VarR4FromI2(sIn
, pFltOut
);
2742 /************************************************************************
2743 * VarR4FromI4 (OLEAUT32.70)
2745 * Convert a VT_I4 to a VT_R4.
2749 * pFltOut [O] Destination
2754 HRESULT WINAPI
VarR4FromI4(LONG lIn
, float *pFltOut
)
2756 return _VarR4FromI4(lIn
, pFltOut
);
2759 /************************************************************************
2760 * VarR4FromR8 (OLEAUT32.71)
2762 * Convert a VT_R8 to a VT_R4.
2766 * pFltOut [O] Destination
2770 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2772 HRESULT WINAPI
VarR4FromR8(double dblIn
, float *pFltOut
)
2774 double d
= dblIn
< 0.0 ? -dblIn
: dblIn
;
2775 if (d
> R4_MAX
) return DISP_E_OVERFLOW
;
2780 /************************************************************************
2781 * VarR4FromCy (OLEAUT32.72)
2783 * Convert a VT_CY to a VT_R4.
2787 * pFltOut [O] Destination
2792 HRESULT WINAPI
VarR4FromCy(CY cyIn
, float *pFltOut
)
2794 *pFltOut
= (double)cyIn
.int64
/ CY_MULTIPLIER_F
;
2798 /************************************************************************
2799 * VarR4FromDate (OLEAUT32.73)
2801 * Convert a VT_DATE to a VT_R4.
2805 * pFltOut [O] Destination
2809 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2811 HRESULT WINAPI
VarR4FromDate(DATE dateIn
, float *pFltOut
)
2813 return VarR4FromR8(dateIn
, pFltOut
);
2816 /************************************************************************
2817 * VarR4FromStr (OLEAUT32.74)
2819 * Convert a VT_BSTR to a VT_R4.
2823 * lcid [I] LCID for the conversion
2824 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2825 * pFltOut [O] Destination
2829 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2830 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2832 HRESULT WINAPI
VarR4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, float *pFltOut
)
2834 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pFltOut
, VT_R4
);
2837 /************************************************************************
2838 * VarR4FromDisp (OLEAUT32.75)
2840 * Convert a VT_DISPATCH to a VT_R4.
2843 * pdispIn [I] Source
2844 * lcid [I] LCID for conversion
2845 * pFltOut [O] Destination
2849 * Failure: E_INVALIDARG, if the source value is invalid
2850 * DISP_E_OVERFLOW, if the value will not fit in the destination
2851 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2853 HRESULT WINAPI
VarR4FromDisp(IDispatch
* pdispIn
, LCID lcid
, float *pFltOut
)
2855 return VARIANT_FromDisp(pdispIn
, lcid
, pFltOut
, VT_R4
, 0);
2858 /************************************************************************
2859 * VarR4FromBool (OLEAUT32.76)
2861 * Convert a VT_BOOL to a VT_R4.
2865 * pFltOut [O] Destination
2870 HRESULT WINAPI
VarR4FromBool(VARIANT_BOOL boolIn
, float *pFltOut
)
2872 return VarR4FromI2(boolIn
, pFltOut
);
2875 /************************************************************************
2876 * VarR4FromI1 (OLEAUT32.213)
2878 * Convert a VT_I1 to a VT_R4.
2882 * pFltOut [O] Destination
2886 * Failure: E_INVALIDARG, if the source value is invalid
2887 * DISP_E_OVERFLOW, if the value will not fit in the destination
2888 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2890 HRESULT WINAPI
VarR4FromI1(signed char cIn
, float *pFltOut
)
2892 return _VarR4FromI1(cIn
, pFltOut
);
2895 /************************************************************************
2896 * VarR4FromUI2 (OLEAUT32.214)
2898 * Convert a VT_UI2 to a VT_R4.
2902 * pFltOut [O] Destination
2906 * Failure: E_INVALIDARG, if the source value is invalid
2907 * DISP_E_OVERFLOW, if the value will not fit in the destination
2908 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2910 HRESULT WINAPI
VarR4FromUI2(USHORT usIn
, float *pFltOut
)
2912 return _VarR4FromUI2(usIn
, pFltOut
);
2915 /************************************************************************
2916 * VarR4FromUI4 (OLEAUT32.215)
2918 * Convert a VT_UI4 to a VT_R4.
2922 * pFltOut [O] Destination
2926 * Failure: E_INVALIDARG, if the source value is invalid
2927 * DISP_E_OVERFLOW, if the value will not fit in the destination
2928 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2930 HRESULT WINAPI
VarR4FromUI4(ULONG ulIn
, float *pFltOut
)
2932 return _VarR4FromUI4(ulIn
, pFltOut
);
2935 /************************************************************************
2936 * VarR4FromDec (OLEAUT32.216)
2938 * Convert a VT_DECIMAL to a VT_R4.
2942 * pFltOut [O] Destination
2946 * Failure: E_INVALIDARG, if the source value is invalid.
2948 HRESULT WINAPI
VarR4FromDec(DECIMAL
* pDecIn
, float *pFltOut
)
2950 BYTE scale
= DEC_SCALE(pDecIn
);
2951 double divisor
= 1.0;
2954 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
2955 return E_INVALIDARG
;
2960 if (DEC_SIGN(pDecIn
))
2963 if (DEC_HI32(pDecIn
))
2965 highPart
= (double)DEC_HI32(pDecIn
) / divisor
;
2966 highPart
*= 4294967296.0F
;
2967 highPart
*= 4294967296.0F
;
2972 *pFltOut
= (double)DEC_LO64(pDecIn
) / divisor
+ highPart
;
2976 /************************************************************************
2977 * VarR4FromI8 (OLEAUT32.360)
2979 * Convert a VT_I8 to a VT_R4.
2983 * pFltOut [O] Destination
2988 HRESULT WINAPI
VarR4FromI8(LONG64 llIn
, float *pFltOut
)
2990 return _VarR4FromI8(llIn
, pFltOut
);
2993 /************************************************************************
2994 * VarR4FromUI8 (OLEAUT32.361)
2996 * Convert a VT_UI8 to a VT_R4.
3000 * pFltOut [O] Destination
3005 HRESULT WINAPI
VarR4FromUI8(ULONG64 ullIn
, float *pFltOut
)
3007 return _VarR4FromUI8(ullIn
, pFltOut
);
3010 /************************************************************************
3011 * VarR4CmpR8 (OLEAUT32.316)
3013 * Compare a VT_R4 to a VT_R8.
3016 * fltLeft [I] Source
3017 * dblRight [I] Value to compare
3020 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3021 * equal to or greater than dblRight respectively.
3023 HRESULT WINAPI
VarR4CmpR8(float fltLeft
, double dblRight
)
3025 if (fltLeft
< dblRight
)
3027 else if (fltLeft
> dblRight
)
3035 /************************************************************************
3036 * VarR8FromUI1 (OLEAUT32.78)
3038 * Convert a VT_UI1 to a VT_R8.
3042 * pDblOut [O] Destination
3047 HRESULT WINAPI
VarR8FromUI1(BYTE bIn
, double *pDblOut
)
3049 return _VarR8FromUI1(bIn
, pDblOut
);
3052 /************************************************************************
3053 * VarR8FromI2 (OLEAUT32.79)
3055 * Convert a VT_I2 to a VT_R8.
3059 * pDblOut [O] Destination
3064 HRESULT WINAPI
VarR8FromI2(SHORT sIn
, double *pDblOut
)
3066 return _VarR8FromI2(sIn
, pDblOut
);
3069 /************************************************************************
3070 * VarR8FromI4 (OLEAUT32.80)
3072 * Convert a VT_I4 to a VT_R8.
3076 * pDblOut [O] Destination
3081 HRESULT WINAPI
VarR8FromI4(LONG lIn
, double *pDblOut
)
3083 return _VarR8FromI4(lIn
, pDblOut
);
3086 /************************************************************************
3087 * VarR8FromR4 (OLEAUT32.81)
3089 * Convert a VT_R4 to a VT_R8.
3093 * pDblOut [O] Destination
3098 HRESULT WINAPI
VarR8FromR4(FLOAT fltIn
, double *pDblOut
)
3100 return _VarR8FromR4(fltIn
, pDblOut
);
3103 /************************************************************************
3104 * VarR8FromCy (OLEAUT32.82)
3106 * Convert a VT_CY to a VT_R8.
3110 * pDblOut [O] Destination
3115 HRESULT WINAPI
VarR8FromCy(CY cyIn
, double *pDblOut
)
3117 return _VarR8FromCy(cyIn
, pDblOut
);
3120 /************************************************************************
3121 * VarR8FromDate (OLEAUT32.83)
3123 * Convert a VT_DATE to a VT_R8.
3127 * pDblOut [O] Destination
3132 HRESULT WINAPI
VarR8FromDate(DATE dateIn
, double *pDblOut
)
3134 return _VarR8FromDate(dateIn
, pDblOut
);
3137 /************************************************************************
3138 * VarR8FromStr (OLEAUT32.84)
3140 * Convert a VT_BSTR to a VT_R8.
3144 * lcid [I] LCID for the conversion
3145 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3146 * pDblOut [O] Destination
3150 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3151 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3153 HRESULT WINAPI
VarR8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, double *pDblOut
)
3155 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDblOut
, VT_R8
);
3158 /************************************************************************
3159 * VarR8FromDisp (OLEAUT32.85)
3161 * Convert a VT_DISPATCH to a VT_R8.
3164 * pdispIn [I] Source
3165 * lcid [I] LCID for conversion
3166 * pDblOut [O] Destination
3170 * Failure: E_INVALIDARG, if the source value is invalid
3171 * DISP_E_OVERFLOW, if the value will not fit in the destination
3172 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3174 HRESULT WINAPI
VarR8FromDisp(IDispatch
* pdispIn
, LCID lcid
, double *pDblOut
)
3176 return VARIANT_FromDisp(pdispIn
, lcid
, pDblOut
, VT_R8
, 0);
3179 /************************************************************************
3180 * VarR8FromBool (OLEAUT32.86)
3182 * Convert a VT_BOOL to a VT_R8.
3186 * pDblOut [O] Destination
3191 HRESULT WINAPI
VarR8FromBool(VARIANT_BOOL boolIn
, double *pDblOut
)
3193 return VarR8FromI2(boolIn
, pDblOut
);
3196 /************************************************************************
3197 * VarR8FromI1 (OLEAUT32.217)
3199 * Convert a VT_I1 to a VT_R8.
3203 * pDblOut [O] Destination
3207 * Failure: E_INVALIDARG, if the source value is invalid
3208 * DISP_E_OVERFLOW, if the value will not fit in the destination
3209 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3211 HRESULT WINAPI
VarR8FromI1(signed char cIn
, double *pDblOut
)
3213 return _VarR8FromI1(cIn
, pDblOut
);
3216 /************************************************************************
3217 * VarR8FromUI2 (OLEAUT32.218)
3219 * Convert a VT_UI2 to a VT_R8.
3223 * pDblOut [O] Destination
3227 * Failure: E_INVALIDARG, if the source value is invalid
3228 * DISP_E_OVERFLOW, if the value will not fit in the destination
3229 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3231 HRESULT WINAPI
VarR8FromUI2(USHORT usIn
, double *pDblOut
)
3233 return _VarR8FromUI2(usIn
, pDblOut
);
3236 /************************************************************************
3237 * VarR8FromUI4 (OLEAUT32.219)
3239 * Convert a VT_UI4 to a VT_R8.
3243 * pDblOut [O] Destination
3247 * Failure: E_INVALIDARG, if the source value is invalid
3248 * DISP_E_OVERFLOW, if the value will not fit in the destination
3249 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3251 HRESULT WINAPI
VarR8FromUI4(ULONG ulIn
, double *pDblOut
)
3253 return _VarR8FromUI4(ulIn
, pDblOut
);
3256 /************************************************************************
3257 * VarR8FromDec (OLEAUT32.220)
3259 * Convert a VT_DECIMAL to a VT_R8.
3263 * pDblOut [O] Destination
3267 * Failure: E_INVALIDARG, if the source value is invalid.
3269 HRESULT WINAPI
VarR8FromDec(const DECIMAL
* pDecIn
, double *pDblOut
)
3271 BYTE scale
= DEC_SCALE(pDecIn
);
3272 double divisor
= 1.0, highPart
;
3274 if (scale
> DEC_MAX_SCALE
|| DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
3275 return E_INVALIDARG
;
3280 if (DEC_SIGN(pDecIn
))
3283 if (DEC_HI32(pDecIn
))
3285 highPart
= (double)DEC_HI32(pDecIn
) / divisor
;
3286 highPart
*= 4294967296.0F
;
3287 highPart
*= 4294967296.0F
;
3292 *pDblOut
= (double)DEC_LO64(pDecIn
) / divisor
+ highPart
;
3296 /************************************************************************
3297 * VarR8FromI8 (OLEAUT32.362)
3299 * Convert a VT_I8 to a VT_R8.
3303 * pDblOut [O] Destination
3308 HRESULT WINAPI
VarR8FromI8(LONG64 llIn
, double *pDblOut
)
3310 return _VarR8FromI8(llIn
, pDblOut
);
3313 /************************************************************************
3314 * VarR8FromUI8 (OLEAUT32.363)
3316 * Convert a VT_UI8 to a VT_R8.
3320 * pDblOut [O] Destination
3325 HRESULT WINAPI
VarR8FromUI8(ULONG64 ullIn
, double *pDblOut
)
3327 return _VarR8FromUI8(ullIn
, pDblOut
);
3330 /************************************************************************
3331 * VarR8Pow (OLEAUT32.315)
3333 * Raise a VT_R8 to a power.
3336 * dblLeft [I] Source
3337 * dblPow [I] Power to raise dblLeft by
3338 * pDblOut [O] Destination
3341 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3343 HRESULT WINAPI
VarR8Pow(double dblLeft
, double dblPow
, double *pDblOut
)
3345 *pDblOut
= pow(dblLeft
, dblPow
);
3349 /************************************************************************
3350 * VarR8Round (OLEAUT32.317)
3352 * Round a VT_R8 to a given number of decimal points.
3356 * nDig [I] Number of decimal points to round to
3357 * pDblOut [O] Destination for rounded number
3360 * Success: S_OK. pDblOut is rounded to nDig digits.
3361 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3364 * The native version of this function rounds using the internal
3365 * binary representation of the number. Wine uses the dutch rounding
3366 * convention, so therefore small differences can occur in the value returned.
3367 * MSDN says that you should use your own rounding function if you want
3368 * rounding to be predictable in your application.
3370 HRESULT WINAPI
VarR8Round(double dblIn
, int nDig
, double *pDblOut
)
3372 double scale
, whole
, fract
;
3375 return E_INVALIDARG
;
3377 scale
= pow(10.0, nDig
);
3380 whole
= dblIn
< 0 ? ceil(dblIn
) : floor(dblIn
);
3381 fract
= dblIn
- whole
;
3384 dblIn
= whole
+ 1.0;
3385 else if (fract
== 0.5)
3386 dblIn
= whole
+ fmod(whole
, 2.0);
3387 else if (fract
>= 0.0)
3389 else if (fract
== -0.5)
3390 dblIn
= whole
- fmod(whole
, 2.0);
3391 else if (fract
> -0.5)
3394 dblIn
= whole
- 1.0;
3396 *pDblOut
= dblIn
/ scale
;
3403 /* Powers of 10 from 0..4 D.P. */
3404 static const int CY_Divisors
[5] = { CY_MULTIPLIER
/10000, CY_MULTIPLIER
/1000,
3405 CY_MULTIPLIER
/100, CY_MULTIPLIER
/10, CY_MULTIPLIER
};
3407 /************************************************************************
3408 * VarCyFromUI1 (OLEAUT32.98)
3410 * Convert a VT_UI1 to a VT_CY.
3414 * pCyOut [O] Destination
3418 * Failure: E_INVALIDARG, if the source value is invalid
3419 * DISP_E_OVERFLOW, if the value will not fit in the destination
3420 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3422 HRESULT WINAPI
VarCyFromUI1(BYTE bIn
, CY
* pCyOut
)
3424 pCyOut
->int64
= (ULONG64
)bIn
* CY_MULTIPLIER
;
3428 /************************************************************************
3429 * VarCyFromI2 (OLEAUT32.99)
3431 * Convert a VT_I2 to a VT_CY.
3435 * pCyOut [O] Destination
3439 * Failure: E_INVALIDARG, if the source value is invalid
3440 * DISP_E_OVERFLOW, if the value will not fit in the destination
3441 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3443 HRESULT WINAPI
VarCyFromI2(SHORT sIn
, CY
* pCyOut
)
3445 pCyOut
->int64
= (LONG64
)sIn
* CY_MULTIPLIER
;
3449 /************************************************************************
3450 * VarCyFromI4 (OLEAUT32.100)
3452 * Convert a VT_I4 to a VT_CY.
3456 * pCyOut [O] Destination
3460 * Failure: E_INVALIDARG, if the source value is invalid
3461 * DISP_E_OVERFLOW, if the value will not fit in the destination
3462 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3464 HRESULT WINAPI
VarCyFromI4(LONG lIn
, CY
* pCyOut
)
3466 pCyOut
->int64
= (LONG64
)lIn
* CY_MULTIPLIER
;
3470 /************************************************************************
3471 * VarCyFromR4 (OLEAUT32.101)
3473 * Convert a VT_R4 to a VT_CY.
3477 * pCyOut [O] Destination
3481 * Failure: E_INVALIDARG, if the source value is invalid
3482 * DISP_E_OVERFLOW, if the value will not fit in the destination
3483 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3485 HRESULT WINAPI
VarCyFromR4(FLOAT fltIn
, CY
* pCyOut
)
3487 return VarCyFromR8(fltIn
, pCyOut
);
3490 /************************************************************************
3491 * VarCyFromR8 (OLEAUT32.102)
3493 * Convert a VT_R8 to a VT_CY.
3497 * pCyOut [O] Destination
3501 * Failure: E_INVALIDARG, if the source value is invalid
3502 * DISP_E_OVERFLOW, if the value will not fit in the destination
3503 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3505 HRESULT WINAPI
VarCyFromR8(double dblIn
, CY
* pCyOut
)
3507 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3508 /* This code gives identical results to Win32 on Intel.
3509 * Here we use fp exceptions to catch overflows when storing the value.
3511 static const unsigned short r8_fpcontrol
= 0x137f;
3512 static const double r8_multiplier
= CY_MULTIPLIER_F
;
3513 unsigned short old_fpcontrol
, result_fpstatus
;
3515 /* Clear exceptions, save the old fp state and load the new state */
3516 __asm__
__volatile__( "fnclex" );
3517 __asm__
__volatile__( "fstcw %0" : "=m" (old_fpcontrol
) : );
3518 __asm__
__volatile__( "fldcw %0" : : "m" (r8_fpcontrol
) );
3519 /* Perform the conversion. */
3520 __asm__
__volatile__( "fldl %0" : : "m" (dblIn
) );
3521 __asm__
__volatile__( "fmull %0" : : "m" (r8_multiplier
) );
3522 __asm__
__volatile__( "fistpll %0" : : "m" (*pCyOut
) );
3523 /* Save the resulting fp state, load the old state and clear exceptions */
3524 __asm__
__volatile__( "fstsw %0" : "=m" (result_fpstatus
) : );
3525 __asm__
__volatile__( "fnclex" );
3526 __asm__
__volatile__( "fldcw %0" : : "m" (old_fpcontrol
) );
3528 if (result_fpstatus
& 0x9) /* Overflow | Invalid */
3529 return DISP_E_OVERFLOW
;
3531 /* This version produces slightly different results for boundary cases */
3532 if (dblIn
< -922337203685477.5807 || dblIn
>= 922337203685477.5807)
3533 return DISP_E_OVERFLOW
;
3534 dblIn
*= CY_MULTIPLIER_F
;
3535 VARIANT_DutchRound(LONG64
, dblIn
, pCyOut
->int64
);
3540 /************************************************************************
3541 * VarCyFromDate (OLEAUT32.103)
3543 * Convert a VT_DATE to a VT_CY.
3547 * pCyOut [O] Destination
3551 * Failure: E_INVALIDARG, if the source value is invalid
3552 * DISP_E_OVERFLOW, if the value will not fit in the destination
3553 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3555 HRESULT WINAPI
VarCyFromDate(DATE dateIn
, CY
* pCyOut
)
3557 return VarCyFromR8(dateIn
, pCyOut
);
3560 /************************************************************************
3561 * VarCyFromStr (OLEAUT32.104)
3563 * Convert a VT_BSTR to a VT_CY.
3567 * lcid [I] LCID for the conversion
3568 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3569 * pCyOut [O] Destination
3573 * Failure: E_INVALIDARG, if the source value is invalid
3574 * DISP_E_OVERFLOW, if the value will not fit in the destination
3575 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3577 HRESULT WINAPI
VarCyFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, CY
* pCyOut
)
3579 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pCyOut
, VT_CY
);
3582 /************************************************************************
3583 * VarCyFromDisp (OLEAUT32.105)
3585 * Convert a VT_DISPATCH to a VT_CY.
3588 * pdispIn [I] Source
3589 * lcid [I] LCID for conversion
3590 * pCyOut [O] Destination
3594 * Failure: E_INVALIDARG, if the source value is invalid
3595 * DISP_E_OVERFLOW, if the value will not fit in the destination
3596 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3598 HRESULT WINAPI
VarCyFromDisp(IDispatch
* pdispIn
, LCID lcid
, CY
* pCyOut
)
3600 return VARIANT_FromDisp(pdispIn
, lcid
, pCyOut
, VT_CY
, 0);
3603 /************************************************************************
3604 * VarCyFromBool (OLEAUT32.106)
3606 * Convert a VT_BOOL to a VT_CY.
3610 * pCyOut [O] Destination
3614 * Failure: E_INVALIDARG, if the source value is invalid
3615 * DISP_E_OVERFLOW, if the value will not fit in the destination
3616 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3619 * While the sign of the boolean is stored in the currency, the value is
3620 * converted to either 0 or 1.
3622 HRESULT WINAPI
VarCyFromBool(VARIANT_BOOL boolIn
, CY
* pCyOut
)
3624 pCyOut
->int64
= (LONG64
)boolIn
* CY_MULTIPLIER
;
3628 /************************************************************************
3629 * VarCyFromI1 (OLEAUT32.225)
3631 * Convert a VT_I1 to a VT_CY.
3635 * pCyOut [O] Destination
3639 * Failure: E_INVALIDARG, if the source value is invalid
3640 * DISP_E_OVERFLOW, if the value will not fit in the destination
3641 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3643 HRESULT WINAPI
VarCyFromI1(signed char cIn
, CY
* pCyOut
)
3645 pCyOut
->int64
= (LONG64
)cIn
* CY_MULTIPLIER
;
3649 /************************************************************************
3650 * VarCyFromUI2 (OLEAUT32.226)
3652 * Convert a VT_UI2 to a VT_CY.
3656 * pCyOut [O] Destination
3660 * Failure: E_INVALIDARG, if the source value is invalid
3661 * DISP_E_OVERFLOW, if the value will not fit in the destination
3662 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3664 HRESULT WINAPI
VarCyFromUI2(USHORT usIn
, CY
* pCyOut
)
3666 pCyOut
->int64
= (ULONG64
)usIn
* CY_MULTIPLIER
;
3670 /************************************************************************
3671 * VarCyFromUI4 (OLEAUT32.227)
3673 * Convert a VT_UI4 to a VT_CY.
3677 * pCyOut [O] Destination
3681 * Failure: E_INVALIDARG, if the source value is invalid
3682 * DISP_E_OVERFLOW, if the value will not fit in the destination
3683 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3685 HRESULT WINAPI
VarCyFromUI4(ULONG ulIn
, CY
* pCyOut
)
3687 pCyOut
->int64
= (ULONG64
)ulIn
* CY_MULTIPLIER
;
3691 /************************************************************************
3692 * VarCyFromDec (OLEAUT32.228)
3694 * Convert a VT_DECIMAL to a VT_CY.
3698 * pCyOut [O] Destination
3702 * Failure: E_INVALIDARG, if the source value is invalid
3703 * DISP_E_OVERFLOW, if the value will not fit in the destination
3704 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3706 HRESULT WINAPI
VarCyFromDec(DECIMAL
* pdecIn
, CY
* pCyOut
)
3711 hRet
= VarDecRound(pdecIn
, 4, &rounded
);
3713 if (SUCCEEDED(hRet
))
3717 if (DEC_HI32(&rounded
))
3718 return DISP_E_OVERFLOW
;
3720 /* Note: Without the casts this promotes to int64 which loses precision */
3721 d
= (double)DEC_LO64(&rounded
) / (double)CY_Divisors
[DEC_SCALE(&rounded
)];
3722 if (DEC_SIGN(&rounded
))
3724 return VarCyFromR8(d
, pCyOut
);
3729 /************************************************************************
3730 * VarCyFromI8 (OLEAUT32.366)
3732 * Convert a VT_I8 to a VT_CY.
3736 * pCyOut [O] Destination
3740 * Failure: E_INVALIDARG, if the source value is invalid
3741 * DISP_E_OVERFLOW, if the value will not fit in the destination
3742 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3744 HRESULT WINAPI
VarCyFromI8(LONG64 llIn
, CY
* pCyOut
)
3746 if (llIn
<= (I8_MIN
/CY_MULTIPLIER
) || llIn
>= (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3747 pCyOut
->int64
= llIn
* CY_MULTIPLIER
;
3751 /************************************************************************
3752 * VarCyFromUI8 (OLEAUT32.375)
3754 * Convert a VT_UI8 to a VT_CY.
3758 * pCyOut [O] Destination
3762 * Failure: E_INVALIDARG, if the source value is invalid
3763 * DISP_E_OVERFLOW, if the value will not fit in the destination
3764 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3766 HRESULT WINAPI
VarCyFromUI8(ULONG64 ullIn
, CY
* pCyOut
)
3768 if (ullIn
> (I8_MAX
/CY_MULTIPLIER
)) return DISP_E_OVERFLOW
;
3769 pCyOut
->int64
= ullIn
* CY_MULTIPLIER
;
3773 /************************************************************************
3774 * VarCyAdd (OLEAUT32.299)
3776 * Add one CY to another.
3780 * cyRight [I] Value to add
3781 * pCyOut [O] Destination
3785 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3787 HRESULT WINAPI
VarCyAdd(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3790 _VarR8FromCy(cyLeft
, &l
);
3791 _VarR8FromCy(cyRight
, &r
);
3793 return VarCyFromR8(l
, pCyOut
);
3796 /************************************************************************
3797 * VarCyMul (OLEAUT32.303)
3799 * Multiply one CY by another.
3803 * cyRight [I] Value to multiply by
3804 * pCyOut [O] Destination
3808 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3810 HRESULT WINAPI
VarCyMul(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3813 _VarR8FromCy(cyLeft
, &l
);
3814 _VarR8FromCy(cyRight
, &r
);
3816 return VarCyFromR8(l
, pCyOut
);
3819 /************************************************************************
3820 * VarCyMulI4 (OLEAUT32.304)
3822 * Multiply one CY by a VT_I4.
3826 * lRight [I] Value to multiply by
3827 * pCyOut [O] Destination
3831 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3833 HRESULT WINAPI
VarCyMulI4(const CY cyLeft
, LONG lRight
, CY
* pCyOut
)
3837 _VarR8FromCy(cyLeft
, &d
);
3839 return VarCyFromR8(d
, pCyOut
);
3842 /************************************************************************
3843 * VarCySub (OLEAUT32.305)
3845 * Subtract one CY from another.
3849 * cyRight [I] Value to subtract
3850 * pCyOut [O] Destination
3854 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3856 HRESULT WINAPI
VarCySub(const CY cyLeft
, const CY cyRight
, CY
* pCyOut
)
3859 _VarR8FromCy(cyLeft
, &l
);
3860 _VarR8FromCy(cyRight
, &r
);
3862 return VarCyFromR8(l
, pCyOut
);
3865 /************************************************************************
3866 * VarCyAbs (OLEAUT32.306)
3868 * Convert a VT_CY into its absolute value.
3872 * pCyOut [O] Destination
3875 * Success: S_OK. pCyOut contains the absolute value.
3876 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3878 HRESULT WINAPI
VarCyAbs(const CY cyIn
, CY
* pCyOut
)
3880 if (cyIn
.s
.Hi
== (int)0x80000000 && !cyIn
.s
.Lo
)
3881 return DISP_E_OVERFLOW
;
3883 pCyOut
->int64
= cyIn
.int64
< 0 ? -cyIn
.int64
: cyIn
.int64
;
3887 /************************************************************************
3888 * VarCyFix (OLEAUT32.307)
3890 * Return the integer part of a VT_CY.
3894 * pCyOut [O] Destination
3898 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3901 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3902 * negative numbers away from 0, while this function rounds them towards zero.
3904 HRESULT WINAPI
VarCyFix(const CY cyIn
, CY
* pCyOut
)
3906 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3907 pCyOut
->int64
*= CY_MULTIPLIER
;
3911 /************************************************************************
3912 * VarCyInt (OLEAUT32.308)
3914 * Return the integer part of a VT_CY.
3918 * pCyOut [O] Destination
3922 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3925 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3926 * negative numbers towards 0, while this function rounds them away from zero.
3928 HRESULT WINAPI
VarCyInt(const CY cyIn
, CY
* pCyOut
)
3930 pCyOut
->int64
= cyIn
.int64
/ CY_MULTIPLIER
;
3931 pCyOut
->int64
*= CY_MULTIPLIER
;
3933 if (cyIn
.int64
< 0 && cyIn
.int64
% CY_MULTIPLIER
!= 0)
3935 pCyOut
->int64
-= CY_MULTIPLIER
;
3940 /************************************************************************
3941 * VarCyNeg (OLEAUT32.309)
3943 * Change the sign of a VT_CY.
3947 * pCyOut [O] Destination
3951 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3953 HRESULT WINAPI
VarCyNeg(const CY cyIn
, CY
* pCyOut
)
3955 if (cyIn
.s
.Hi
== (int)0x80000000 && !cyIn
.s
.Lo
)
3956 return DISP_E_OVERFLOW
;
3958 pCyOut
->int64
= -cyIn
.int64
;
3962 /************************************************************************
3963 * VarCyRound (OLEAUT32.310)
3965 * Change the precision of a VT_CY.
3969 * cDecimals [I] New number of decimals to keep
3970 * pCyOut [O] Destination
3974 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3976 HRESULT WINAPI
VarCyRound(const CY cyIn
, int cDecimals
, CY
* pCyOut
)
3979 return E_INVALIDARG
;
3983 /* Rounding to more precision than we have */
3989 double d
, div
= CY_Divisors
[cDecimals
];
3991 _VarR8FromCy(cyIn
, &d
);
3993 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
3994 d
= (double)pCyOut
->int64
/ div
* CY_MULTIPLIER_F
;
3995 VARIANT_DutchRound(LONGLONG
, d
, pCyOut
->int64
);
4000 /************************************************************************
4001 * VarCyCmp (OLEAUT32.311)
4003 * Compare two VT_CY values.
4007 * cyRight [I] Value to compare
4010 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4011 * compare is less, equal or greater than source respectively.
4012 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4014 HRESULT WINAPI
VarCyCmp(const CY cyLeft
, const CY cyRight
)
4019 /* Subtract right from left, and compare the result to 0 */
4020 hRet
= VarCySub(cyLeft
, cyRight
, &result
);
4022 if (SUCCEEDED(hRet
))
4024 if (result
.int64
< 0)
4025 hRet
= (HRESULT
)VARCMP_LT
;
4026 else if (result
.int64
> 0)
4027 hRet
= (HRESULT
)VARCMP_GT
;
4029 hRet
= (HRESULT
)VARCMP_EQ
;
4034 /************************************************************************
4035 * VarCyCmpR8 (OLEAUT32.312)
4037 * Compare a VT_CY to a double
4040 * cyLeft [I] Currency Source
4041 * dblRight [I] double to compare to cyLeft
4044 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4045 * less than, equal to or greater than cyLeft respectively.
4046 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4048 HRESULT WINAPI
VarCyCmpR8(const CY cyLeft
, double dblRight
)
4053 hRet
= VarCyFromR8(dblRight
, &cyRight
);
4055 if (SUCCEEDED(hRet
))
4056 hRet
= VarCyCmp(cyLeft
, cyRight
);
4061 /************************************************************************
4062 * VarCyMulI8 (OLEAUT32.329)
4064 * Multiply a VT_CY by a VT_I8.
4068 * llRight [I] Value to multiply by
4069 * pCyOut [O] Destination
4073 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4075 HRESULT WINAPI
VarCyMulI8(const CY cyLeft
, LONG64 llRight
, CY
* pCyOut
)
4079 _VarR8FromCy(cyLeft
, &d
);
4080 d
= d
* (double)llRight
;
4081 return VarCyFromR8(d
, pCyOut
);
4087 /************************************************************************
4088 * VarDecFromUI1 (OLEAUT32.190)
4090 * Convert a VT_UI1 to a DECIMAL.
4094 * pDecOut [O] Destination
4099 HRESULT WINAPI
VarDecFromUI1(BYTE bIn
, DECIMAL
* pDecOut
)
4101 return VarDecFromUI4(bIn
, pDecOut
);
4104 /************************************************************************
4105 * VarDecFromI2 (OLEAUT32.191)
4107 * Convert a VT_I2 to a DECIMAL.
4111 * pDecOut [O] Destination
4116 HRESULT WINAPI
VarDecFromI2(SHORT sIn
, DECIMAL
* pDecOut
)
4118 return VarDecFromI4(sIn
, pDecOut
);
4121 /************************************************************************
4122 * VarDecFromI4 (OLEAUT32.192)
4124 * Convert a VT_I4 to a DECIMAL.
4128 * pDecOut [O] Destination
4133 HRESULT WINAPI
VarDecFromI4(LONG lIn
, DECIMAL
* pDecOut
)
4135 DEC_HI32(pDecOut
) = 0;
4136 DEC_MID32(pDecOut
) = 0;
4140 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4141 DEC_LO32(pDecOut
) = -lIn
;
4145 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4146 DEC_LO32(pDecOut
) = lIn
;
4151 /* internal representation of the value stored in a DECIMAL. The bytes are
4152 stored from LSB at index 0 to MSB at index 11
4154 typedef struct DECIMAL_internal
4156 DWORD bitsnum
[3]; /* 96 significant bits, unsigned */
4157 unsigned char scale
; /* number scaled * 10 ^ -(scale) */
4158 unsigned int sign
: 1; /* 0 - positive, 1 - negative */
4161 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
);
4162 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
);
4163 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
);
4164 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
);
4165 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
);
4166 static BOOL
VARIANT_int_iszero(const DWORD
* p
, unsigned int n
);
4168 /************************************************************************
4169 * VarDecFromR4 (OLEAUT32.193)
4171 * Convert a VT_R4 to a DECIMAL.
4175 * pDecOut [O] Destination
4180 HRESULT WINAPI
VarDecFromR4(FLOAT fltIn
, DECIMAL
* pDecOut
)
4185 hres
= VARIANT_DI_FromR4(fltIn
, &di
);
4186 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4190 /************************************************************************
4191 * VarDecFromR8 (OLEAUT32.194)
4193 * Convert a VT_R8 to a DECIMAL.
4197 * pDecOut [O] Destination
4202 HRESULT WINAPI
VarDecFromR8(double dblIn
, DECIMAL
* pDecOut
)
4207 hres
= VARIANT_DI_FromR8(dblIn
, &di
);
4208 if (hres
== S_OK
) VARIANT_DecFromDI(&di
, pDecOut
);
4212 /************************************************************************
4213 * VarDecFromDate (OLEAUT32.195)
4215 * Convert a VT_DATE to a DECIMAL.
4219 * pDecOut [O] Destination
4224 HRESULT WINAPI
VarDecFromDate(DATE dateIn
, DECIMAL
* pDecOut
)
4226 return VarDecFromR8(dateIn
, pDecOut
);
4229 /************************************************************************
4230 * VarDecFromCy (OLEAUT32.196)
4232 * Convert a VT_CY to a DECIMAL.
4236 * pDecOut [O] Destination
4241 HRESULT WINAPI
VarDecFromCy(CY cyIn
, DECIMAL
* pDecOut
)
4243 DEC_HI32(pDecOut
) = 0;
4245 /* Note: This assumes 2s complement integer representation */
4246 if (cyIn
.s
.Hi
& 0x80000000)
4248 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,4);
4249 DEC_LO64(pDecOut
) = -cyIn
.int64
;
4253 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,4);
4254 DEC_MID32(pDecOut
) = cyIn
.s
.Hi
;
4255 DEC_LO32(pDecOut
) = cyIn
.s
.Lo
;
4260 /************************************************************************
4261 * VarDecFromStr (OLEAUT32.197)
4263 * Convert a VT_BSTR to a DECIMAL.
4267 * lcid [I] LCID for the conversion
4268 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4269 * pDecOut [O] Destination
4273 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4275 HRESULT WINAPI
VarDecFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DECIMAL
* pDecOut
)
4277 return VARIANT_NumberFromBstr(strIn
, lcid
, dwFlags
, pDecOut
, VT_DECIMAL
);
4280 /************************************************************************
4281 * VarDecFromDisp (OLEAUT32.198)
4283 * Convert a VT_DISPATCH to a DECIMAL.
4286 * pdispIn [I] Source
4287 * lcid [I] LCID for conversion
4288 * pDecOut [O] Destination
4292 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4294 HRESULT WINAPI
VarDecFromDisp(IDispatch
* pdispIn
, LCID lcid
, DECIMAL
* pDecOut
)
4296 return VARIANT_FromDisp(pdispIn
, lcid
, pDecOut
, VT_DECIMAL
, 0);
4299 /************************************************************************
4300 * VarDecFromBool (OLEAUT32.199)
4302 * Convert a VT_BOOL to a DECIMAL.
4306 * pDecOut [O] Destination
4312 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4314 HRESULT WINAPI
VarDecFromBool(VARIANT_BOOL bIn
, DECIMAL
* pDecOut
)
4316 DEC_HI32(pDecOut
) = 0;
4317 DEC_MID32(pDecOut
) = 0;
4320 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4321 DEC_LO32(pDecOut
) = 1;
4325 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4326 DEC_LO32(pDecOut
) = 0;
4331 /************************************************************************
4332 * VarDecFromI1 (OLEAUT32.241)
4334 * Convert a VT_I1 to a DECIMAL.
4338 * pDecOut [O] Destination
4343 HRESULT WINAPI
VarDecFromI1(signed char cIn
, DECIMAL
* pDecOut
)
4345 return VarDecFromI4(cIn
, pDecOut
);
4348 /************************************************************************
4349 * VarDecFromUI2 (OLEAUT32.242)
4351 * Convert a VT_UI2 to a DECIMAL.
4355 * pDecOut [O] Destination
4360 HRESULT WINAPI
VarDecFromUI2(USHORT usIn
, DECIMAL
* pDecOut
)
4362 return VarDecFromUI4(usIn
, pDecOut
);
4365 /************************************************************************
4366 * VarDecFromUI4 (OLEAUT32.243)
4368 * Convert a VT_UI4 to a DECIMAL.
4372 * pDecOut [O] Destination
4377 HRESULT WINAPI
VarDecFromUI4(ULONG ulIn
, DECIMAL
* pDecOut
)
4379 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4380 DEC_HI32(pDecOut
) = 0;
4381 DEC_MID32(pDecOut
) = 0;
4382 DEC_LO32(pDecOut
) = ulIn
;
4386 /************************************************************************
4387 * VarDecFromI8 (OLEAUT32.374)
4389 * Convert a VT_I8 to a DECIMAL.
4393 * pDecOut [O] Destination
4398 HRESULT WINAPI
VarDecFromI8(LONG64 llIn
, DECIMAL
* pDecOut
)
4400 PULARGE_INTEGER pLi
= (PULARGE_INTEGER
)&llIn
;
4402 DEC_HI32(pDecOut
) = 0;
4404 /* Note: This assumes 2s complement integer representation */
4405 if (pLi
->u
.HighPart
& 0x80000000)
4407 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_NEG
,0);
4408 DEC_LO64(pDecOut
) = -pLi
->QuadPart
;
4412 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4413 DEC_MID32(pDecOut
) = pLi
->u
.HighPart
;
4414 DEC_LO32(pDecOut
) = pLi
->u
.LowPart
;
4419 /************************************************************************
4420 * VarDecFromUI8 (OLEAUT32.375)
4422 * Convert a VT_UI8 to a DECIMAL.
4426 * pDecOut [O] Destination
4431 HRESULT WINAPI
VarDecFromUI8(ULONG64 ullIn
, DECIMAL
* pDecOut
)
4433 DEC_SIGNSCALE(pDecOut
) = SIGNSCALE(DECIMAL_POS
,0);
4434 DEC_HI32(pDecOut
) = 0;
4435 DEC_LO64(pDecOut
) = ullIn
;
4439 /* Make two DECIMALS the same scale; used by math functions below */
4440 static HRESULT
VARIANT_DecScale(const DECIMAL
** ppDecLeft
,
4441 const DECIMAL
** ppDecRight
,
4444 static DECIMAL scaleFactor
;
4445 unsigned char remainder
;
4450 if (DEC_SIGN(*ppDecLeft
) & ~DECIMAL_NEG
|| DEC_SIGN(*ppDecRight
) & ~DECIMAL_NEG
)
4451 return E_INVALIDARG
;
4453 DEC_LO32(&scaleFactor
) = 10;
4455 i
= scaleAmount
= DEC_SCALE(*ppDecLeft
) - DEC_SCALE(*ppDecRight
);
4458 return S_OK
; /* Same scale */
4460 if (scaleAmount
> 0)
4462 decTemp
= *(*ppDecRight
); /* Left is bigger - scale the right hand side */
4463 *ppDecRight
= &pDecOut
[0];
4467 decTemp
= *(*ppDecLeft
); /* Right is bigger - scale the left hand side */
4468 *ppDecLeft
= &pDecOut
[0];
4472 /* Multiply up the value to be scaled by the correct amount (if possible) */
4473 while (i
> 0 && SUCCEEDED(VarDecMul(&decTemp
, &scaleFactor
, &pDecOut
[0])))
4475 decTemp
= pDecOut
[0];
4481 DEC_SCALE(&pDecOut
[0]) += (scaleAmount
> 0) ? scaleAmount
: (-scaleAmount
);
4482 return S_OK
; /* Same scale */
4485 /* Scaling further not possible, reduce accuracy of other argument */
4486 pDecOut
[0] = decTemp
;
4487 if (scaleAmount
> 0)
4489 DEC_SCALE(&pDecOut
[0]) += scaleAmount
- i
;
4490 VARIANT_DIFromDec(*ppDecLeft
, &di
);
4491 *ppDecLeft
= &pDecOut
[1];
4495 DEC_SCALE(&pDecOut
[0]) += (-scaleAmount
) - i
;
4496 VARIANT_DIFromDec(*ppDecRight
, &di
);
4497 *ppDecRight
= &pDecOut
[1];
4502 while (i
-- > 0 && !VARIANT_int_iszero(di
.bitsnum
, sizeof(di
.bitsnum
)/sizeof(DWORD
)))
4504 remainder
= VARIANT_int_divbychar(di
.bitsnum
, sizeof(di
.bitsnum
)/sizeof(DWORD
), 10);
4505 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4508 /* round up the result - native oleaut32 does this */
4509 if (remainder
>= 5) {
4510 for (remainder
= 1, i
= 0; i
< sizeof(di
.bitsnum
)/sizeof(DWORD
) && remainder
; i
++) {
4511 ULONGLONG digit
= di
.bitsnum
[i
] + 1;
4512 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4513 di
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
4517 VARIANT_DecFromDI(&di
, &pDecOut
[1]);
4521 /* Add two unsigned 32 bit values with overflow */
4522 static ULONG
VARIANT_Add(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4524 ULARGE_INTEGER ul64
;
4526 ul64
.QuadPart
= (ULONG64
)ulLeft
+ (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4527 *pulHigh
= ul64
.u
.HighPart
;
4528 return ul64
.u
.LowPart
;
4531 /* Subtract two unsigned 32 bit values with underflow */
4532 static ULONG
VARIANT_Sub(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4534 BOOL invert
= FALSE
;
4535 ULARGE_INTEGER ul64
;
4537 ul64
.QuadPart
= (LONG64
)ulLeft
- (ULONG64
)ulRight
;
4538 if (ulLeft
< ulRight
)
4541 if (ul64
.QuadPart
> (ULONG64
)*pulHigh
)
4542 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4545 ul64
.QuadPart
-= (ULONG64
)*pulHigh
;
4549 ul64
.u
.HighPart
= -ul64
.u
.HighPart
;
4551 *pulHigh
= ul64
.u
.HighPart
;
4552 return ul64
.u
.LowPart
;
4555 /* Multiply two unsigned 32 bit values with overflow */
4556 static ULONG
VARIANT_Mul(ULONG ulLeft
, ULONG ulRight
, ULONG
* pulHigh
)
4558 ULARGE_INTEGER ul64
;
4560 ul64
.QuadPart
= (ULONG64
)ulLeft
* (ULONG64
)ulRight
+ (ULONG64
)*pulHigh
;
4561 *pulHigh
= ul64
.u
.HighPart
;
4562 return ul64
.u
.LowPart
;
4565 /* Compare two decimals that have the same scale */
4566 static inline int VARIANT_DecCmp(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
)
4568 if ( DEC_HI32(pDecLeft
) < DEC_HI32(pDecRight
) ||
4569 (DEC_HI32(pDecLeft
) <= DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) < DEC_LO64(pDecRight
)))
4571 else if (DEC_HI32(pDecLeft
) == DEC_HI32(pDecRight
) && DEC_LO64(pDecLeft
) == DEC_LO64(pDecRight
))
4576 /************************************************************************
4577 * VarDecAdd (OLEAUT32.177)
4579 * Add one DECIMAL to another.
4582 * pDecLeft [I] Source
4583 * pDecRight [I] Value to add
4584 * pDecOut [O] Destination
4588 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4590 HRESULT WINAPI
VarDecAdd(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
4595 hRet
= VARIANT_DecScale(&pDecLeft
, &pDecRight
, scaled
);
4597 if (SUCCEEDED(hRet
))
4599 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4601 BYTE sign
= DECIMAL_POS
;
4604 /* Correct for the sign of the result */
4605 if (DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4607 /* -x + -y : Negative */
4609 goto VarDecAdd_AsPositive
;
4611 else if (DEC_SIGN(pDecLeft
) && !DEC_SIGN(pDecRight
))
4613 cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4615 /* -x + y : Negative if x > y */
4619 VarDecAdd_AsNegative
:
4620 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4621 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4622 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4626 VarDecAdd_AsInvertedNegative
:
4627 DEC_LO32(pDecOut
) = VARIANT_Sub(DEC_LO32(pDecRight
), DEC_LO32(pDecLeft
), &overflow
);
4628 DEC_MID32(pDecOut
) = VARIANT_Sub(DEC_MID32(pDecRight
), DEC_MID32(pDecLeft
), &overflow
);
4629 DEC_HI32(pDecOut
) = VARIANT_Sub(DEC_HI32(pDecRight
), DEC_HI32(pDecLeft
), &overflow
);
4632 else if (!DEC_SIGN(pDecLeft
) && DEC_SIGN(pDecRight
))
4634 cmp
= VARIANT_DecCmp(pDecLeft
, pDecRight
);
4636 /* x + -y : Negative if x <= y */
4640 goto VarDecAdd_AsInvertedNegative
;
4642 goto VarDecAdd_AsNegative
;
4646 /* x + y : Positive */
4647 VarDecAdd_AsPositive
:
4648 DEC_LO32(pDecOut
) = VARIANT_Add(DEC_LO32(pDecLeft
), DEC_LO32(pDecRight
), &overflow
);
4649 DEC_MID32(pDecOut
) = VARIANT_Add(DEC_MID32(pDecLeft
), DEC_MID32(pDecRight
), &overflow
);
4650 DEC_HI32(pDecOut
) = VARIANT_Add(DEC_HI32(pDecLeft
), DEC_HI32(pDecRight
), &overflow
);
4654 return DISP_E_OVERFLOW
; /* overflowed */
4656 DEC_SCALE(pDecOut
) = DEC_SCALE(pDecLeft
);
4657 DEC_SIGN(pDecOut
) = sign
;
4662 /* translate from external DECIMAL format into an internal representation */
4663 static void VARIANT_DIFromDec(const DECIMAL
* from
, VARIANT_DI
* to
)
4665 to
->scale
= DEC_SCALE(from
);
4666 to
->sign
= DEC_SIGN(from
) ? 1 : 0;
4668 to
->bitsnum
[0] = DEC_LO32(from
);
4669 to
->bitsnum
[1] = DEC_MID32(from
);
4670 to
->bitsnum
[2] = DEC_HI32(from
);
4673 static void VARIANT_DecFromDI(const VARIANT_DI
* from
, DECIMAL
* to
)
4676 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_NEG
, from
->scale
);
4678 DEC_SIGNSCALE(to
) = SIGNSCALE(DECIMAL_POS
, from
->scale
);
4681 DEC_LO32(to
) = from
->bitsnum
[0];
4682 DEC_MID32(to
) = from
->bitsnum
[1];
4683 DEC_HI32(to
) = from
->bitsnum
[2];
4686 /* clear an internal representation of a DECIMAL */
4687 static void VARIANT_DI_clear(VARIANT_DI
* i
)
4689 memset(i
, 0, sizeof(VARIANT_DI
));
4692 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4693 size is supported. The value in p is replaced by the quotient of the division, and
4694 the remainder is returned as a result. This routine is most often used with a divisor
4695 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4697 static unsigned char VARIANT_int_divbychar(DWORD
* p
, unsigned int n
, unsigned char divisor
)
4702 } else if (divisor
== 1) {
4703 /* dividend remains unchanged */
4706 unsigned char remainder
= 0;
4707 ULONGLONG iTempDividend
;
4710 for (i
= n
- 1; i
>= 0 && !p
[i
]; i
--); /* skip leading zeros */
4711 for (; i
>= 0; i
--) {
4712 iTempDividend
= ((ULONGLONG
)remainder
<< 32) + p
[i
];
4713 remainder
= iTempDividend
% divisor
;
4714 p
[i
] = iTempDividend
/ divisor
;
4721 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4722 static BOOL
VARIANT_int_iszero(const DWORD
* p
, unsigned int n
)
4724 for (; n
> 0; n
--) if (*p
++ != 0) return FALSE
;
4728 /* multiply two DECIMALS, without changing either one, and place result in third
4729 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4730 digits when scale > 0 in order to fit an overflowing result. Final overflow
4733 static int VARIANT_DI_mul(const VARIANT_DI
* a
, const VARIANT_DI
* b
, VARIANT_DI
* result
)
4735 BOOL r_overflow
= FALSE
;
4737 signed int mulstart
;
4739 VARIANT_DI_clear(result
);
4740 result
->sign
= (a
->sign
^ b
->sign
) ? 1 : 0;
4742 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4743 of the result is formed by adding the scales of the operands.
4745 result
->scale
= a
->scale
+ b
->scale
;
4746 memset(running
, 0, sizeof(running
));
4748 /* count number of leading zero-bytes in operand A */
4749 for (mulstart
= sizeof(a
->bitsnum
)/sizeof(DWORD
) - 1; mulstart
>= 0 && !a
->bitsnum
[mulstart
]; mulstart
--);
4751 /* result is 0, because operand A is 0 */
4755 unsigned char remainder
= 0;
4758 /* perform actual multiplication */
4759 for (iA
= 0; iA
<= mulstart
; iA
++) {
4763 for (iOverflowMul
= 0, iB
= 0; iB
< sizeof(b
->bitsnum
)/sizeof(DWORD
); iB
++) {
4767 iRV
= VARIANT_Mul(b
->bitsnum
[iB
], a
->bitsnum
[iA
], &iOverflowMul
);
4770 running
[iR
] = VARIANT_Add(running
[iR
], 0, &iRV
);
4776 /* Too bad - native oleaut does not do this, so we should not either */
4778 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4779 This operation should not lose significant digits, and gives an
4780 opportunity to reduce the possibility of overflows in future
4781 operations issued by the application.
4783 while (result
->scale
> 0) {
4784 memcpy(quotient
, running
, sizeof(quotient
));
4785 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4786 if (remainder
> 0) break;
4787 memcpy(running
, quotient
, sizeof(quotient
));
4791 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4792 This operation *will* lose significant digits of the result because
4793 all the factors of 10 were consumed by the previous operation.
4795 while (result
->scale
> 0 && !VARIANT_int_iszero(
4796 running
+ sizeof(result
->bitsnum
) / sizeof(DWORD
),
4797 (sizeof(running
) - sizeof(result
->bitsnum
)) / sizeof(DWORD
))) {
4799 remainder
= VARIANT_int_divbychar(running
, sizeof(running
) / sizeof(DWORD
), 10);
4800 if (remainder
> 0) WARN("losing significant digits (remainder %u)...\n", remainder
);
4804 /* round up the result - native oleaut32 does this */
4805 if (remainder
>= 5) {
4807 for (remainder
= 1, i
= 0; i
< sizeof(running
)/sizeof(DWORD
) && remainder
; i
++) {
4808 ULONGLONG digit
= running
[i
] + 1;
4809 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
4810 running
[i
] = digit
& 0xFFFFFFFF;
4814 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4815 and copy result bits into result structure
4817 r_overflow
= !VARIANT_int_iszero(
4818 running
+ sizeof(result
->bitsnum
)/sizeof(DWORD
),
4819 (sizeof(running
) - sizeof(result
->bitsnum
))/sizeof(DWORD
));
4820 memcpy(result
->bitsnum
, running
, sizeof(result
->bitsnum
));
4825 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4826 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4827 success, FALSE if insufficient space in output buffer.
4829 static BOOL
VARIANT_DI_tostringW(const VARIANT_DI
* a
, WCHAR
* s
, unsigned int n
)
4831 BOOL overflow
= FALSE
;
4833 unsigned char remainder
;
4836 /* place negative sign */
4837 if (!VARIANT_int_iszero(a
->bitsnum
, sizeof(a
->bitsnum
) / sizeof(DWORD
)) && a
->sign
) {
4842 else overflow
= TRUE
;
4845 /* prepare initial 0 */
4850 } else overflow
= TRUE
;
4854 memcpy(quotient
, a
->bitsnum
, sizeof(a
->bitsnum
));
4855 while (!overflow
&& !VARIANT_int_iszero(quotient
, sizeof(quotient
) / sizeof(DWORD
))) {
4856 remainder
= VARIANT_int_divbychar(quotient
, sizeof(quotient
) / sizeof(DWORD
), 10);
4860 s
[i
++] = '0' + remainder
;
4865 if (!overflow
&& !VARIANT_int_iszero(a
->bitsnum
, sizeof(a
->bitsnum
) / sizeof(DWORD
))) {
4867 /* reverse order of digits */
4868 WCHAR
* x
= s
; WCHAR
* y
= s
+ i
- 1;
4875 /* check for decimal point. "i" now has string length */
4876 if (i
<= a
->scale
) {
4877 unsigned int numzeroes
= a
->scale
+ 1 - i
;
4878 if (i
+ 1 + numzeroes
>= n
) {
4881 memmove(s
+ numzeroes
, s
, (i
+ 1) * sizeof(WCHAR
));
4883 while (numzeroes
> 0) {
4884 s
[--numzeroes
] = '0';
4889 /* place decimal point */
4891 unsigned int periodpos
= i
- a
->scale
;
4895 memmove(s
+ periodpos
+ 1, s
+ periodpos
, (i
+ 1 - periodpos
) * sizeof(WCHAR
));
4896 s
[periodpos
] = '.'; i
++;
4898 /* remove extra zeros at the end, if any */
4899 while (s
[i
- 1] == '0') s
[--i
] = '\0';
4900 if (s
[i
- 1] == '.') s
[--i
] = '\0';
4908 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4909 static void VARIANT_int_shiftleft(DWORD
* p
, unsigned int n
, unsigned int shift
)
4914 /* shift whole DWORDs to the left */
4917 memmove(p
+ 1, p
, (n
- 1) * sizeof(DWORD
));
4918 *p
= 0; shift
-= 32;
4921 /* shift remainder (1..31 bits) */
4923 if (shift
> 0) for (i
= 0; i
< n
; i
++)
4926 b
= p
[i
] >> (32 - shift
);
4927 p
[i
] = (p
[i
] << shift
) | shifted
;
4932 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4933 Value at v is incremented by the value at p. Any size is supported, provided
4934 that v is not shorter than p. Any unapplied carry is returned as a result.
4936 static unsigned char VARIANT_int_add(DWORD
* v
, unsigned int nv
, const DWORD
* p
,
4939 unsigned char carry
= 0;
4945 for (i
= 0; i
< np
; i
++) {
4946 sum
= (ULONGLONG
)v
[i
]
4949 v
[i
] = sum
& 0xffffffff;
4952 for (; i
< nv
&& carry
; i
++) {
4953 sum
= (ULONGLONG
)v
[i
]
4955 v
[i
] = sum
& 0xffffffff;
4962 /* perform integral division with operand p as dividend. Parameter n indicates
4963 number of available DWORDs in divisor p, but available space in p must be
4964 actually at least 2 * n DWORDs, because the remainder of the integral
4965 division is built in the next n DWORDs past the start of the quotient. This
4966 routine replaces the dividend in p with the quotient, and appends n
4967 additional DWORDs for the remainder.
4969 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4970 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4971 source code to the VLI (Very Large Integer) division operator. This algorithm
4972 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4973 variably-scaled integers such as the MS DECIMAL representation.
4975 static void VARIANT_int_div(DWORD
* p
, unsigned int n
, const DWORD
* divisor
,
4980 DWORD
* negdivisor
= tempsub
+ n
;
4982 /* build 2s-complement of divisor */
4983 for (i
= 0; i
< n
; i
++) negdivisor
[i
] = (i
< dn
) ? ~divisor
[i
] : 0xFFFFFFFF;
4985 VARIANT_int_add(negdivisor
, n
, p
+ n
, 1);
4986 memset(p
+ n
, 0, n
* sizeof(DWORD
));
4988 /* skip all leading zero DWORDs in quotient */
4989 for (i
= 0; i
< n
&& !p
[n
- 1]; i
++) VARIANT_int_shiftleft(p
, n
, 32);
4990 /* i is now number of DWORDs left to process */
4991 for (i
<<= 5; i
< (n
<< 5); i
++) {
4992 VARIANT_int_shiftleft(p
, n
<< 1, 1); /* shl quotient+remainder */
4994 /* trial subtraction */
4995 memcpy(tempsub
, p
+ n
, n
* sizeof(DWORD
));
4996 VARIANT_int_add(tempsub
, n
, negdivisor
, n
);
4998 /* check whether result of subtraction was negative */
4999 if ((tempsub
[n
- 1] & 0x80000000) == 0) {
5000 memcpy(p
+ n
, tempsub
, n
* sizeof(DWORD
));
5006 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
5007 static unsigned char VARIANT_int_mulbychar(DWORD
* p
, unsigned int n
, unsigned char m
)
5012 for (iOverflowMul
= 0, i
= 0; i
< n
; i
++)
5013 p
[i
] = VARIANT_Mul(p
[i
], m
, &iOverflowMul
);
5014 return (unsigned char)iOverflowMul
;
5017 /* increment value in A by the value indicated in B, with scale adjusting.
5018 Modifies parameters by adjusting scales. Returns 0 if addition was
5019 successful, nonzero if a parameter underflowed before it could be
5020 successfully used in the addition.
5022 static int VARIANT_int_addlossy(
5023 DWORD
* a
, int * ascale
, unsigned int an
,
5024 DWORD
* b
, int * bscale
, unsigned int bn
)
5028 if (VARIANT_int_iszero(a
, an
)) {
5029 /* if A is zero, copy B into A, after removing digits */
5030 while (bn
> an
&& !VARIANT_int_iszero(b
+ an
, bn
- an
)) {
5031 VARIANT_int_divbychar(b
, bn
, 10);
5034 memcpy(a
, b
, an
* sizeof(DWORD
));
5036 } else if (!VARIANT_int_iszero(b
, bn
)) {
5037 unsigned int tn
= an
+ 1;
5040 if (bn
+ 1 > tn
) tn
= bn
+ 1;
5041 if (*ascale
!= *bscale
) {
5042 /* first (optimistic) try - try to scale down the one with the bigger
5043 scale, while this number is divisible by 10 */
5044 DWORD
* digitchosen
;
5045 unsigned int nchosen
;
5049 if (*ascale
< *bscale
) {
5050 targetscale
= *ascale
;
5051 scalechosen
= bscale
;
5055 targetscale
= *bscale
;
5056 scalechosen
= ascale
;
5060 memset(t
, 0, tn
* sizeof(DWORD
));
5061 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5063 /* divide by 10 until target scale is reached */
5064 while (*scalechosen
> targetscale
) {
5065 unsigned char remainder
= VARIANT_int_divbychar(t
, tn
, 10);
5068 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5073 if (*ascale
!= *bscale
) {
5074 DWORD
* digitchosen
;
5075 unsigned int nchosen
;
5079 /* try to scale up the one with the smaller scale */
5080 if (*ascale
> *bscale
) {
5081 targetscale
= *ascale
;
5082 scalechosen
= bscale
;
5086 targetscale
= *bscale
;
5087 scalechosen
= ascale
;
5091 memset(t
, 0, tn
* sizeof(DWORD
));
5092 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5094 /* multiply by 10 until target scale is reached, or
5095 significant bytes overflow the number
5097 while (*scalechosen
< targetscale
&& t
[nchosen
] == 0) {
5098 VARIANT_int_mulbychar(t
, tn
, 10);
5099 if (t
[nchosen
] == 0) {
5100 /* still does not overflow */
5102 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5107 if (*ascale
!= *bscale
) {
5108 /* still different? try to scale down the one with the bigger scale
5109 (this *will* lose significant digits) */
5110 DWORD
* digitchosen
;
5111 unsigned int nchosen
;
5115 if (*ascale
< *bscale
) {
5116 targetscale
= *ascale
;
5117 scalechosen
= bscale
;
5121 targetscale
= *bscale
;
5122 scalechosen
= ascale
;
5126 memset(t
, 0, tn
* sizeof(DWORD
));
5127 memcpy(t
, digitchosen
, nchosen
* sizeof(DWORD
));
5129 /* divide by 10 until target scale is reached */
5130 while (*scalechosen
> targetscale
) {
5131 VARIANT_int_divbychar(t
, tn
, 10);
5133 memcpy(digitchosen
, t
, nchosen
* sizeof(DWORD
));
5137 /* check whether any of the operands still has significant digits
5140 if (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
)) {
5143 /* at this step, both numbers have the same scale and can be added
5144 as integers. However, the result might not fit in A, so further
5145 scaling down might be necessary.
5147 while (!underflow
) {
5148 memset(t
, 0, tn
* sizeof(DWORD
));
5149 memcpy(t
, a
, an
* sizeof(DWORD
));
5151 VARIANT_int_add(t
, tn
, b
, bn
);
5152 if (VARIANT_int_iszero(t
+ an
, tn
- an
)) {
5153 /* addition was successful */
5154 memcpy(a
, t
, an
* sizeof(DWORD
));
5157 /* addition overflowed - remove significant digits
5158 from both operands and try again */
5159 VARIANT_int_divbychar(a
, an
, 10); (*ascale
)--;
5160 VARIANT_int_divbychar(b
, bn
, 10); (*bscale
)--;
5161 /* check whether any operand keeps significant digits after
5162 scaledown (underflow case 2)
5164 underflow
= (VARIANT_int_iszero(a
, an
) || VARIANT_int_iszero(b
, bn
));
5172 /* perform complete DECIMAL division in the internal representation. Returns
5173 0 if the division was completed (even if quotient is set to 0), or nonzero
5174 in case of quotient overflow.
5176 static HRESULT
VARIANT_DI_div(const VARIANT_DI
* dividend
, const VARIANT_DI
* divisor
,
5177 VARIANT_DI
* quotient
, BOOL round_remainder
)
5179 HRESULT r_overflow
= S_OK
;
5181 if (VARIANT_int_iszero(divisor
->bitsnum
, sizeof(divisor
->bitsnum
)/sizeof(DWORD
))) {
5183 r_overflow
= DISP_E_DIVBYZERO
;
5184 } else if (VARIANT_int_iszero(dividend
->bitsnum
, sizeof(dividend
->bitsnum
)/sizeof(DWORD
))) {
5185 VARIANT_DI_clear(quotient
);
5187 int quotientscale
, remainderscale
, tempquotientscale
;
5188 DWORD remainderplusquotient
[8];
5191 quotientscale
= remainderscale
= (int)dividend
->scale
- (int)divisor
->scale
;
5192 tempquotientscale
= quotientscale
;
5193 VARIANT_DI_clear(quotient
);
5194 quotient
->sign
= (dividend
->sign
^ divisor
->sign
) ? 1 : 0;
5196 /* The following strategy is used for division
5197 1) if there was a nonzero remainder from previous iteration, use it as
5198 dividend for this iteration, else (for first iteration) use intended
5200 2) perform integer division in temporary buffer, develop quotient in
5201 low-order part, remainder in high-order part
5202 3) add quotient from step 2 to final result, with possible loss of
5204 4) multiply integer part of remainder by 10, while incrementing the
5205 scale of the remainder. This operation preserves the intended value
5207 5) loop to step 1 until one of the following is true:
5208 a) remainder is zero (exact division achieved)
5209 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5211 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5212 memcpy(remainderplusquotient
, dividend
->bitsnum
, sizeof(dividend
->bitsnum
));
5215 remainderplusquotient
, 4,
5216 divisor
->bitsnum
, sizeof(divisor
->bitsnum
)/sizeof(DWORD
));
5217 underflow
= VARIANT_int_addlossy(
5218 quotient
->bitsnum
, "ientscale
, sizeof(quotient
->bitsnum
) / sizeof(DWORD
),
5219 remainderplusquotient
, &tempquotientscale
, 4);
5220 if (round_remainder
) {
5221 if(remainderplusquotient
[4] >= 5){
5223 unsigned char remainder
= 1;
5224 for (i
= 0; i
< sizeof(quotient
->bitsnum
) / sizeof(DWORD
) && remainder
; i
++) {
5225 ULONGLONG digit
= quotient
->bitsnum
[i
] + 1;
5226 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5227 quotient
->bitsnum
[i
] = digit
& 0xFFFFFFFF;
5230 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5232 VARIANT_int_mulbychar(remainderplusquotient
+ 4, 4, 10);
5233 memcpy(remainderplusquotient
, remainderplusquotient
+ 4, 4 * sizeof(DWORD
));
5235 tempquotientscale
= ++remainderscale
;
5236 } while (!underflow
&& !VARIANT_int_iszero(remainderplusquotient
+ 4, 4));
5238 /* quotient scale might now be negative (extremely big number). If, so, try
5239 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5240 until scale is 0. If this cannot be done, it is a real overflow.
5242 while (r_overflow
== S_OK
&& quotientscale
< 0) {
5243 memset(remainderplusquotient
, 0, sizeof(remainderplusquotient
));
5244 memcpy(remainderplusquotient
, quotient
->bitsnum
, sizeof(quotient
->bitsnum
));
5245 VARIANT_int_mulbychar(remainderplusquotient
, sizeof(remainderplusquotient
)/sizeof(DWORD
), 10);
5246 if (VARIANT_int_iszero(remainderplusquotient
+ sizeof(quotient
->bitsnum
)/sizeof(DWORD
),
5247 (sizeof(remainderplusquotient
) - sizeof(quotient
->bitsnum
))/sizeof(DWORD
))) {
5249 memcpy(quotient
->bitsnum
, remainderplusquotient
, sizeof(quotient
->bitsnum
));
5250 } else r_overflow
= DISP_E_OVERFLOW
;
5252 if (r_overflow
== S_OK
) {
5253 if (quotientscale
<= 255) quotient
->scale
= quotientscale
;
5254 else VARIANT_DI_clear(quotient
);
5260 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5261 with an undefined scale, which will be assigned to (if possible). It also
5262 receives an exponent of 2. This procedure will then manipulate the mantissa
5263 and calculate a corresponding scale, so that the exponent2 value is assimilated
5264 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5265 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5267 static HRESULT
VARIANT_DI_normalize(VARIANT_DI
* val
, int exponent2
, BOOL isDouble
)
5269 HRESULT hres
= S_OK
;
5270 int exponent5
, exponent10
;
5272 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5273 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5274 exponent10 might be used to set the VARIANT_DI scale directly. However,
5275 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5276 exponent5
= -exponent2
;
5277 exponent10
= exponent2
;
5279 /* Handle exponent5 > 0 */
5280 while (exponent5
> 0) {
5284 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5285 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5286 somehow the mantissa should be divided by 2. */
5287 if ((val
->bitsnum
[0] & 1) == 0) {
5288 /* The mantissa is divisible by 2. Therefore the division can be done
5289 without losing significant digits. */
5290 exponent10
++; exponent5
--;
5293 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5294 val
->bitsnum
[2] >>= 1;
5295 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5296 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5297 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5299 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5300 be multiplied by 5, unless the multiplication overflows. */
5301 DWORD temp_bitsnum
[3];
5305 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5306 if (0 == VARIANT_int_mulbychar(temp_bitsnum
, 3, 5)) {
5307 /* Multiplication succeeded without overflow, so copy result back
5309 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5311 /* Mask out 3 extraneous bits introduced by the multiply */
5313 /* Multiplication by 5 overflows. The mantissa should be divided
5314 by 2, and therefore will lose significant digits. */
5318 bPrevCarryBit
= val
->bitsnum
[2] & 1;
5319 val
->bitsnum
[2] >>= 1;
5320 bCurrCarryBit
= val
->bitsnum
[1] & 1;
5321 val
->bitsnum
[1] = (val
->bitsnum
[1] >> 1) | (bPrevCarryBit
? 0x80000000 : 0);
5322 val
->bitsnum
[0] = (val
->bitsnum
[0] >> 1) | (bCurrCarryBit
? 0x80000000 : 0);
5327 /* Handle exponent5 < 0 */
5328 while (exponent5
< 0) {
5329 /* In order to divide the value represented by the VARIANT_DI by 5, it
5330 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5331 and the mantissa should be multiplied by 2 */
5332 if ((val
->bitsnum
[2] & 0x80000000) == 0) {
5333 /* The mantissa can withstand a shift-left without overflowing */
5334 exponent10
--; exponent5
++;
5335 VARIANT_int_shiftleft(val
->bitsnum
, 3, 1);
5337 /* The mantissa would overflow if shifted. Therefore it should be
5338 directly divided by 5. This will lose significant digits, unless
5339 by chance the mantissa happens to be divisible by 5 */
5341 VARIANT_int_divbychar(val
->bitsnum
, 3, 5);
5345 /* At this point, the mantissa has assimilated the exponent5, but the
5346 exponent10 might not be suitable for assignment. The exponent10 must be
5347 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5348 down appropriately. */
5349 while (hres
== S_OK
&& exponent10
> 0) {
5350 /* In order to bring exponent10 down to 0, the mantissa should be
5351 multiplied by 10 to compensate. If the exponent10 is too big, this
5352 will cause the mantissa to overflow. */
5353 if (0 == VARIANT_int_mulbychar(val
->bitsnum
, 3, 10)) {
5356 hres
= DISP_E_OVERFLOW
;
5359 while (exponent10
< -DEC_MAX_SCALE
) {
5361 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5362 be divided by 10 to compensate. If the exponent10 is too small, this
5363 will cause the mantissa to underflow and become 0 */
5364 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5366 if (VARIANT_int_iszero(val
->bitsnum
, 3)) {
5367 /* Underflow, unable to keep dividing */
5369 } else if (rem10
>= 5) {
5371 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5374 /* This step is required in order to remove excess bits of precision from the
5375 end of the bit representation, down to the precision guaranteed by the
5376 floating point number. */
5378 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || (val
->bitsnum
[2] == 0 && (val
->bitsnum
[1] & 0xFFE00000) != 0))) {
5381 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5385 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5389 while (exponent10
< 0 && (val
->bitsnum
[2] != 0 || val
->bitsnum
[1] != 0 ||
5390 (val
->bitsnum
[2] == 0 && val
->bitsnum
[1] == 0 && (val
->bitsnum
[0] & 0xFF000000) != 0))) {
5393 rem10
= VARIANT_int_divbychar(val
->bitsnum
, 3, 10);
5397 VARIANT_int_add(val
->bitsnum
, 3, &x
, 1);
5401 /* Remove multiples of 10 from the representation */
5402 while (exponent10
< 0) {
5403 DWORD temp_bitsnum
[3];
5405 memcpy(temp_bitsnum
, val
->bitsnum
, 3 * sizeof(DWORD
));
5406 if (0 == VARIANT_int_divbychar(temp_bitsnum
, 3, 10)) {
5408 memcpy(val
->bitsnum
, temp_bitsnum
, 3 * sizeof(DWORD
));
5412 /* Scale assignment */
5413 if (hres
== S_OK
) val
->scale
= -exponent10
;
5422 unsigned int m
: 23;
5423 unsigned int exp_bias
: 8;
5424 unsigned int sign
: 1;
5429 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5430 intermediate string step. */
5431 static HRESULT
VARIANT_DI_FromR4(float source
, VARIANT_DI
* dest
)
5433 HRESULT hres
= S_OK
;
5438 /* Detect special cases */
5439 if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0) {
5440 /* Floating-point zero */
5441 VARIANT_DI_clear(dest
);
5442 } else if (fx
.i
.m
== 0 && fx
.i
.exp_bias
== 0xFF) {
5443 /* Floating-point infinity */
5444 hres
= DISP_E_OVERFLOW
;
5445 } else if (fx
.i
.exp_bias
== 0xFF) {
5446 /* Floating-point NaN */
5447 hres
= DISP_E_BADVARTYPE
;
5450 VARIANT_DI_clear(dest
);
5452 exponent2
= fx
.i
.exp_bias
- 127; /* Get unbiased exponent */
5453 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5455 /* Copy significant bits to VARIANT_DI mantissa */
5456 dest
->bitsnum
[0] = fx
.i
.m
;
5457 dest
->bitsnum
[0] &= 0x007FFFFF;
5458 if (fx
.i
.exp_bias
== 0) {
5459 /* Denormalized number - correct exponent */
5462 /* Add hidden bit to mantissa */
5463 dest
->bitsnum
[0] |= 0x00800000;
5466 /* The act of copying a FP mantissa as integer bits is equivalent to
5467 shifting left the mantissa 23 bits. The exponent2 is reduced to
5471 hres
= VARIANT_DI_normalize(dest
, exponent2
, FALSE
);
5481 unsigned int m_lo
: 32; /* 52 bits of precision */
5482 unsigned int m_hi
: 20;
5483 unsigned int exp_bias
: 11; /* bias == 1023 */
5484 unsigned int sign
: 1;
5489 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5490 intermediate string step. */
5491 static HRESULT
VARIANT_DI_FromR8(double source
, VARIANT_DI
* dest
)
5493 HRESULT hres
= S_OK
;
5498 /* Detect special cases */
5499 if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0) {
5500 /* Floating-point zero */
5501 VARIANT_DI_clear(dest
);
5502 } else if (fx
.i
.m_lo
== 0 && fx
.i
.m_hi
== 0 && fx
.i
.exp_bias
== 0x7FF) {
5503 /* Floating-point infinity */
5504 hres
= DISP_E_OVERFLOW
;
5505 } else if (fx
.i
.exp_bias
== 0x7FF) {
5506 /* Floating-point NaN */
5507 hres
= DISP_E_BADVARTYPE
;
5510 VARIANT_DI_clear(dest
);
5512 exponent2
= fx
.i
.exp_bias
- 1023; /* Get unbiased exponent */
5513 dest
->sign
= fx
.i
.sign
; /* Sign is simply copied */
5515 /* Copy significant bits to VARIANT_DI mantissa */
5516 dest
->bitsnum
[0] = fx
.i
.m_lo
;
5517 dest
->bitsnum
[1] = fx
.i
.m_hi
;
5518 dest
->bitsnum
[1] &= 0x000FFFFF;
5519 if (fx
.i
.exp_bias
== 0) {
5520 /* Denormalized number - correct exponent */
5523 /* Add hidden bit to mantissa */
5524 dest
->bitsnum
[1] |= 0x00100000;
5527 /* The act of copying a FP mantissa as integer bits is equivalent to
5528 shifting left the mantissa 52 bits. The exponent2 is reduced to
5532 hres
= VARIANT_DI_normalize(dest
, exponent2
, TRUE
);
5538 static HRESULT
VARIANT_do_division(const DECIMAL
*pDecLeft
, const DECIMAL
*pDecRight
, DECIMAL
*pDecOut
,
5541 HRESULT hRet
= S_OK
;
5542 VARIANT_DI di_left
, di_right
, di_result
;
5545 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5546 VARIANT_DIFromDec(pDecRight
, &di_right
);
5547 divresult
= VARIANT_DI_div(&di_left
, &di_right
, &di_result
, round
);
5548 if (divresult
!= S_OK
)
5550 /* division actually overflowed */
5557 if (di_result
.scale
> DEC_MAX_SCALE
)
5559 unsigned char remainder
= 0;
5561 /* division underflowed. In order to comply with the MSDN
5562 specifications for DECIMAL ranges, some significant digits
5565 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5567 while (di_result
.scale
> DEC_MAX_SCALE
&&
5568 !VARIANT_int_iszero(di_result
.bitsnum
, sizeof(di_result
.bitsnum
) / sizeof(DWORD
)))
5570 remainder
= VARIANT_int_divbychar(di_result
.bitsnum
, sizeof(di_result
.bitsnum
) / sizeof(DWORD
), 10);
5573 if (di_result
.scale
> DEC_MAX_SCALE
)
5575 WARN("result underflowed, setting to 0\n");
5576 di_result
.scale
= 0;
5579 else if (remainder
>= 5) /* round up result - native oleaut32 does this */
5582 for (remainder
= 1, i
= 0; i
< sizeof(di_result
.bitsnum
) / sizeof(DWORD
) && remainder
; i
++) {
5583 ULONGLONG digit
= di_result
.bitsnum
[i
] + 1;
5584 remainder
= (digit
> 0xFFFFFFFF) ? 1 : 0;
5585 di_result
.bitsnum
[i
] = digit
& 0xFFFFFFFF;
5589 VARIANT_DecFromDI(&di_result
, pDecOut
);
5594 /************************************************************************
5595 * VarDecDiv (OLEAUT32.178)
5597 * Divide one DECIMAL by another.
5600 * pDecLeft [I] Source
5601 * pDecRight [I] Value to divide by
5602 * pDecOut [O] Destination
5606 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5608 HRESULT WINAPI
VarDecDiv(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5610 if (!pDecLeft
|| !pDecRight
|| !pDecOut
) return E_INVALIDARG
;
5612 return VARIANT_do_division(pDecLeft
, pDecRight
, pDecOut
, FALSE
);
5615 /************************************************************************
5616 * VarDecMul (OLEAUT32.179)
5618 * Multiply one DECIMAL by another.
5621 * pDecLeft [I] Source
5622 * pDecRight [I] Value to multiply by
5623 * pDecOut [O] Destination
5627 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5629 HRESULT WINAPI
VarDecMul(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5631 HRESULT hRet
= S_OK
;
5632 VARIANT_DI di_left
, di_right
, di_result
;
5635 VARIANT_DIFromDec(pDecLeft
, &di_left
);
5636 VARIANT_DIFromDec(pDecRight
, &di_right
);
5637 mulresult
= VARIANT_DI_mul(&di_left
, &di_right
, &di_result
);
5640 /* multiplication actually overflowed */
5641 hRet
= DISP_E_OVERFLOW
;
5645 if (di_result
.scale
> DEC_MAX_SCALE
)
5647 /* multiplication underflowed. In order to comply with the MSDN
5648 specifications for DECIMAL ranges, some significant digits
5651 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5653 while (di_result
.scale
> DEC_MAX_SCALE
&&
5654 !VARIANT_int_iszero(di_result
.bitsnum
, sizeof(di_result
.bitsnum
)/sizeof(DWORD
)))
5656 VARIANT_int_divbychar(di_result
.bitsnum
, sizeof(di_result
.bitsnum
)/sizeof(DWORD
), 10);
5659 if (di_result
.scale
> DEC_MAX_SCALE
)
5661 WARN("result underflowed, setting to 0\n");
5662 di_result
.scale
= 0;
5666 VARIANT_DecFromDI(&di_result
, pDecOut
);
5671 /************************************************************************
5672 * VarDecSub (OLEAUT32.181)
5674 * Subtract one DECIMAL from another.
5677 * pDecLeft [I] Source
5678 * pDecRight [I] DECIMAL to subtract from pDecLeft
5679 * pDecOut [O] Destination
5682 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5684 HRESULT WINAPI
VarDecSub(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
, DECIMAL
* pDecOut
)
5688 /* Implement as addition of the negative */
5689 VarDecNeg(pDecRight
, &decRight
);
5690 return VarDecAdd(pDecLeft
, &decRight
, pDecOut
);
5693 /************************************************************************
5694 * VarDecAbs (OLEAUT32.182)
5696 * Convert a DECIMAL into its absolute value.
5700 * pDecOut [O] Destination
5703 * S_OK. This function does not fail.
5705 HRESULT WINAPI
VarDecAbs(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5708 DEC_SIGN(pDecOut
) &= ~DECIMAL_NEG
;
5712 /************************************************************************
5713 * VarDecFix (OLEAUT32.187)
5715 * Return the integer portion of a DECIMAL.
5719 * pDecOut [O] Destination
5723 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5726 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5727 * negative numbers away from 0, while this function rounds them towards zero.
5729 HRESULT WINAPI
VarDecFix(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5734 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5735 return E_INVALIDARG
;
5737 if (!DEC_SCALE(pDecIn
))
5739 *pDecOut
= *pDecIn
; /* Already an integer */
5743 hr
= VarR8FromDec(pDecIn
, &dbl
);
5744 if (SUCCEEDED(hr
)) {
5745 LONGLONG rounded
= dbl
;
5747 hr
= VarDecFromI8(rounded
, pDecOut
);
5752 /************************************************************************
5753 * VarDecInt (OLEAUT32.188)
5755 * Return the integer portion of a DECIMAL.
5759 * pDecOut [O] Destination
5763 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5766 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5767 * negative numbers towards 0, while this function rounds them away from zero.
5769 HRESULT WINAPI
VarDecInt(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5774 if (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
)
5775 return E_INVALIDARG
;
5777 if (!(DEC_SIGN(pDecIn
) & DECIMAL_NEG
) || !DEC_SCALE(pDecIn
))
5778 return VarDecFix(pDecIn
, pDecOut
); /* The same, if +ve or no fractionals */
5780 hr
= VarR8FromDec(pDecIn
, &dbl
);
5781 if (SUCCEEDED(hr
)) {
5782 LONGLONG rounded
= dbl
>= 0.0 ? dbl
+ 0.5 : dbl
- 0.5;
5784 hr
= VarDecFromI8(rounded
, pDecOut
);
5789 /************************************************************************
5790 * VarDecNeg (OLEAUT32.189)
5792 * Change the sign of a DECIMAL.
5796 * pDecOut [O] Destination
5799 * S_OK. This function does not fail.
5801 HRESULT WINAPI
VarDecNeg(const DECIMAL
* pDecIn
, DECIMAL
* pDecOut
)
5804 DEC_SIGN(pDecOut
) ^= DECIMAL_NEG
;
5808 /************************************************************************
5809 * VarDecRound (OLEAUT32.203)
5811 * Change the precision of a DECIMAL.
5815 * cDecimals [I] New number of decimals to keep
5816 * pDecOut [O] Destination
5819 * Success: S_OK. pDecOut contains the rounded value.
5820 * Failure: E_INVALIDARG if any argument is invalid.
5822 HRESULT WINAPI
VarDecRound(const DECIMAL
* pDecIn
, int cDecimals
, DECIMAL
* pDecOut
)
5824 DECIMAL divisor
, tmp
;
5828 if (cDecimals
< 0 || (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
) || DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
)
5829 return E_INVALIDARG
;
5831 if (cDecimals
>= DEC_SCALE(pDecIn
))
5833 *pDecOut
= *pDecIn
; /* More precision than we have */
5837 /* truncate significant digits and rescale */
5838 memset(&divisor
, 0, sizeof(divisor
));
5839 DEC_LO64(&divisor
) = 1;
5841 memset(&tmp
, 0, sizeof(tmp
));
5842 DEC_LO64(&tmp
) = 10;
5843 for (i
= 0; i
< DEC_SCALE(pDecIn
) - cDecimals
; ++i
)
5845 hr
= VarDecMul(&divisor
, &tmp
, &divisor
);
5850 hr
= VARIANT_do_division(pDecIn
, &divisor
, pDecOut
, TRUE
);
5854 DEC_SCALE(pDecOut
) = cDecimals
;
5859 /************************************************************************
5860 * VarDecCmp (OLEAUT32.204)
5862 * Compare two DECIMAL values.
5865 * pDecLeft [I] Source
5866 * pDecRight [I] Value to compare
5869 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5870 * is less than, equal to or greater than pDecRight respectively.
5871 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5873 HRESULT WINAPI
VarDecCmp(const DECIMAL
* pDecLeft
, const DECIMAL
* pDecRight
)
5878 if (!pDecLeft
|| !pDecRight
)
5881 if ((!(DEC_SIGN(pDecLeft
) & DECIMAL_NEG
)) && (DEC_SIGN(pDecRight
) & DECIMAL_NEG
) &&
5882 (DEC_HI32(pDecLeft
) | DEC_MID32(pDecLeft
) | DEC_LO32(pDecLeft
)))
5884 else if ((DEC_SIGN(pDecLeft
) & DECIMAL_NEG
) && (!(DEC_SIGN(pDecRight
) & DECIMAL_NEG
)) &&
5885 (DEC_HI32(pDecLeft
) | DEC_MID32(pDecLeft
) | DEC_LO32(pDecLeft
)))
5888 /* Subtract right from left, and compare the result to 0 */
5889 hRet
= VarDecSub(pDecLeft
, pDecRight
, &result
);
5891 if (SUCCEEDED(hRet
))
5893 int non_zero
= DEC_HI32(&result
) | DEC_MID32(&result
) | DEC_LO32(&result
);
5895 if ((DEC_SIGN(&result
) & DECIMAL_NEG
) && non_zero
)
5896 hRet
= (HRESULT
)VARCMP_LT
;
5898 hRet
= (HRESULT
)VARCMP_GT
;
5900 hRet
= (HRESULT
)VARCMP_EQ
;
5905 /************************************************************************
5906 * VarDecCmpR8 (OLEAUT32.298)
5908 * Compare a DECIMAL to a double
5911 * pDecLeft [I] DECIMAL Source
5912 * dblRight [I] double to compare to pDecLeft
5915 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5916 * is less than, equal to or greater than pDecLeft respectively.
5917 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5919 HRESULT WINAPI
VarDecCmpR8(const DECIMAL
* pDecLeft
, double dblRight
)
5924 hRet
= VarDecFromR8(dblRight
, &decRight
);
5926 if (SUCCEEDED(hRet
))
5927 hRet
= VarDecCmp(pDecLeft
, &decRight
);
5935 /************************************************************************
5936 * VarBoolFromUI1 (OLEAUT32.118)
5938 * Convert a VT_UI1 to a VT_BOOL.
5942 * pBoolOut [O] Destination
5947 HRESULT WINAPI
VarBoolFromUI1(BYTE bIn
, VARIANT_BOOL
*pBoolOut
)
5949 *pBoolOut
= bIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5953 /************************************************************************
5954 * VarBoolFromI2 (OLEAUT32.119)
5956 * Convert a VT_I2 to a VT_BOOL.
5960 * pBoolOut [O] Destination
5965 HRESULT WINAPI
VarBoolFromI2(SHORT sIn
, VARIANT_BOOL
*pBoolOut
)
5967 *pBoolOut
= sIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5971 /************************************************************************
5972 * VarBoolFromI4 (OLEAUT32.120)
5974 * Convert a VT_I4 to a VT_BOOL.
5978 * pBoolOut [O] Destination
5983 HRESULT WINAPI
VarBoolFromI4(LONG lIn
, VARIANT_BOOL
*pBoolOut
)
5985 *pBoolOut
= lIn
? VARIANT_TRUE
: VARIANT_FALSE
;
5989 /************************************************************************
5990 * VarBoolFromR4 (OLEAUT32.121)
5992 * Convert a VT_R4 to a VT_BOOL.
5996 * pBoolOut [O] Destination
6001 HRESULT WINAPI
VarBoolFromR4(FLOAT fltIn
, VARIANT_BOOL
*pBoolOut
)
6003 *pBoolOut
= fltIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6007 /************************************************************************
6008 * VarBoolFromR8 (OLEAUT32.122)
6010 * Convert a VT_R8 to a VT_BOOL.
6014 * pBoolOut [O] Destination
6019 HRESULT WINAPI
VarBoolFromR8(double dblIn
, VARIANT_BOOL
*pBoolOut
)
6021 *pBoolOut
= dblIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6025 /************************************************************************
6026 * VarBoolFromDate (OLEAUT32.123)
6028 * Convert a VT_DATE to a VT_BOOL.
6032 * pBoolOut [O] Destination
6037 HRESULT WINAPI
VarBoolFromDate(DATE dateIn
, VARIANT_BOOL
*pBoolOut
)
6039 *pBoolOut
= dateIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6043 /************************************************************************
6044 * VarBoolFromCy (OLEAUT32.124)
6046 * Convert a VT_CY to a VT_BOOL.
6050 * pBoolOut [O] Destination
6055 HRESULT WINAPI
VarBoolFromCy(CY cyIn
, VARIANT_BOOL
*pBoolOut
)
6057 *pBoolOut
= cyIn
.int64
? VARIANT_TRUE
: VARIANT_FALSE
;
6061 /************************************************************************
6062 * VARIANT_GetLocalisedText [internal]
6064 * Get a localized string from the resources
6067 BOOL
VARIANT_GetLocalisedText(LANGID langId
, DWORD dwId
, WCHAR
*lpszDest
)
6071 hrsrc
= FindResourceExW( hProxyDll
, (LPWSTR
)RT_STRING
,
6072 MAKEINTRESOURCEW((dwId
>> 4) + 1), langId
);
6075 HGLOBAL hmem
= LoadResource( hProxyDll
, hrsrc
);
6082 p
= LockResource( hmem
);
6083 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
6085 memcpy( lpszDest
, p
+ 1, *p
* sizeof(WCHAR
) );
6086 lpszDest
[*p
] = '\0';
6087 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest
), langId
);
6094 /************************************************************************
6095 * VarBoolFromStr (OLEAUT32.125)
6097 * Convert a VT_BSTR to a VT_BOOL.
6101 * lcid [I] LCID for the conversion
6102 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6103 * pBoolOut [O] Destination
6107 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6108 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6111 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6112 * it may contain (in any case mapping) the text "true" or "false".
6113 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6114 * localised text of "True" or "False" in the language specified by lcid.
6115 * - If none of these matches occur, the string is treated as a numeric string
6116 * and the boolean pBoolOut will be set according to whether the number is zero
6117 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6118 * - If the text is not numeric and does not match any of the above, then
6119 * DISP_E_TYPEMISMATCH is returned.
6121 HRESULT WINAPI
VarBoolFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, VARIANT_BOOL
*pBoolOut
)
6123 /* Any VB/VBA programmers out there should recognise these strings... */
6124 static const WCHAR szFalse
[] = { '#','F','A','L','S','E','#','\0' };
6125 static const WCHAR szTrue
[] = { '#','T','R','U','E','#','\0' };
6127 LANGID langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6128 HRESULT hRes
= S_OK
;
6130 if (!strIn
|| !pBoolOut
)
6131 return DISP_E_TYPEMISMATCH
;
6133 /* Check if we should be comparing against localised text */
6134 if (dwFlags
& VAR_LOCALBOOL
)
6136 /* Convert our LCID into a usable value */
6137 lcid
= ConvertDefaultLocale(lcid
);
6139 langId
= LANGIDFROMLCID(lcid
);
6141 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6142 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6144 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6145 * I don't think this is needed unless any of the localised text strings
6146 * contain characters that can be so mapped. In the event that this is
6147 * true for a given language (possibly some Asian languages), then strIn
6148 * should be mapped here _only_ if langId is an Id for which this can occur.
6152 /* Note that if we are not comparing against localised strings, langId
6153 * will have its default value of LANG_ENGLISH. This allows us to mimic
6154 * the native behaviour of always checking against English strings even
6155 * after we've checked for localised ones.
6157 VarBoolFromStr_CheckLocalised
:
6158 if (VARIANT_GetLocalisedText(langId
, IDS_TRUE
, szBuff
))
6160 /* Compare against localised strings, ignoring case */
6161 if (!strcmpiW(strIn
, szBuff
))
6163 *pBoolOut
= VARIANT_TRUE
; /* Matched localised 'true' text */
6166 VARIANT_GetLocalisedText(langId
, IDS_FALSE
, szBuff
);
6167 if (!strcmpiW(strIn
, szBuff
))
6169 *pBoolOut
= VARIANT_FALSE
; /* Matched localised 'false' text */
6174 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6176 /* We have checked the localised text, now check English */
6177 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6178 goto VarBoolFromStr_CheckLocalised
;
6181 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6182 if (!strcmpW(strIn
, szFalse
))
6183 *pBoolOut
= VARIANT_FALSE
;
6184 else if (!strcmpW(strIn
, szTrue
))
6185 *pBoolOut
= VARIANT_TRUE
;
6190 /* If this string is a number, convert it as one */
6191 hRes
= VarR8FromStr(strIn
, lcid
, dwFlags
, &d
);
6192 if (SUCCEEDED(hRes
)) *pBoolOut
= d
? VARIANT_TRUE
: VARIANT_FALSE
;
6197 /************************************************************************
6198 * VarBoolFromDisp (OLEAUT32.126)
6200 * Convert a VT_DISPATCH to a VT_BOOL.
6203 * pdispIn [I] Source
6204 * lcid [I] LCID for conversion
6205 * pBoolOut [O] Destination
6209 * Failure: E_INVALIDARG, if the source value is invalid
6210 * DISP_E_OVERFLOW, if the value will not fit in the destination
6211 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6213 HRESULT WINAPI
VarBoolFromDisp(IDispatch
* pdispIn
, LCID lcid
, VARIANT_BOOL
*pBoolOut
)
6215 return VARIANT_FromDisp(pdispIn
, lcid
, pBoolOut
, VT_BOOL
, 0);
6218 /************************************************************************
6219 * VarBoolFromI1 (OLEAUT32.233)
6221 * Convert a VT_I1 to a VT_BOOL.
6225 * pBoolOut [O] Destination
6230 HRESULT WINAPI
VarBoolFromI1(signed char cIn
, VARIANT_BOOL
*pBoolOut
)
6232 *pBoolOut
= cIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6236 /************************************************************************
6237 * VarBoolFromUI2 (OLEAUT32.234)
6239 * Convert a VT_UI2 to a VT_BOOL.
6243 * pBoolOut [O] Destination
6248 HRESULT WINAPI
VarBoolFromUI2(USHORT usIn
, VARIANT_BOOL
*pBoolOut
)
6250 *pBoolOut
= usIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6254 /************************************************************************
6255 * VarBoolFromUI4 (OLEAUT32.235)
6257 * Convert a VT_UI4 to a VT_BOOL.
6261 * pBoolOut [O] Destination
6266 HRESULT WINAPI
VarBoolFromUI4(ULONG ulIn
, VARIANT_BOOL
*pBoolOut
)
6268 *pBoolOut
= ulIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6272 /************************************************************************
6273 * VarBoolFromDec (OLEAUT32.236)
6275 * Convert a VT_DECIMAL to a VT_BOOL.
6279 * pBoolOut [O] Destination
6283 * Failure: E_INVALIDARG, if pDecIn is invalid.
6285 HRESULT WINAPI
VarBoolFromDec(DECIMAL
* pDecIn
, VARIANT_BOOL
*pBoolOut
)
6287 if (DEC_SCALE(pDecIn
) > DEC_MAX_SCALE
|| (DEC_SIGN(pDecIn
) & ~DECIMAL_NEG
))
6288 return E_INVALIDARG
;
6290 if (DEC_HI32(pDecIn
) || DEC_MID32(pDecIn
) || DEC_LO32(pDecIn
))
6291 *pBoolOut
= VARIANT_TRUE
;
6293 *pBoolOut
= VARIANT_FALSE
;
6297 /************************************************************************
6298 * VarBoolFromI8 (OLEAUT32.370)
6300 * Convert a VT_I8 to a VT_BOOL.
6304 * pBoolOut [O] Destination
6309 HRESULT WINAPI
VarBoolFromI8(LONG64 llIn
, VARIANT_BOOL
*pBoolOut
)
6311 *pBoolOut
= llIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6315 /************************************************************************
6316 * VarBoolFromUI8 (OLEAUT32.371)
6318 * Convert a VT_UI8 to a VT_BOOL.
6322 * pBoolOut [O] Destination
6327 HRESULT WINAPI
VarBoolFromUI8(ULONG64 ullIn
, VARIANT_BOOL
*pBoolOut
)
6329 *pBoolOut
= ullIn
? VARIANT_TRUE
: VARIANT_FALSE
;
6336 /* Write a number from a UI8 and sign */
6337 static WCHAR
*VARIANT_WriteNumber(ULONG64 ulVal
, WCHAR
* szOut
)
6341 WCHAR ulNextDigit
= ulVal
% 10;
6343 *szOut
-- = '0' + ulNextDigit
;
6344 ulVal
= (ulVal
- ulNextDigit
) / 10;
6351 /* Create a (possibly localised) BSTR from a UI8 and sign */
6352 static BSTR
VARIANT_MakeBstr(LCID lcid
, DWORD dwFlags
, WCHAR
*szOut
)
6354 WCHAR szConverted
[256];
6356 if (dwFlags
& VAR_NEGATIVE
)
6359 if (dwFlags
& LOCALE_USE_NLS
)
6361 /* Format the number for the locale */
6362 szConverted
[0] = '\0';
6363 GetNumberFormatW(lcid
,
6364 dwFlags
& LOCALE_NOUSEROVERRIDE
,
6365 szOut
, NULL
, szConverted
, sizeof(szConverted
)/sizeof(WCHAR
));
6366 szOut
= szConverted
;
6368 return SysAllocStringByteLen((LPCSTR
)szOut
, strlenW(szOut
) * sizeof(WCHAR
));
6371 /* Create a (possibly localised) BSTR from a UI8 and sign */
6372 static HRESULT
VARIANT_BstrFromUInt(ULONG64 ulVal
, LCID lcid
, DWORD dwFlags
, BSTR
*pbstrOut
)
6374 WCHAR szBuff
[64], *szOut
= szBuff
+ sizeof(szBuff
)/sizeof(WCHAR
) - 1;
6377 return E_INVALIDARG
;
6379 /* Create the basic number string */
6381 szOut
= VARIANT_WriteNumber(ulVal
, szOut
);
6383 *pbstrOut
= VARIANT_MakeBstr(lcid
, dwFlags
, szOut
);
6384 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6385 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6388 /******************************************************************************
6389 * VarBstrFromUI1 (OLEAUT32.108)
6391 * Convert a VT_UI1 to a VT_BSTR.
6395 * lcid [I] LCID for the conversion
6396 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6397 * pbstrOut [O] Destination
6401 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6402 * E_OUTOFMEMORY, if memory allocation fails.
6404 HRESULT WINAPI
VarBstrFromUI1(BYTE bIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6406 return VARIANT_BstrFromUInt(bIn
, lcid
, dwFlags
, pbstrOut
);
6409 /******************************************************************************
6410 * VarBstrFromI2 (OLEAUT32.109)
6412 * Convert a VT_I2 to a VT_BSTR.
6416 * lcid [I] LCID for the conversion
6417 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6418 * pbstrOut [O] Destination
6422 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6423 * E_OUTOFMEMORY, if memory allocation fails.
6425 HRESULT WINAPI
VarBstrFromI2(short sIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6432 dwFlags
|= VAR_NEGATIVE
;
6434 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6437 /******************************************************************************
6438 * VarBstrFromI4 (OLEAUT32.110)
6440 * Convert a VT_I4 to a VT_BSTR.
6444 * lcid [I] LCID for the conversion
6445 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6446 * pbstrOut [O] Destination
6450 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6451 * E_OUTOFMEMORY, if memory allocation fails.
6453 HRESULT WINAPI
VarBstrFromI4(LONG lIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6460 dwFlags
|= VAR_NEGATIVE
;
6462 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6465 static BSTR
VARIANT_BstrReplaceDecimal(const WCHAR
* buff
, LCID lcid
, ULONG dwFlags
)
6468 WCHAR lpDecimalSep
[16];
6470 /* Native oleaut32 uses the locale-specific decimal separator even in the
6471 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6472 American locales will see "one thousand and one tenth" as "1000,1"
6473 instead of "1000.1" (notice the comma). The following code checks for
6474 the need to replace the decimal separator, and if so, will prepare an
6475 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6477 GetLocaleInfoW(lcid
, LOCALE_SDECIMAL
| (dwFlags
& LOCALE_NOUSEROVERRIDE
),
6478 lpDecimalSep
, sizeof(lpDecimalSep
) / sizeof(WCHAR
));
6479 if (lpDecimalSep
[0] == '.' && lpDecimalSep
[1] == '\0')
6481 /* locale is compatible with English - return original string */
6482 bstrOut
= SysAllocString(buff
);
6488 WCHAR empty
[] = {'\0'};
6489 NUMBERFMTW minFormat
;
6491 minFormat
.NumDigits
= 0;
6492 minFormat
.LeadingZero
= 0;
6493 minFormat
.Grouping
= 0;
6494 minFormat
.lpDecimalSep
= lpDecimalSep
;
6495 minFormat
.lpThousandSep
= empty
;
6496 minFormat
.NegativeOrder
= 1; /* NLS_NEG_LEFT */
6498 /* count number of decimal digits in string */
6499 p
= strchrW( buff
, '.' );
6500 if (p
) minFormat
.NumDigits
= strlenW(p
+ 1);
6503 if (!GetNumberFormatW(lcid
, 0, buff
, &minFormat
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
)))
6505 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6506 bstrOut
= SysAllocString(buff
);
6510 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff
));
6511 bstrOut
= SysAllocString(numbuff
);
6517 static HRESULT
VARIANT_BstrFromReal(DOUBLE dblIn
, LCID lcid
, ULONG dwFlags
,
6518 BSTR
* pbstrOut
, LPCWSTR lpszFormat
)
6523 return E_INVALIDARG
;
6525 sprintfW( buff
, lpszFormat
, dblIn
);
6527 /* Negative zeroes are disallowed (some applications depend on this).
6528 If buff starts with a minus, and then nothing follows but zeroes
6529 and/or a period, it is a negative zero and is replaced with a
6530 canonical zero. This duplicates native oleaut32 behavior.
6534 const WCHAR szAccept
[] = {'0', '.', '\0'};
6535 if (strlenW(buff
+ 1) == strspnW(buff
+ 1, szAccept
))
6536 { buff
[0] = '0'; buff
[1] = '\0'; }
6539 TRACE("created string %s\n", debugstr_w(buff
));
6540 if (dwFlags
& LOCALE_USE_NLS
)
6544 /* Format the number for the locale */
6546 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6547 buff
, NULL
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
));
6548 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
6549 *pbstrOut
= SysAllocString(numbuff
);
6553 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
6555 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6558 /******************************************************************************
6559 * VarBstrFromR4 (OLEAUT32.111)
6561 * Convert a VT_R4 to a VT_BSTR.
6565 * lcid [I] LCID for the conversion
6566 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6567 * pbstrOut [O] Destination
6571 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6572 * E_OUTOFMEMORY, if memory allocation fails.
6574 HRESULT WINAPI
VarBstrFromR4(FLOAT fltIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6576 return VARIANT_BstrFromReal(fltIn
, lcid
, dwFlags
, pbstrOut
, szFloatFormatW
);
6579 /******************************************************************************
6580 * VarBstrFromR8 (OLEAUT32.112)
6582 * Convert a VT_R8 to a VT_BSTR.
6586 * lcid [I] LCID for the conversion
6587 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6588 * pbstrOut [O] Destination
6592 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6593 * E_OUTOFMEMORY, if memory allocation fails.
6595 HRESULT WINAPI
VarBstrFromR8(double dblIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6597 return VARIANT_BstrFromReal(dblIn
, lcid
, dwFlags
, pbstrOut
, szDoubleFormatW
);
6600 /******************************************************************************
6601 * VarBstrFromCy [OLEAUT32.113]
6603 * Convert a VT_CY to a VT_BSTR.
6607 * lcid [I] LCID for the conversion
6608 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6609 * pbstrOut [O] Destination
6613 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6614 * E_OUTOFMEMORY, if memory allocation fails.
6616 HRESULT WINAPI
VarBstrFromCy(CY cyIn
, LCID lcid
, ULONG dwFlags
, BSTR
*pbstrOut
)
6622 return E_INVALIDARG
;
6626 decVal
.bitsnum
[0] = cyIn
.s
.Lo
;
6627 decVal
.bitsnum
[1] = cyIn
.s
.Hi
;
6628 if (cyIn
.s
.Hi
& 0x80000000UL
) {
6631 /* Negative number! */
6633 decVal
.bitsnum
[0] = ~decVal
.bitsnum
[0];
6634 decVal
.bitsnum
[1] = ~decVal
.bitsnum
[1];
6635 VARIANT_int_add(decVal
.bitsnum
, 3, &one
, 1);
6637 decVal
.bitsnum
[2] = 0;
6638 VARIANT_DI_tostringW(&decVal
, buff
, sizeof(buff
)/sizeof(buff
[0]));
6640 if (dwFlags
& LOCALE_USE_NLS
)
6644 /* Format the currency for the locale */
6646 GetCurrencyFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
6647 buff
, NULL
, cybuff
, sizeof(cybuff
) / sizeof(WCHAR
));
6648 *pbstrOut
= SysAllocString(cybuff
);
6651 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
,lcid
,dwFlags
);
6653 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6656 static inline int output_int_len(int o
, int min_len
, WCHAR
*date
, int date_len
)
6660 if(min_len
>= date_len
)
6663 for(len
=0, tmp
=o
; tmp
; tmp
/=10) len
++;
6668 for(tmp
=min_len
-len
; tmp
>0; tmp
--)
6670 for(tmp
=len
; tmp
>0; tmp
--, o
/=10)
6671 date
[tmp
-1] = '0' + o
%10;
6672 return min_len
>len
? min_len
: len
;
6675 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6676 BOOL
get_date_format(LCID lcid
, DWORD flags
, const SYSTEMTIME
*st
,
6677 const WCHAR
*fmt
, WCHAR
*date
, int date_len
)
6679 static const LCTYPE dayname
[] = {
6680 LOCALE_SDAYNAME7
, LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
,
6681 LOCALE_SDAYNAME4
, LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
6683 static const LCTYPE sdayname
[] = {
6684 LOCALE_SABBREVDAYNAME7
, LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
,
6685 LOCALE_SABBREVDAYNAME3
, LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
,
6686 LOCALE_SABBREVDAYNAME6
6688 static const LCTYPE monthname
[] = {
6689 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
6690 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
6691 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
6693 static const LCTYPE smonthname
[] = {
6694 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
6695 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
6696 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
6697 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
6700 if(flags
& ~(LOCALE_NOUSEROVERRIDE
|VAR_DATEVALUEONLY
))
6701 FIXME("ignoring flags %x\n", flags
);
6702 flags
&= LOCALE_NOUSEROVERRIDE
;
6704 while(*fmt
&& date_len
) {
6712 while(*fmt
== *(fmt
+count
))
6720 count
= GetLocaleInfoW(lcid
, dayname
[st
->wDayOfWeek
] | flags
, date
, date_len
)-1;
6722 count
= GetLocaleInfoW(lcid
, sdayname
[st
->wDayOfWeek
] | flags
, date
, date_len
)-1;
6724 count
= output_int_len(st
->wDay
, count
, date
, date_len
);
6728 count
= GetLocaleInfoW(lcid
, monthname
[st
->wMonth
-1] | flags
, date
, date_len
)-1;
6730 count
= GetLocaleInfoW(lcid
, smonthname
[st
->wMonth
-1] | flags
, date
, date_len
)-1;
6732 count
= output_int_len(st
->wMonth
, count
, date
, date_len
);
6736 count
= output_int_len(st
->wYear
, 0, date
, date_len
);
6738 count
= output_int_len(st
->wYear
%100, count
, date
, date_len
);
6742 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6770 /******************************************************************************
6771 * VarBstrFromDate [OLEAUT32.114]
6773 * Convert a VT_DATE to a VT_BSTR.
6777 * lcid [I] LCID for the conversion
6778 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6779 * pbstrOut [O] Destination
6783 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6784 * E_OUTOFMEMORY, if memory allocation fails.
6786 HRESULT WINAPI
VarBstrFromDate(DATE dateIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6789 DWORD dwFormatFlags
= dwFlags
& LOCALE_NOUSEROVERRIDE
;
6790 WCHAR date
[128], fmt_buff
[80], *time
;
6792 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn
, lcid
, dwFlags
, pbstrOut
);
6794 if (!pbstrOut
|| !VariantTimeToSystemTime(dateIn
, &st
))
6795 return E_INVALIDARG
;
6799 if (dwFlags
& VAR_CALENDAR_THAI
)
6800 st
.wYear
+= 553; /* Use the Thai buddhist calendar year */
6801 else if (dwFlags
& (VAR_CALENDAR_HIJRI
|VAR_CALENDAR_GREGORIAN
))
6802 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6804 if (dwFlags
& LOCALE_USE_NLS
)
6805 dwFlags
&= ~(VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
);
6808 double whole
= dateIn
< 0 ? ceil(dateIn
) : floor(dateIn
);
6809 double partial
= dateIn
- whole
;
6812 dwFlags
|= VAR_TIMEVALUEONLY
;
6813 else if (partial
> -1e-12 && partial
< 1e-12)
6814 dwFlags
|= VAR_DATEVALUEONLY
;
6817 if (dwFlags
& VAR_TIMEVALUEONLY
)
6820 if (!GetLocaleInfoW(lcid
, LOCALE_SSHORTDATE
, fmt_buff
, sizeof(fmt_buff
)/sizeof(WCHAR
)) ||
6821 !get_date_format(lcid
, dwFlags
, &st
, fmt_buff
, date
, sizeof(date
)/sizeof(WCHAR
)))
6822 return E_INVALIDARG
;
6824 if (!(dwFlags
& VAR_DATEVALUEONLY
))
6826 time
= date
+ strlenW(date
);
6829 if (!GetTimeFormatW(lcid
, dwFormatFlags
, &st
, NULL
, time
,
6830 sizeof(date
)/sizeof(WCHAR
)-(time
-date
)))
6831 return E_INVALIDARG
;
6834 *pbstrOut
= SysAllocString(date
);
6836 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
6837 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6840 /******************************************************************************
6841 * VarBstrFromBool (OLEAUT32.116)
6843 * Convert a VT_BOOL to a VT_BSTR.
6847 * lcid [I] LCID for the conversion
6848 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6849 * pbstrOut [O] Destination
6853 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6854 * E_OUTOFMEMORY, if memory allocation fails.
6857 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6858 * localised text of "True" or "False". To convert a bool into a
6859 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6861 HRESULT WINAPI
VarBstrFromBool(VARIANT_BOOL boolIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6864 DWORD dwResId
= IDS_TRUE
;
6867 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn
, lcid
, dwFlags
, pbstrOut
);
6870 return E_INVALIDARG
;
6872 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6873 * for variant formatting */
6874 switch (dwFlags
& (VAR_LOCALBOOL
|VAR_BOOLONOFF
|VAR_BOOLYESNO
))
6885 lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
),SORT_DEFAULT
);
6888 lcid
= ConvertDefaultLocale(lcid
);
6889 langId
= LANGIDFROMLCID(lcid
);
6890 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
6891 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6893 if (boolIn
== VARIANT_FALSE
)
6894 dwResId
++; /* Use negative form */
6896 VarBstrFromBool_GetLocalised
:
6897 if (VARIANT_GetLocalisedText(langId
, dwResId
, szBuff
))
6899 *pbstrOut
= SysAllocString(szBuff
);
6900 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
6903 if (langId
!= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
6905 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
6906 goto VarBstrFromBool_GetLocalised
;
6909 /* Should never get here */
6910 WARN("Failed to load bool text!\n");
6911 return E_OUTOFMEMORY
;
6914 /******************************************************************************
6915 * VarBstrFromI1 (OLEAUT32.229)
6917 * Convert a VT_I1 to a VT_BSTR.
6921 * lcid [I] LCID for the conversion
6922 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6923 * pbstrOut [O] Destination
6927 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6928 * E_OUTOFMEMORY, if memory allocation fails.
6930 HRESULT WINAPI
VarBstrFromI1(signed char cIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6937 dwFlags
|= VAR_NEGATIVE
;
6939 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
6942 /******************************************************************************
6943 * VarBstrFromUI2 (OLEAUT32.230)
6945 * Convert a VT_UI2 to a VT_BSTR.
6949 * lcid [I] LCID for the conversion
6950 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6951 * pbstrOut [O] Destination
6955 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6956 * E_OUTOFMEMORY, if memory allocation fails.
6958 HRESULT WINAPI
VarBstrFromUI2(USHORT usIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6960 return VARIANT_BstrFromUInt(usIn
, lcid
, dwFlags
, pbstrOut
);
6963 /******************************************************************************
6964 * VarBstrFromUI4 (OLEAUT32.231)
6966 * Convert a VT_UI4 to a VT_BSTR.
6970 * lcid [I] LCID for the conversion
6971 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6972 * pbstrOut [O] Destination
6976 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6977 * E_OUTOFMEMORY, if memory allocation fails.
6979 HRESULT WINAPI
VarBstrFromUI4(ULONG ulIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
6981 return VARIANT_BstrFromUInt(ulIn
, lcid
, dwFlags
, pbstrOut
);
6984 /******************************************************************************
6985 * VarBstrFromDec (OLEAUT32.232)
6987 * Convert a VT_DECIMAL to a VT_BSTR.
6991 * lcid [I] LCID for the conversion
6992 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6993 * pbstrOut [O] Destination
6997 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6998 * E_OUTOFMEMORY, if memory allocation fails.
7000 HRESULT WINAPI
VarBstrFromDec(DECIMAL
* pDecIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7006 return E_INVALIDARG
;
7008 VARIANT_DIFromDec(pDecIn
, &temp
);
7009 VARIANT_DI_tostringW(&temp
, buff
, 256);
7011 if (dwFlags
& LOCALE_USE_NLS
)
7015 /* Format the number for the locale */
7017 GetNumberFormatW(lcid
, dwFlags
& LOCALE_NOUSEROVERRIDE
,
7018 buff
, NULL
, numbuff
, sizeof(numbuff
) / sizeof(WCHAR
));
7019 TRACE("created NLS string %s\n", debugstr_w(numbuff
));
7020 *pbstrOut
= SysAllocString(numbuff
);
7024 *pbstrOut
= VARIANT_BstrReplaceDecimal(buff
, lcid
, dwFlags
);
7027 TRACE("returning %s\n", debugstr_w(*pbstrOut
));
7028 return *pbstrOut
? S_OK
: E_OUTOFMEMORY
;
7031 /************************************************************************
7032 * VarBstrFromI8 (OLEAUT32.370)
7034 * Convert a VT_I8 to a VT_BSTR.
7038 * lcid [I] LCID for the conversion
7039 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7040 * pbstrOut [O] Destination
7044 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7045 * E_OUTOFMEMORY, if memory allocation fails.
7047 HRESULT WINAPI
VarBstrFromI8(LONG64 llIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7049 ULONG64 ul64
= llIn
;
7054 dwFlags
|= VAR_NEGATIVE
;
7056 return VARIANT_BstrFromUInt(ul64
, lcid
, dwFlags
, pbstrOut
);
7059 /************************************************************************
7060 * VarBstrFromUI8 (OLEAUT32.371)
7062 * Convert a VT_UI8 to a VT_BSTR.
7066 * lcid [I] LCID for the conversion
7067 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7068 * pbstrOut [O] Destination
7072 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7073 * E_OUTOFMEMORY, if memory allocation fails.
7075 HRESULT WINAPI
VarBstrFromUI8(ULONG64 ullIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7077 return VARIANT_BstrFromUInt(ullIn
, lcid
, dwFlags
, pbstrOut
);
7080 /************************************************************************
7081 * VarBstrFromDisp (OLEAUT32.115)
7083 * Convert a VT_DISPATCH to a BSTR.
7086 * pdispIn [I] Source
7087 * lcid [I] LCID for conversion
7088 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7089 * pbstrOut [O] Destination
7093 * Failure: E_INVALIDARG, if the source value is invalid
7094 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7096 HRESULT WINAPI
VarBstrFromDisp(IDispatch
* pdispIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
7098 return VARIANT_FromDisp(pdispIn
, lcid
, pbstrOut
, VT_BSTR
, dwFlags
);
7101 /**********************************************************************
7102 * VarBstrCat (OLEAUT32.313)
7104 * Concatenate two BSTR values.
7107 * pbstrLeft [I] Source
7108 * pbstrRight [I] Value to concatenate
7109 * pbstrOut [O] Destination
7113 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7114 * E_OUTOFMEMORY, if memory allocation fails.
7116 HRESULT WINAPI
VarBstrCat(BSTR pbstrLeft
, BSTR pbstrRight
, BSTR
*pbstrOut
)
7118 unsigned int lenLeft
, lenRight
;
7121 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
7122 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), pbstrOut
);
7125 return E_INVALIDARG
;
7127 /* use byte length here to properly handle ansi-allocated BSTRs */
7128 lenLeft
= pbstrLeft
? SysStringByteLen(pbstrLeft
) : 0;
7129 lenRight
= pbstrRight
? SysStringByteLen(pbstrRight
) : 0;
7131 *pbstrOut
= SysAllocStringByteLen(NULL
, lenLeft
+ lenRight
);
7133 return E_OUTOFMEMORY
;
7135 (*pbstrOut
)[0] = '\0';
7138 memcpy(*pbstrOut
, pbstrLeft
, lenLeft
);
7141 memcpy((CHAR
*)*pbstrOut
+ lenLeft
, pbstrRight
, lenRight
);
7143 TRACE("%s\n", debugstr_wn(*pbstrOut
, SysStringLen(*pbstrOut
)));
7147 /**********************************************************************
7148 * VarBstrCmp (OLEAUT32.314)
7150 * Compare two BSTR values.
7153 * pbstrLeft [I] Source
7154 * pbstrRight [I] Value to compare
7155 * lcid [I] LCID for the comparison
7156 * dwFlags [I] Flags to pass directly to CompareStringW().
7159 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7160 * than, equal to or greater than pbstrRight respectively.
7163 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7164 * states. A NULL BSTR pointer is equivalent to an empty string.
7165 * If LCID is equal to 0, a byte by byte comparison is performed.
7167 HRESULT WINAPI
VarBstrCmp(BSTR pbstrLeft
, BSTR pbstrRight
, LCID lcid
, DWORD dwFlags
)
7172 TRACE("%s,%s,%d,%08x\n",
7173 debugstr_wn(pbstrLeft
, SysStringLen(pbstrLeft
)),
7174 debugstr_wn(pbstrRight
, SysStringLen(pbstrRight
)), lcid
, dwFlags
);
7176 if (!pbstrLeft
|| !*pbstrLeft
)
7178 if (pbstrRight
&& *pbstrRight
)
7181 else if (!pbstrRight
|| !*pbstrRight
)
7186 unsigned int lenLeft
= SysStringByteLen(pbstrLeft
);
7187 unsigned int lenRight
= SysStringByteLen(pbstrRight
);
7188 ret
= memcmp(pbstrLeft
, pbstrRight
, min(lenLeft
, lenRight
));
7193 if (lenLeft
< lenRight
)
7195 if (lenLeft
> lenRight
)
7201 unsigned int lenLeft
= SysStringLen(pbstrLeft
);
7202 unsigned int lenRight
= SysStringLen(pbstrRight
);
7204 if (lenLeft
== 0 || lenRight
== 0)
7206 if (lenLeft
== 0 && lenRight
== 0) return VARCMP_EQ
;
7207 return lenLeft
< lenRight
? VARCMP_LT
: VARCMP_GT
;
7210 hres
= CompareStringW(lcid
, dwFlags
, pbstrLeft
, lenLeft
,
7211 pbstrRight
, lenRight
) - CSTR_LESS_THAN
;
7212 TRACE("%d\n", hres
);
7221 /******************************************************************************
7222 * VarDateFromUI1 (OLEAUT32.88)
7224 * Convert a VT_UI1 to a VT_DATE.
7228 * pdateOut [O] Destination
7233 HRESULT WINAPI
VarDateFromUI1(BYTE bIn
, DATE
* pdateOut
)
7235 return VarR8FromUI1(bIn
, pdateOut
);
7238 /******************************************************************************
7239 * VarDateFromI2 (OLEAUT32.89)
7241 * Convert a VT_I2 to a VT_DATE.
7245 * pdateOut [O] Destination
7250 HRESULT WINAPI
VarDateFromI2(short sIn
, DATE
* pdateOut
)
7252 return VarR8FromI2(sIn
, pdateOut
);
7255 /******************************************************************************
7256 * VarDateFromI4 (OLEAUT32.90)
7258 * Convert a VT_I4 to a VT_DATE.
7262 * pdateOut [O] Destination
7267 HRESULT WINAPI
VarDateFromI4(LONG lIn
, DATE
* pdateOut
)
7269 return VarDateFromR8(lIn
, pdateOut
);
7272 /******************************************************************************
7273 * VarDateFromR4 (OLEAUT32.91)
7275 * Convert a VT_R4 to a VT_DATE.
7279 * pdateOut [O] Destination
7284 HRESULT WINAPI
VarDateFromR4(FLOAT fltIn
, DATE
* pdateOut
)
7286 return VarR8FromR4(fltIn
, pdateOut
);
7289 /******************************************************************************
7290 * VarDateFromR8 (OLEAUT32.92)
7292 * Convert a VT_R8 to a VT_DATE.
7296 * pdateOut [O] Destination
7301 HRESULT WINAPI
VarDateFromR8(double dblIn
, DATE
* pdateOut
)
7303 if (dblIn
<= (DATE_MIN
- 1.0) || dblIn
>= (DATE_MAX
+ 1.0)) return DISP_E_OVERFLOW
;
7304 *pdateOut
= (DATE
)dblIn
;
7308 /**********************************************************************
7309 * VarDateFromDisp (OLEAUT32.95)
7311 * Convert a VT_DISPATCH to a VT_DATE.
7314 * pdispIn [I] Source
7315 * lcid [I] LCID for conversion
7316 * pdateOut [O] Destination
7320 * Failure: E_INVALIDARG, if the source value is invalid
7321 * DISP_E_OVERFLOW, if the value will not fit in the destination
7322 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7324 HRESULT WINAPI
VarDateFromDisp(IDispatch
* pdispIn
, LCID lcid
, DATE
* pdateOut
)
7326 return VARIANT_FromDisp(pdispIn
, lcid
, pdateOut
, VT_DATE
, 0);
7329 /******************************************************************************
7330 * VarDateFromBool (OLEAUT32.96)
7332 * Convert a VT_BOOL to a VT_DATE.
7336 * pdateOut [O] Destination
7341 HRESULT WINAPI
VarDateFromBool(VARIANT_BOOL boolIn
, DATE
* pdateOut
)
7343 return VarR8FromBool(boolIn
, pdateOut
);
7346 /**********************************************************************
7347 * VarDateFromCy (OLEAUT32.93)
7349 * Convert a VT_CY to a VT_DATE.
7353 * pdateOut [O] Destination
7358 HRESULT WINAPI
VarDateFromCy(CY cyIn
, DATE
* pdateOut
)
7360 return VarR8FromCy(cyIn
, pdateOut
);
7363 /* Date string parsing */
7364 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7365 #define DP_DATESEP 0x02 /* Date separator */
7366 #define DP_MONTH 0x04 /* Month name */
7367 #define DP_AM 0x08 /* AM */
7368 #define DP_PM 0x10 /* PM */
7370 typedef struct tagDATEPARSE
7372 DWORD dwCount
; /* Number of fields found so far (maximum 6) */
7373 DWORD dwParseFlags
; /* Global parse flags (DP_ Flags above) */
7374 DWORD dwFlags
[6]; /* Flags for each field */
7375 DWORD dwValues
[6]; /* Value of each field */
7378 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7380 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7382 /* Determine if a day is valid in a given month of a given year */
7383 static BOOL
VARIANT_IsValidMonthDay(DWORD day
, DWORD month
, DWORD year
)
7385 static const BYTE days
[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7387 if (day
&& month
&& month
< 13)
7389 if (day
<= days
[month
] || (month
== 2 && day
== 29 && IsLeapYear(year
)))
7395 /* Possible orders for 3 numbers making up a date */
7396 #define ORDER_MDY 0x01
7397 #define ORDER_YMD 0x02
7398 #define ORDER_YDM 0x04
7399 #define ORDER_DMY 0x08
7400 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7402 /* Determine a date for a particular locale, from 3 numbers */
7403 static inline HRESULT
VARIANT_MakeDate(DATEPARSE
*dp
, DWORD iDate
,
7404 DWORD offset
, SYSTEMTIME
*st
)
7406 DWORD dwAllOrders
, dwTry
, dwCount
= 0, v1
, v2
, v3
;
7410 v1
= 30; /* Default to (Variant) 0 date part */
7413 goto VARIANT_MakeDate_OK
;
7416 v1
= dp
->dwValues
[offset
+ 0];
7417 v2
= dp
->dwValues
[offset
+ 1];
7418 if (dp
->dwCount
== 2)
7421 GetSystemTime(¤t
);
7425 v3
= dp
->dwValues
[offset
+ 2];
7427 TRACE("(%d,%d,%d,%d,%d)\n", v1
, v2
, v3
, iDate
, offset
);
7429 /* If one number must be a month (Because a month name was given), then only
7430 * consider orders with the month in that position.
7431 * If we took the current year as 'v3', then only allow a year in that position.
7433 if (dp
->dwFlags
[offset
+ 0] & DP_MONTH
)
7435 dwAllOrders
= ORDER_MDY
;
7437 else if (dp
->dwFlags
[offset
+ 1] & DP_MONTH
)
7439 dwAllOrders
= ORDER_DMY
;
7440 if (dp
->dwCount
> 2)
7441 dwAllOrders
|= ORDER_YMD
;
7443 else if (dp
->dwCount
> 2 && dp
->dwFlags
[offset
+ 2] & DP_MONTH
)
7445 dwAllOrders
= ORDER_YDM
;
7449 dwAllOrders
= ORDER_MDY
|ORDER_DMY
;
7450 if (dp
->dwCount
> 2)
7451 dwAllOrders
|= (ORDER_YMD
|ORDER_YDM
);
7454 VARIANT_MakeDate_Start
:
7455 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders
);
7463 /* First: Try the order given by iDate */
7466 case 0: dwTry
= dwAllOrders
& ORDER_MDY
; break;
7467 case 1: dwTry
= dwAllOrders
& ORDER_DMY
; break;
7468 default: dwTry
= dwAllOrders
& ORDER_YMD
; break;
7471 else if (dwCount
== 1)
7473 /* Second: Try all the orders compatible with iDate */
7476 case 0: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7477 case 1: dwTry
= dwAllOrders
& ~(ORDER_MDY
|ORDER_YDM
|ORDER_MYD
); break;
7478 default: dwTry
= dwAllOrders
& ~(ORDER_DMY
|ORDER_YDM
); break;
7483 /* Finally: Try any remaining orders */
7484 dwTry
= dwAllOrders
;
7487 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount
, dwTry
);
7493 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7495 if (dwTry
& ORDER_MDY
)
7497 if (VARIANT_IsValidMonthDay(v2
,v1
,v3
))
7500 goto VARIANT_MakeDate_OK
;
7502 dwAllOrders
&= ~ORDER_MDY
;
7504 if (dwTry
& ORDER_YMD
)
7506 if (VARIANT_IsValidMonthDay(v3
,v2
,v1
))
7509 goto VARIANT_MakeDate_OK
;
7511 dwAllOrders
&= ~ORDER_YMD
;
7513 if (dwTry
& ORDER_YDM
)
7515 if (VARIANT_IsValidMonthDay(v2
,v3
,v1
))
7519 goto VARIANT_MakeDate_OK
;
7521 dwAllOrders
&= ~ORDER_YDM
;
7523 if (dwTry
& ORDER_DMY
)
7525 if (VARIANT_IsValidMonthDay(v1
,v2
,v3
))
7526 goto VARIANT_MakeDate_OK
;
7527 dwAllOrders
&= ~ORDER_DMY
;
7529 if (dwTry
& ORDER_MYD
)
7531 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7532 if (VARIANT_IsValidMonthDay(v3
,v1
,v2
))
7536 goto VARIANT_MakeDate_OK
;
7538 dwAllOrders
&= ~ORDER_MYD
;
7542 if (dp
->dwCount
== 2)
7544 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7545 v3
= 1; /* 1st of the month */
7546 dwAllOrders
= ORDER_YMD
|ORDER_MYD
;
7547 dp
->dwCount
= 0; /* Don't return to this code path again */
7549 goto VARIANT_MakeDate_Start
;
7552 /* No valid dates were able to be constructed */
7553 return DISP_E_TYPEMISMATCH
;
7555 VARIANT_MakeDate_OK
:
7557 /* Check that the time part is ok */
7558 if (st
->wHour
> 23 || st
->wMinute
> 59 || st
->wSecond
> 59)
7559 return DISP_E_TYPEMISMATCH
;
7561 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7562 if (st
->wHour
< 12 && (dp
->dwParseFlags
& DP_PM
))
7564 else if (st
->wHour
== 12 && (dp
->dwParseFlags
& DP_AM
))
7566 TRACE("Time %d %d %d\n", st
->wHour
, st
->wMinute
, st
->wSecond
);
7570 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7571 * be retrieved from:
7572 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7573 * But Wine doesn't have/use that key as at the time of writing.
7575 st
->wYear
= v3
< 30 ? 2000 + v3
: v3
< 100 ? 1900 + v3
: v3
;
7576 TRACE("Returning date %d/%d/%d\n", v1
, v2
, st
->wYear
);
7580 /******************************************************************************
7581 * VarDateFromStr [OLEAUT32.94]
7583 * Convert a VT_BSTR to at VT_DATE.
7586 * strIn [I] String to convert
7587 * lcid [I] Locale identifier for the conversion
7588 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7589 * pdateOut [O] Destination for the converted value
7592 * Success: S_OK. pdateOut contains the converted value.
7593 * FAILURE: An HRESULT error code indicating the problem.
7596 * Any date format that can be created using the date formats from lcid
7597 * (Either from kernel Nls functions, variant conversion or formatting) is a
7598 * valid input to this function. In addition, a few more esoteric formats are
7599 * also supported for compatibility with the native version. The date is
7600 * interpreted according to the date settings in the control panel, unless
7601 * the date is invalid in that format, in which the most compatible format
7602 * that produces a valid date will be used.
7604 HRESULT WINAPI
VarDateFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DATE
* pdateOut
)
7606 static const USHORT ParseDateTokens
[] =
7608 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
7609 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
7610 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
,
7611 LOCALE_SMONTHNAME13
,
7612 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
7613 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
7614 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
7615 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
,
7616 LOCALE_SABBREVMONTHNAME13
,
7617 LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
, LOCALE_SDAYNAME4
,
7618 LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
, LOCALE_SDAYNAME7
,
7619 LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
, LOCALE_SABBREVDAYNAME3
,
7620 LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
, LOCALE_SABBREVDAYNAME6
,
7621 LOCALE_SABBREVDAYNAME7
,
7622 LOCALE_S1159
, LOCALE_S2359
,
7625 static const BYTE ParseDateMonths
[] =
7627 1,2,3,4,5,6,7,8,9,10,11,12,13,
7628 1,2,3,4,5,6,7,8,9,10,11,12,13
7631 BSTR tokens
[sizeof(ParseDateTokens
)/sizeof(ParseDateTokens
[0])];
7633 DWORD dwDateSeps
= 0, iDate
= 0;
7634 HRESULT hRet
= S_OK
;
7636 if ((dwFlags
& (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
)) ==
7637 (VAR_TIMEVALUEONLY
|VAR_DATEVALUEONLY
))
7638 return E_INVALIDARG
;
7641 return DISP_E_TYPEMISMATCH
;
7645 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn
), lcid
, dwFlags
, pdateOut
);
7647 memset(&dp
, 0, sizeof(dp
));
7649 GetLocaleInfoW(lcid
, LOCALE_IDATE
|LOCALE_RETURN_NUMBER
|(dwFlags
& LOCALE_NOUSEROVERRIDE
),
7650 (LPWSTR
)&iDate
, sizeof(iDate
)/sizeof(WCHAR
));
7651 TRACE("iDate is %d\n", iDate
);
7653 /* Get the month/day/am/pm tokens for this locale */
7654 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7657 LCTYPE lctype
= ParseDateTokens
[i
] | (dwFlags
& LOCALE_NOUSEROVERRIDE
);
7659 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7660 * GetAltMonthNames(). We should really cache these strings too.
7663 GetLocaleInfoW(lcid
, lctype
, buff
, sizeof(buff
)/sizeof(WCHAR
));
7664 tokens
[i
] = SysAllocString(buff
);
7665 TRACE("token %d is %s\n", i
, debugstr_w(tokens
[i
]));
7668 /* Parse the string into our structure */
7671 if (isdigitW(*strIn
))
7673 if (dp
.dwCount
>= 6)
7675 hRet
= DISP_E_TYPEMISMATCH
;
7678 dp
.dwValues
[dp
.dwCount
] = strtoulW(strIn
, &strIn
, 10);
7682 else if (isalpha(*strIn
))
7684 BOOL bFound
= FALSE
;
7686 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7688 DWORD dwLen
= strlenW(tokens
[i
]);
7689 if (dwLen
&& !strncmpiW(strIn
, tokens
[i
], dwLen
))
7693 if (dp
.dwCount
>= 6)
7694 hRet
= DISP_E_TYPEMISMATCH
;
7697 dp
.dwValues
[dp
.dwCount
] = ParseDateMonths
[i
];
7698 dp
.dwFlags
[dp
.dwCount
] |= (DP_MONTH
|DP_DATESEP
);
7702 else if (i
> 39 && i
< 42)
7704 if (!dp
.dwCount
|| dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7705 hRet
= DISP_E_TYPEMISMATCH
;
7708 dp
.dwFlags
[dp
.dwCount
- 1] |= (i
== 40 ? DP_AM
: DP_PM
);
7709 dp
.dwParseFlags
|= (i
== 40 ? DP_AM
: DP_PM
);
7712 strIn
+= (dwLen
- 1);
7720 if ((*strIn
== 'a' || *strIn
== 'A' || *strIn
== 'p' || *strIn
== 'P') &&
7721 (dp
.dwCount
&& !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7723 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7724 if (*strIn
== 'a' || *strIn
== 'A')
7726 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_AM
;
7727 dp
.dwParseFlags
|= DP_AM
;
7731 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_PM
;
7732 dp
.dwParseFlags
|= DP_PM
;
7738 TRACE("No matching token for %s\n", debugstr_w(strIn
));
7739 hRet
= DISP_E_TYPEMISMATCH
;
7744 else if (*strIn
== ':' || *strIn
== '.')
7746 if (!dp
.dwCount
|| !strIn
[1])
7747 hRet
= DISP_E_TYPEMISMATCH
;
7749 if (tokens
[42][0] == *strIn
)
7753 hRet
= DISP_E_TYPEMISMATCH
;
7755 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7758 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_TIMESEP
;
7760 else if (*strIn
== '-' || *strIn
== '/')
7763 if (dwDateSeps
> 2 || !dp
.dwCount
|| !strIn
[1])
7764 hRet
= DISP_E_TYPEMISMATCH
;
7766 dp
.dwFlags
[dp
.dwCount
- 1] |= DP_DATESEP
;
7768 else if (*strIn
== ',' || isspaceW(*strIn
))
7770 if (*strIn
== ',' && !strIn
[1])
7771 hRet
= DISP_E_TYPEMISMATCH
;
7775 hRet
= DISP_E_TYPEMISMATCH
;
7780 if (!dp
.dwCount
|| dp
.dwCount
> 6 ||
7781 (dp
.dwCount
== 1 && !(dp
.dwParseFlags
& (DP_AM
|DP_PM
))))
7782 hRet
= DISP_E_TYPEMISMATCH
;
7784 if (SUCCEEDED(hRet
))
7787 DWORD dwOffset
= 0; /* Start of date fields in dp.dwValues */
7789 st
.wDayOfWeek
= st
.wHour
= st
.wMinute
= st
.wSecond
= st
.wMilliseconds
= 0;
7791 /* Figure out which numbers correspond to which fields.
7793 * This switch statement works based on the fact that native interprets any
7794 * fields that are not joined with a time separator ('.' or ':') as date
7795 * fields. Thus we construct a value from 0-32 where each set bit indicates
7796 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7797 * For valid permutations, we set dwOffset to point to the first date field
7798 * and shorten dp.dwCount by the number of time fields found. The real
7799 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7800 * each date number must represent in the context of iDate.
7802 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7804 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7806 case 0x1: /* TT TTDD TTDDD */
7807 if (dp
.dwCount
> 3 &&
7808 ((dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) ||
7809 (dp
.dwFlags
[4] & (DP_AM
|DP_PM
))))
7810 hRet
= DISP_E_TYPEMISMATCH
;
7811 else if (dp
.dwCount
!= 2 && dp
.dwCount
!= 4 && dp
.dwCount
!= 5)
7812 hRet
= DISP_E_TYPEMISMATCH
;
7813 st
.wHour
= dp
.dwValues
[0];
7814 st
.wMinute
= dp
.dwValues
[1];
7819 case 0x3: /* TTT TTTDD TTTDDD */
7820 if (dp
.dwCount
> 4 &&
7821 ((dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[4] & (DP_AM
|DP_PM
)) ||
7822 (dp
.dwFlags
[5] & (DP_AM
|DP_PM
))))
7823 hRet
= DISP_E_TYPEMISMATCH
;
7824 else if (dp
.dwCount
!= 3 && dp
.dwCount
!= 5 && dp
.dwCount
!= 6)
7825 hRet
= DISP_E_TYPEMISMATCH
;
7826 st
.wHour
= dp
.dwValues
[0];
7827 st
.wMinute
= dp
.dwValues
[1];
7828 st
.wSecond
= dp
.dwValues
[2];
7833 case 0x4: /* DDTT */
7834 if (dp
.dwCount
!= 4 ||
7835 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7836 hRet
= DISP_E_TYPEMISMATCH
;
7838 st
.wHour
= dp
.dwValues
[2];
7839 st
.wMinute
= dp
.dwValues
[3];
7843 case 0x0: /* T DD DDD TDDD TDDD */
7844 if (dp
.dwCount
== 1 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7846 st
.wHour
= dp
.dwValues
[0]; /* T */
7850 else if (dp
.dwCount
> 4 || (dp
.dwCount
< 3 && dp
.dwParseFlags
& (DP_AM
|DP_PM
)))
7852 hRet
= DISP_E_TYPEMISMATCH
;
7854 else if (dp
.dwCount
== 3)
7856 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDD */
7859 st
.wHour
= dp
.dwValues
[0];
7863 if (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)) /* DDT */
7866 st
.wHour
= dp
.dwValues
[2];
7869 else if (dp
.dwParseFlags
& (DP_AM
|DP_PM
))
7870 hRet
= DISP_E_TYPEMISMATCH
;
7872 else if (dp
.dwCount
== 4)
7875 if (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) /* TDDD */
7877 st
.wHour
= dp
.dwValues
[0];
7880 else if (dp
.dwFlags
[3] & (DP_AM
|DP_PM
)) /* DDDT */
7882 st
.wHour
= dp
.dwValues
[3];
7885 hRet
= DISP_E_TYPEMISMATCH
;
7888 /* .. fall through .. */
7890 case 0x8: /* DDDTT */
7891 if ((dp
.dwCount
== 2 && (dp
.dwParseFlags
& (DP_AM
|DP_PM
))) ||
7892 (dp
.dwCount
== 5 && ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) ||
7893 (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))) ||
7894 dp
.dwCount
== 4 || dp
.dwCount
== 6)
7895 hRet
= DISP_E_TYPEMISMATCH
;
7896 st
.wHour
= dp
.dwValues
[3];
7897 st
.wMinute
= dp
.dwValues
[4];
7898 if (dp
.dwCount
== 5)
7902 case 0xC: /* DDTTT */
7903 if (dp
.dwCount
!= 5 ||
7904 (dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)))
7905 hRet
= DISP_E_TYPEMISMATCH
;
7906 st
.wHour
= dp
.dwValues
[2];
7907 st
.wMinute
= dp
.dwValues
[3];
7908 st
.wSecond
= dp
.dwValues
[4];
7912 case 0x18: /* DDDTTT */
7913 if ((dp
.dwFlags
[0] & (DP_AM
|DP_PM
)) || (dp
.dwFlags
[1] & (DP_AM
|DP_PM
)) ||
7914 (dp
.dwFlags
[2] & (DP_AM
|DP_PM
)))
7915 hRet
= DISP_E_TYPEMISMATCH
;
7916 st
.wHour
= dp
.dwValues
[3];
7917 st
.wMinute
= dp
.dwValues
[4];
7918 st
.wSecond
= dp
.dwValues
[5];
7923 hRet
= DISP_E_TYPEMISMATCH
;
7927 if (SUCCEEDED(hRet
))
7929 hRet
= VARIANT_MakeDate(&dp
, iDate
, dwOffset
, &st
);
7931 if (dwFlags
& VAR_TIMEVALUEONLY
)
7937 else if (dwFlags
& VAR_DATEVALUEONLY
)
7938 st
.wHour
= st
.wMinute
= st
.wSecond
= 0;
7940 /* Finally, convert the value to a VT_DATE */
7941 if (SUCCEEDED(hRet
))
7942 hRet
= SystemTimeToVariantTime(&st
, pdateOut
) ? S_OK
: DISP_E_TYPEMISMATCH
;
7946 for (i
= 0; i
< sizeof(tokens
)/sizeof(tokens
[0]); i
++)
7947 SysFreeString(tokens
[i
]);
7951 /******************************************************************************
7952 * VarDateFromI1 (OLEAUT32.221)
7954 * Convert a VT_I1 to a VT_DATE.
7958 * pdateOut [O] Destination
7963 HRESULT WINAPI
VarDateFromI1(signed char cIn
, DATE
* pdateOut
)
7965 return VarR8FromI1(cIn
, pdateOut
);
7968 /******************************************************************************
7969 * VarDateFromUI2 (OLEAUT32.222)
7971 * Convert a VT_UI2 to a VT_DATE.
7975 * pdateOut [O] Destination
7980 HRESULT WINAPI
VarDateFromUI2(USHORT uiIn
, DATE
* pdateOut
)
7982 return VarR8FromUI2(uiIn
, pdateOut
);
7985 /******************************************************************************
7986 * VarDateFromUI4 (OLEAUT32.223)
7988 * Convert a VT_UI4 to a VT_DATE.
7992 * pdateOut [O] Destination
7997 HRESULT WINAPI
VarDateFromUI4(ULONG ulIn
, DATE
* pdateOut
)
7999 return VarDateFromR8(ulIn
, pdateOut
);
8002 /**********************************************************************
8003 * VarDateFromDec (OLEAUT32.224)
8005 * Convert a VT_DECIMAL to a VT_DATE.
8009 * pdateOut [O] Destination
8014 HRESULT WINAPI
VarDateFromDec(DECIMAL
*pdecIn
, DATE
* pdateOut
)
8016 return VarR8FromDec(pdecIn
, pdateOut
);
8019 /******************************************************************************
8020 * VarDateFromI8 (OLEAUT32.364)
8022 * Convert a VT_I8 to a VT_DATE.
8026 * pdateOut [O] Destination
8030 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8032 HRESULT WINAPI
VarDateFromI8(LONG64 llIn
, DATE
* pdateOut
)
8034 if (llIn
< DATE_MIN
|| llIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
8035 *pdateOut
= (DATE
)llIn
;
8039 /******************************************************************************
8040 * VarDateFromUI8 (OLEAUT32.365)
8042 * Convert a VT_UI8 to a VT_DATE.
8046 * pdateOut [O] Destination
8050 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8052 HRESULT WINAPI
VarDateFromUI8(ULONG64 ullIn
, DATE
* pdateOut
)
8054 if (ullIn
> DATE_MAX
) return DISP_E_OVERFLOW
;
8055 *pdateOut
= (DATE
)ullIn
;