advapi32/tests: Allow ERROR_ACCESS_DENIED for newer Win10.
[wine.git] / dlls / oleaut32 / vartype.c
blobe2df87328c9b9ce2ede6b047c26b05aa915c7a01
1 /*
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
21 #define COBJMACROS
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
25 #include "wine/debug.h"
26 #include "wine/unicode.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winnt.h"
30 #include "variant.h"
31 #include "resource.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)
48 switch (vt)
50 case VT_I1:
51 case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
52 case VT_BOOL:
53 case VT_I2:
54 case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
55 case VT_R4:
56 case VT_INT:
57 case VT_I4:
58 case VT_UINT:
59 case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
60 case VT_R8:
61 case VT_DATE:
62 case VT_CY:
63 case VT_I8:
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;
68 default:
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; \
85 } while(0)
88 /* Coerce VT_BSTR to a numeric type */
89 static HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
90 void* pOut, VARTYPE vt)
92 VARIANTARG dstVar;
93 HRESULT hRet;
94 NUMPARSE np;
95 BYTE rgb[1024];
97 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
98 np.cDig = ARRAY_SIZE(rgb);
99 np.dwInFlags = NUMPRS_STD;
101 hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
103 if (SUCCEEDED(hRet))
105 /* 1 << vt gives us the VTBIT constant for the destination number type */
106 hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
107 if (SUCCEEDED(hRet))
108 VARIANT_CopyData(&dstVar, vt, pOut);
110 return hRet;
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;
119 HRESULT hRet;
121 if (!pdispIn)
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);
129 if (SUCCEEDED(hRet))
131 /* Convert the property to the requested type */
132 VariantInit(&dstVar);
133 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt);
134 VariantClear(&srcVar);
136 if (SUCCEEDED(hRet))
137 VARIANT_CopyData(&dstVar, vt, pOut);
139 else
140 hRet = DISP_E_TYPEMISMATCH;
141 return hRet;
144 /* Inline return type */
145 #define RETTYP static inline HRESULT
148 /* Simple compiler cast from one type to another */
149 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
150 *out = in; return S_OK; }
152 /* Compiler cast where input cannot be negative */
153 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
154 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
156 /* Compiler cast where input cannot be > some number */
157 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
158 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
160 /* Compiler cast where input cannot be < some number or >= some other number */
161 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
162 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
164 /* I1 */
165 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX)
166 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX)
167 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX)
168 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool)
169 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX)
170 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX)
171 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX)
172 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX)
174 /* UI1 */
175 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX)
176 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool)
177 NEGTST(BYTE, signed char, VarUI1FromI1)
178 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX)
179 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX)
180 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX)
181 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX)
182 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX)
184 /* I2 */
185 SIMPLE(SHORT, BYTE, VarI2FromUI1)
186 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX)
187 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool)
188 SIMPLE(SHORT, signed char, VarI2FromI1)
189 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX)
190 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX)
191 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX)
192 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX)
194 /* UI2 */
195 SIMPLE(USHORT, BYTE, VarUI2FromUI1)
196 NEGTST(USHORT, SHORT, VarUI2FromI2)
197 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX)
198 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool)
199 NEGTST(USHORT, signed char, VarUI2FromI1)
200 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX)
201 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX)
202 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX)
204 /* I4 */
205 SIMPLE(LONG, BYTE, VarI4FromUI1)
206 SIMPLE(LONG, SHORT, VarI4FromI2)
207 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool)
208 SIMPLE(LONG, signed char, VarI4FromI1)
209 SIMPLE(LONG, USHORT, VarI4FromUI2)
210 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX)
211 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX)
212 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX)
214 /* UI4 */
215 SIMPLE(ULONG, BYTE, VarUI4FromUI1)
216 NEGTST(ULONG, SHORT, VarUI4FromI2)
217 NEGTST(ULONG, LONG, VarUI4FromI4)
218 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool)
219 NEGTST(ULONG, signed char, VarUI4FromI1)
220 SIMPLE(ULONG, USHORT, VarUI4FromUI2)
221 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX)
222 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX)
224 /* I8 */
225 SIMPLE(LONG64, BYTE, VarI8FromUI1)
226 SIMPLE(LONG64, SHORT, VarI8FromI2)
227 SIMPLE(LONG64, signed char, VarI8FromI1)
228 SIMPLE(LONG64, USHORT, VarI8FromUI2)
229 SIMPLE(LONG64, ULONG, VarI8FromUI4)
230 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX)
232 /* UI8 */
233 SIMPLE(ULONG64, BYTE, VarUI8FromUI1)
234 NEGTST(ULONG64, SHORT, VarUI8FromI2)
235 NEGTST(ULONG64, signed char, VarUI8FromI1)
236 SIMPLE(ULONG64, USHORT, VarUI8FromUI2)
237 SIMPLE(ULONG64, ULONG, VarUI8FromUI4)
238 NEGTST(ULONG64, LONG64, VarUI8FromI8)
240 /* R4 (float) */
241 SIMPLE(float, BYTE, VarR4FromUI1)
242 SIMPLE(float, SHORT, VarR4FromI2)
243 SIMPLE(float, signed char, VarR4FromI1)
244 SIMPLE(float, USHORT, VarR4FromUI2)
245 SIMPLE(float, LONG, VarR4FromI4)
246 SIMPLE(float, ULONG, VarR4FromUI4)
247 SIMPLE(float, LONG64, VarR4FromI8)
248 SIMPLE(float, ULONG64, VarR4FromUI8)
250 /* R8 (double) */
251 SIMPLE(double, BYTE, VarR8FromUI1)
252 SIMPLE(double, SHORT, VarR8FromI2)
253 SIMPLE(double, float, VarR8FromR4)
254 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
255 SIMPLE(double, DATE, VarR8FromDate)
256 SIMPLE(double, signed char, VarR8FromI1)
257 SIMPLE(double, USHORT, VarR8FromUI2)
258 SIMPLE(double, LONG, VarR8FromI4)
259 SIMPLE(double, ULONG, VarR8FromUI4)
260 SIMPLE(double, LONG64, VarR8FromI8)
261 SIMPLE(double, ULONG64, VarR8FromUI8)
264 /* I1
267 /************************************************************************
268 * VarI1FromUI1 (OLEAUT32.244)
270 * Convert a VT_UI1 to a VT_I1.
272 * PARAMS
273 * bIn [I] Source
274 * pcOut [O] Destination
276 * RETURNS
277 * Success: S_OK.
278 * Failure: E_INVALIDARG, if the source value is invalid
279 * DISP_E_OVERFLOW, if the value will not fit in the destination
281 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
283 return _VarI1FromUI1(bIn, pcOut);
286 /************************************************************************
287 * VarI1FromI2 (OLEAUT32.245)
289 * Convert a VT_I2 to a VT_I1.
291 * PARAMS
292 * sIn [I] Source
293 * pcOut [O] Destination
295 * RETURNS
296 * Success: S_OK.
297 * Failure: E_INVALIDARG, if the source value is invalid
298 * DISP_E_OVERFLOW, if the value will not fit in the destination
300 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
302 return _VarI1FromI2(sIn, pcOut);
305 /************************************************************************
306 * VarI1FromI4 (OLEAUT32.246)
308 * Convert a VT_I4 to a VT_I1.
310 * PARAMS
311 * iIn [I] Source
312 * pcOut [O] Destination
314 * RETURNS
315 * Success: S_OK.
316 * Failure: E_INVALIDARG, if the source value is invalid
317 * DISP_E_OVERFLOW, if the value will not fit in the destination
319 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
321 return _VarI1FromI4(iIn, pcOut);
324 /************************************************************************
325 * VarI1FromR4 (OLEAUT32.247)
327 * Convert a VT_R4 to a VT_I1.
329 * PARAMS
330 * fltIn [I] Source
331 * pcOut [O] Destination
333 * RETURNS
334 * Success: S_OK.
335 * Failure: E_INVALIDARG, if the source value is invalid
336 * DISP_E_OVERFLOW, if the value will not fit in the destination
338 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
340 return VarI1FromR8(fltIn, pcOut);
343 /************************************************************************
344 * VarI1FromR8 (OLEAUT32.248)
346 * Convert a VT_R8 to a VT_I1.
348 * PARAMS
349 * dblIn [I] Source
350 * pcOut [O] Destination
352 * RETURNS
353 * Success: S_OK.
354 * Failure: E_INVALIDARG, if the source value is invalid
355 * DISP_E_OVERFLOW, if the value will not fit in the destination
357 * NOTES
358 * See VarI8FromR8() for details concerning rounding.
360 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
362 if (dblIn < I1_MIN - 0.5 || dblIn >= I1_MAX + 0.5)
363 return DISP_E_OVERFLOW;
364 VARIANT_DutchRound(CHAR, dblIn, *pcOut);
365 return S_OK;
368 /************************************************************************
369 * VarI1FromDate (OLEAUT32.249)
371 * Convert a VT_DATE to a VT_I1.
373 * PARAMS
374 * dateIn [I] Source
375 * pcOut [O] Destination
377 * RETURNS
378 * Success: S_OK.
379 * Failure: E_INVALIDARG, if the source value is invalid
380 * DISP_E_OVERFLOW, if the value will not fit in the destination
382 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
384 return VarI1FromR8(dateIn, pcOut);
387 /************************************************************************
388 * VarI1FromCy (OLEAUT32.250)
390 * Convert a VT_CY to a VT_I1.
392 * PARAMS
393 * cyIn [I] Source
394 * pcOut [O] Destination
396 * RETURNS
397 * Success: S_OK.
398 * Failure: E_INVALIDARG, if the source value is invalid
399 * DISP_E_OVERFLOW, if the value will not fit in the destination
401 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
403 LONG i = I1_MAX + 1;
405 VarI4FromCy(cyIn, &i);
406 return _VarI1FromI4(i, pcOut);
409 /************************************************************************
410 * VarI1FromStr (OLEAUT32.251)
412 * Convert a VT_BSTR to a VT_I1.
414 * PARAMS
415 * strIn [I] Source
416 * lcid [I] LCID for the conversion
417 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
418 * pcOut [O] Destination
420 * RETURNS
421 * Success: S_OK.
422 * Failure: E_INVALIDARG, if the source value is invalid
423 * DISP_E_OVERFLOW, if the value will not fit in the destination
424 * DISP_E_TYPEMISMATCH, if the type cannot be converted
426 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
428 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
431 /************************************************************************
432 * VarI1FromDisp (OLEAUT32.252)
434 * Convert a VT_DISPATCH to a VT_I1.
436 * PARAMS
437 * pdispIn [I] Source
438 * lcid [I] LCID for conversion
439 * pcOut [O] Destination
441 * RETURNS
442 * Success: S_OK.
443 * Failure: E_INVALIDARG, if the source value is invalid
444 * DISP_E_OVERFLOW, if the value will not fit in the destination
445 * DISP_E_TYPEMISMATCH, if the type cannot be converted
447 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
449 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0);
452 /************************************************************************
453 * VarI1FromBool (OLEAUT32.253)
455 * Convert a VT_BOOL to a VT_I1.
457 * PARAMS
458 * boolIn [I] Source
459 * pcOut [O] Destination
461 * RETURNS
462 * S_OK.
464 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
466 return _VarI1FromBool(boolIn, pcOut);
469 /************************************************************************
470 * VarI1FromUI2 (OLEAUT32.254)
472 * Convert a VT_UI2 to a VT_I1.
474 * PARAMS
475 * usIn [I] Source
476 * pcOut [O] Destination
478 * RETURNS
479 * Success: S_OK.
480 * Failure: E_INVALIDARG, if the source value is invalid
481 * DISP_E_OVERFLOW, if the value will not fit in the destination
483 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
485 return _VarI1FromUI2(usIn, pcOut);
488 /************************************************************************
489 * VarI1FromUI4 (OLEAUT32.255)
491 * Convert a VT_UI4 to a VT_I1.
493 * PARAMS
494 * ulIn [I] Source
495 * pcOut [O] Destination
497 * RETURNS
498 * Success: S_OK.
499 * Failure: E_INVALIDARG, if the source value is invalid
500 * DISP_E_OVERFLOW, if the value will not fit in the destination
501 * DISP_E_TYPEMISMATCH, if the type cannot be converted
503 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
505 return _VarI1FromUI4(ulIn, pcOut);
508 /************************************************************************
509 * VarI1FromDec (OLEAUT32.256)
511 * Convert a VT_DECIMAL to a VT_I1.
513 * PARAMS
514 * pDecIn [I] Source
515 * pcOut [O] Destination
517 * RETURNS
518 * Success: S_OK.
519 * Failure: E_INVALIDARG, if the source value is invalid
520 * DISP_E_OVERFLOW, if the value will not fit in the destination
522 HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut)
524 LONG64 i64;
525 HRESULT hRet;
527 hRet = VarI8FromDec(pdecIn, &i64);
529 if (SUCCEEDED(hRet))
530 hRet = _VarI1FromI8(i64, pcOut);
531 return hRet;
534 /************************************************************************
535 * VarI1FromI8 (OLEAUT32.376)
537 * Convert a VT_I8 to a VT_I1.
539 * PARAMS
540 * llIn [I] Source
541 * pcOut [O] Destination
543 * RETURNS
544 * Success: S_OK.
545 * Failure: E_INVALIDARG, if the source value is invalid
546 * DISP_E_OVERFLOW, if the value will not fit in the destination
548 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
550 return _VarI1FromI8(llIn, pcOut);
553 /************************************************************************
554 * VarI1FromUI8 (OLEAUT32.377)
556 * Convert a VT_UI8 to a VT_I1.
558 * PARAMS
559 * ullIn [I] Source
560 * pcOut [O] Destination
562 * RETURNS
563 * Success: S_OK.
564 * Failure: E_INVALIDARG, if the source value is invalid
565 * DISP_E_OVERFLOW, if the value will not fit in the destination
567 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
569 return _VarI1FromUI8(ullIn, pcOut);
572 /* UI1
575 /************************************************************************
576 * VarUI1FromI2 (OLEAUT32.130)
578 * Convert a VT_I2 to a VT_UI1.
580 * PARAMS
581 * sIn [I] Source
582 * pbOut [O] Destination
584 * RETURNS
585 * Success: S_OK.
586 * Failure: E_INVALIDARG, if the source value is invalid
587 * DISP_E_OVERFLOW, if the value will not fit in the destination
589 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
591 return _VarUI1FromI2(sIn, pbOut);
594 /************************************************************************
595 * VarUI1FromI4 (OLEAUT32.131)
597 * Convert a VT_I4 to a VT_UI1.
599 * PARAMS
600 * iIn [I] Source
601 * pbOut [O] Destination
603 * RETURNS
604 * Success: S_OK.
605 * Failure: E_INVALIDARG, if the source value is invalid
606 * DISP_E_OVERFLOW, if the value will not fit in the destination
608 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
610 return _VarUI1FromI4(iIn, pbOut);
613 /************************************************************************
614 * VarUI1FromR4 (OLEAUT32.132)
616 * Convert a VT_R4 to a VT_UI1.
618 * PARAMS
619 * fltIn [I] Source
620 * pbOut [O] Destination
622 * RETURNS
623 * Success: S_OK.
624 * Failure: E_INVALIDARG, if the source value is invalid
625 * DISP_E_OVERFLOW, if the value will not fit in the destination
626 * DISP_E_TYPEMISMATCH, if the type cannot be converted
628 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
630 return VarUI1FromR8(fltIn, pbOut);
633 /************************************************************************
634 * VarUI1FromR8 (OLEAUT32.133)
636 * Convert a VT_R8 to a VT_UI1.
638 * PARAMS
639 * dblIn [I] Source
640 * pbOut [O] Destination
642 * RETURNS
643 * Success: S_OK.
644 * Failure: E_INVALIDARG, if the source value is invalid
645 * DISP_E_OVERFLOW, if the value will not fit in the destination
647 * NOTES
648 * See VarI8FromR8() for details concerning rounding.
650 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
652 if (dblIn < -0.5 || dblIn >= UI1_MAX + 0.5)
653 return DISP_E_OVERFLOW;
654 VARIANT_DutchRound(BYTE, dblIn, *pbOut);
655 return S_OK;
658 /************************************************************************
659 * VarUI1FromCy (OLEAUT32.134)
661 * Convert a VT_CY to a VT_UI1.
663 * PARAMS
664 * cyIn [I] Source
665 * pbOut [O] Destination
667 * RETURNS
668 * Success: S_OK.
669 * Failure: E_INVALIDARG, if the source value is invalid
670 * DISP_E_OVERFLOW, if the value will not fit in the destination
672 * NOTES
673 * Negative values >= -5000 will be converted to 0.
675 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
677 ULONG i = UI1_MAX + 1;
679 VarUI4FromCy(cyIn, &i);
680 return _VarUI1FromUI4(i, pbOut);
683 /************************************************************************
684 * VarUI1FromDate (OLEAUT32.135)
686 * Convert a VT_DATE to a VT_UI1.
688 * PARAMS
689 * dateIn [I] Source
690 * pbOut [O] Destination
692 * RETURNS
693 * Success: S_OK.
694 * Failure: E_INVALIDARG, if the source value is invalid
695 * DISP_E_OVERFLOW, if the value will not fit in the destination
697 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
699 return VarUI1FromR8(dateIn, pbOut);
702 /************************************************************************
703 * VarUI1FromStr (OLEAUT32.136)
705 * Convert a VT_BSTR to a VT_UI1.
707 * PARAMS
708 * strIn [I] Source
709 * lcid [I] LCID for the conversion
710 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
711 * pbOut [O] Destination
713 * RETURNS
714 * Success: S_OK.
715 * Failure: E_INVALIDARG, if the source value is invalid
716 * DISP_E_OVERFLOW, if the value will not fit in the destination
717 * DISP_E_TYPEMISMATCH, if the type cannot be converted
719 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
721 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
724 /************************************************************************
725 * VarUI1FromDisp (OLEAUT32.137)
727 * Convert a VT_DISPATCH to a VT_UI1.
729 * PARAMS
730 * pdispIn [I] Source
731 * lcid [I] LCID for conversion
732 * pbOut [O] Destination
734 * RETURNS
735 * Success: S_OK.
736 * Failure: E_INVALIDARG, if the source value is invalid
737 * DISP_E_OVERFLOW, if the value will not fit in the destination
738 * DISP_E_TYPEMISMATCH, if the type cannot be converted
740 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
742 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0);
745 /************************************************************************
746 * VarUI1FromBool (OLEAUT32.138)
748 * Convert a VT_BOOL to a VT_UI1.
750 * PARAMS
751 * boolIn [I] Source
752 * pbOut [O] Destination
754 * RETURNS
755 * S_OK.
757 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
759 return _VarUI1FromBool(boolIn, pbOut);
762 /************************************************************************
763 * VarUI1FromI1 (OLEAUT32.237)
765 * Convert a VT_I1 to a VT_UI1.
767 * PARAMS
768 * cIn [I] Source
769 * pbOut [O] Destination
771 * RETURNS
772 * Success: S_OK.
773 * Failure: E_INVALIDARG, if the source value is invalid
774 * DISP_E_OVERFLOW, if the value will not fit in the destination
776 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
778 return _VarUI1FromI1(cIn, pbOut);
781 /************************************************************************
782 * VarUI1FromUI2 (OLEAUT32.238)
784 * Convert a VT_UI2 to a VT_UI1.
786 * PARAMS
787 * usIn [I] Source
788 * pbOut [O] Destination
790 * RETURNS
791 * Success: S_OK.
792 * Failure: E_INVALIDARG, if the source value is invalid
793 * DISP_E_OVERFLOW, if the value will not fit in the destination
795 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
797 return _VarUI1FromUI2(usIn, pbOut);
800 /************************************************************************
801 * VarUI1FromUI4 (OLEAUT32.239)
803 * Convert a VT_UI4 to a VT_UI1.
805 * PARAMS
806 * ulIn [I] Source
807 * pbOut [O] Destination
809 * RETURNS
810 * Success: S_OK.
811 * Failure: E_INVALIDARG, if the source value is invalid
812 * DISP_E_OVERFLOW, if the value will not fit in the destination
814 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
816 return _VarUI1FromUI4(ulIn, pbOut);
819 /************************************************************************
820 * VarUI1FromDec (OLEAUT32.240)
822 * Convert a VT_DECIMAL to a VT_UI1.
824 * PARAMS
825 * pDecIn [I] Source
826 * pbOut [O] Destination
828 * RETURNS
829 * Success: S_OK.
830 * Failure: E_INVALIDARG, if the source value is invalid
831 * DISP_E_OVERFLOW, if the value will not fit in the destination
833 HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut)
835 LONG64 i64;
836 HRESULT hRet;
838 hRet = VarI8FromDec(pdecIn, &i64);
840 if (SUCCEEDED(hRet))
841 hRet = _VarUI1FromI8(i64, pbOut);
842 return hRet;
845 /************************************************************************
846 * VarUI1FromI8 (OLEAUT32.372)
848 * Convert a VT_I8 to a VT_UI1.
850 * PARAMS
851 * llIn [I] Source
852 * pbOut [O] Destination
854 * RETURNS
855 * Success: S_OK.
856 * Failure: E_INVALIDARG, if the source value is invalid
857 * DISP_E_OVERFLOW, if the value will not fit in the destination
859 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
861 return _VarUI1FromI8(llIn, pbOut);
864 /************************************************************************
865 * VarUI1FromUI8 (OLEAUT32.373)
867 * Convert a VT_UI8 to a VT_UI1.
869 * PARAMS
870 * ullIn [I] Source
871 * pbOut [O] Destination
873 * RETURNS
874 * Success: S_OK.
875 * Failure: E_INVALIDARG, if the source value is invalid
876 * DISP_E_OVERFLOW, if the value will not fit in the destination
878 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
880 return _VarUI1FromUI8(ullIn, pbOut);
884 /* I2
887 /************************************************************************
888 * VarI2FromUI1 (OLEAUT32.48)
890 * Convert a VT_UI2 to a VT_I2.
892 * PARAMS
893 * bIn [I] Source
894 * psOut [O] Destination
896 * RETURNS
897 * S_OK.
899 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
901 return _VarI2FromUI1(bIn, psOut);
904 /************************************************************************
905 * VarI2FromI4 (OLEAUT32.49)
907 * Convert a VT_I4 to a VT_I2.
909 * PARAMS
910 * iIn [I] Source
911 * psOut [O] Destination
913 * RETURNS
914 * Success: S_OK.
915 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
917 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
919 return _VarI2FromI4(iIn, psOut);
922 /************************************************************************
923 * VarI2FromR4 (OLEAUT32.50)
925 * Convert a VT_R4 to a VT_I2.
927 * PARAMS
928 * fltIn [I] Source
929 * psOut [O] Destination
931 * RETURNS
932 * Success: S_OK.
933 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
935 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
937 return VarI2FromR8(fltIn, psOut);
940 /************************************************************************
941 * VarI2FromR8 (OLEAUT32.51)
943 * Convert a VT_R8 to a VT_I2.
945 * PARAMS
946 * dblIn [I] Source
947 * psOut [O] Destination
949 * RETURNS
950 * Success: S_OK.
951 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
953 * NOTES
954 * See VarI8FromR8() for details concerning rounding.
956 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
958 if (dblIn < I2_MIN - 0.5 || dblIn >= I2_MAX + 0.5)
959 return DISP_E_OVERFLOW;
960 VARIANT_DutchRound(SHORT, dblIn, *psOut);
961 return S_OK;
964 /************************************************************************
965 * VarI2FromCy (OLEAUT32.52)
967 * Convert a VT_CY to a VT_I2.
969 * PARAMS
970 * cyIn [I] Source
971 * psOut [O] Destination
973 * RETURNS
974 * Success: S_OK.
975 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
977 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
979 LONG i = I2_MAX + 1;
981 VarI4FromCy(cyIn, &i);
982 return _VarI2FromI4(i, psOut);
985 /************************************************************************
986 * VarI2FromDate (OLEAUT32.53)
988 * Convert a VT_DATE to a VT_I2.
990 * PARAMS
991 * dateIn [I] Source
992 * psOut [O] Destination
994 * RETURNS
995 * Success: S_OK.
996 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
998 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
1000 return VarI2FromR8(dateIn, psOut);
1003 /************************************************************************
1004 * VarI2FromStr (OLEAUT32.54)
1006 * Convert a VT_BSTR to a VT_I2.
1008 * PARAMS
1009 * strIn [I] Source
1010 * lcid [I] LCID for the conversion
1011 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1012 * psOut [O] Destination
1014 * RETURNS
1015 * Success: S_OK.
1016 * Failure: E_INVALIDARG, if any parameter is invalid
1017 * DISP_E_OVERFLOW, if the value will not fit in the destination
1018 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1020 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
1022 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
1025 /************************************************************************
1026 * VarI2FromDisp (OLEAUT32.55)
1028 * Convert a VT_DISPATCH to a VT_I2.
1030 * PARAMS
1031 * pdispIn [I] Source
1032 * lcid [I] LCID for conversion
1033 * psOut [O] Destination
1035 * RETURNS
1036 * Success: S_OK.
1037 * Failure: E_INVALIDARG, if pdispIn is invalid,
1038 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1039 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1041 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
1043 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0);
1046 /************************************************************************
1047 * VarI2FromBool (OLEAUT32.56)
1049 * Convert a VT_BOOL to a VT_I2.
1051 * PARAMS
1052 * boolIn [I] Source
1053 * psOut [O] Destination
1055 * RETURNS
1056 * S_OK.
1058 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
1060 return _VarI2FromBool(boolIn, psOut);
1063 /************************************************************************
1064 * VarI2FromI1 (OLEAUT32.205)
1066 * Convert a VT_I1 to a VT_I2.
1068 * PARAMS
1069 * cIn [I] Source
1070 * psOut [O] Destination
1072 * RETURNS
1073 * S_OK.
1075 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
1077 return _VarI2FromI1(cIn, psOut);
1080 /************************************************************************
1081 * VarI2FromUI2 (OLEAUT32.206)
1083 * Convert a VT_UI2 to a VT_I2.
1085 * PARAMS
1086 * usIn [I] Source
1087 * psOut [O] Destination
1089 * RETURNS
1090 * Success: S_OK.
1091 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1093 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
1095 return _VarI2FromUI2(usIn, psOut);
1098 /************************************************************************
1099 * VarI2FromUI4 (OLEAUT32.207)
1101 * Convert a VT_UI4 to a VT_I2.
1103 * PARAMS
1104 * ulIn [I] Source
1105 * psOut [O] Destination
1107 * RETURNS
1108 * Success: S_OK.
1109 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1111 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
1113 return _VarI2FromUI4(ulIn, psOut);
1116 /************************************************************************
1117 * VarI2FromDec (OLEAUT32.208)
1119 * Convert a VT_DECIMAL to a VT_I2.
1121 * PARAMS
1122 * pDecIn [I] Source
1123 * psOut [O] Destination
1125 * RETURNS
1126 * Success: S_OK.
1127 * Failure: E_INVALIDARG, if the source value is invalid
1128 * DISP_E_OVERFLOW, if the value will not fit in the destination
1130 HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut)
1132 LONG64 i64;
1133 HRESULT hRet;
1135 hRet = VarI8FromDec(pdecIn, &i64);
1137 if (SUCCEEDED(hRet))
1138 hRet = _VarI2FromI8(i64, psOut);
1139 return hRet;
1142 /************************************************************************
1143 * VarI2FromI8 (OLEAUT32.346)
1145 * Convert a VT_I8 to a VT_I2.
1147 * PARAMS
1148 * llIn [I] Source
1149 * psOut [O] Destination
1151 * RETURNS
1152 * Success: S_OK.
1153 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1155 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
1157 return _VarI2FromI8(llIn, psOut);
1160 /************************************************************************
1161 * VarI2FromUI8 (OLEAUT32.347)
1163 * Convert a VT_UI8 to a VT_I2.
1165 * PARAMS
1166 * ullIn [I] Source
1167 * psOut [O] Destination
1169 * RETURNS
1170 * Success: S_OK.
1171 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1173 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
1175 return _VarI2FromUI8(ullIn, psOut);
1178 /* UI2
1181 /************************************************************************
1182 * VarUI2FromUI1 (OLEAUT32.257)
1184 * Convert a VT_UI1 to a VT_UI2.
1186 * PARAMS
1187 * bIn [I] Source
1188 * pusOut [O] Destination
1190 * RETURNS
1191 * S_OK.
1193 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
1195 return _VarUI2FromUI1(bIn, pusOut);
1198 /************************************************************************
1199 * VarUI2FromI2 (OLEAUT32.258)
1201 * Convert a VT_I2 to a VT_UI2.
1203 * PARAMS
1204 * sIn [I] Source
1205 * pusOut [O] Destination
1207 * RETURNS
1208 * Success: S_OK.
1209 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1211 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
1213 return _VarUI2FromI2(sIn, pusOut);
1216 /************************************************************************
1217 * VarUI2FromI4 (OLEAUT32.259)
1219 * Convert a VT_I4 to a VT_UI2.
1221 * PARAMS
1222 * iIn [I] Source
1223 * pusOut [O] Destination
1225 * RETURNS
1226 * Success: S_OK.
1227 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1229 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
1231 return _VarUI2FromI4(iIn, pusOut);
1234 /************************************************************************
1235 * VarUI2FromR4 (OLEAUT32.260)
1237 * Convert a VT_R4 to a VT_UI2.
1239 * PARAMS
1240 * fltIn [I] Source
1241 * pusOut [O] Destination
1243 * RETURNS
1244 * Success: S_OK.
1245 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1247 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
1249 return VarUI2FromR8(fltIn, pusOut);
1252 /************************************************************************
1253 * VarUI2FromR8 (OLEAUT32.261)
1255 * Convert a VT_R8 to a VT_UI2.
1257 * PARAMS
1258 * dblIn [I] Source
1259 * pusOut [O] Destination
1261 * RETURNS
1262 * Success: S_OK.
1263 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1265 * NOTES
1266 * See VarI8FromR8() for details concerning rounding.
1268 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
1270 if (dblIn < -0.5 || dblIn >= UI2_MAX + 0.5)
1271 return DISP_E_OVERFLOW;
1272 VARIANT_DutchRound(USHORT, dblIn, *pusOut);
1273 return S_OK;
1276 /************************************************************************
1277 * VarUI2FromDate (OLEAUT32.262)
1279 * Convert a VT_DATE to a VT_UI2.
1281 * PARAMS
1282 * dateIn [I] Source
1283 * pusOut [O] Destination
1285 * RETURNS
1286 * Success: S_OK.
1287 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1289 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
1291 return VarUI2FromR8(dateIn, pusOut);
1294 /************************************************************************
1295 * VarUI2FromCy (OLEAUT32.263)
1297 * Convert a VT_CY to a VT_UI2.
1299 * PARAMS
1300 * cyIn [I] Source
1301 * pusOut [O] Destination
1303 * RETURNS
1304 * Success: S_OK.
1305 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1307 * NOTES
1308 * Negative values >= -5000 will be converted to 0.
1310 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
1312 ULONG i = UI2_MAX + 1;
1314 VarUI4FromCy(cyIn, &i);
1315 return _VarUI2FromUI4(i, pusOut);
1318 /************************************************************************
1319 * VarUI2FromStr (OLEAUT32.264)
1321 * Convert a VT_BSTR to a VT_UI2.
1323 * PARAMS
1324 * strIn [I] Source
1325 * lcid [I] LCID for the conversion
1326 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1327 * pusOut [O] Destination
1329 * RETURNS
1330 * Success: S_OK.
1331 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1332 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1334 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
1336 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
1339 /************************************************************************
1340 * VarUI2FromDisp (OLEAUT32.265)
1342 * Convert a VT_DISPATCH to a VT_UI2.
1344 * PARAMS
1345 * pdispIn [I] Source
1346 * lcid [I] LCID for conversion
1347 * pusOut [O] Destination
1349 * RETURNS
1350 * Success: S_OK.
1351 * Failure: E_INVALIDARG, if the source value is invalid
1352 * DISP_E_OVERFLOW, if the value will not fit in the destination
1353 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1355 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
1357 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0);
1360 /************************************************************************
1361 * VarUI2FromBool (OLEAUT32.266)
1363 * Convert a VT_BOOL to a VT_UI2.
1365 * PARAMS
1366 * boolIn [I] Source
1367 * pusOut [O] Destination
1369 * RETURNS
1370 * S_OK.
1372 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
1374 return _VarUI2FromBool(boolIn, pusOut);
1377 /************************************************************************
1378 * VarUI2FromI1 (OLEAUT32.267)
1380 * Convert a VT_I1 to a VT_UI2.
1382 * PARAMS
1383 * cIn [I] Source
1384 * pusOut [O] Destination
1386 * RETURNS
1387 * Success: S_OK.
1388 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1390 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
1392 return _VarUI2FromI1(cIn, pusOut);
1395 /************************************************************************
1396 * VarUI2FromUI4 (OLEAUT32.268)
1398 * Convert a VT_UI4 to a VT_UI2.
1400 * PARAMS
1401 * ulIn [I] Source
1402 * pusOut [O] Destination
1404 * RETURNS
1405 * Success: S_OK.
1406 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1408 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
1410 return _VarUI2FromUI4(ulIn, pusOut);
1413 /************************************************************************
1414 * VarUI2FromDec (OLEAUT32.269)
1416 * Convert a VT_DECIMAL to a VT_UI2.
1418 * PARAMS
1419 * pDecIn [I] Source
1420 * pusOut [O] Destination
1422 * RETURNS
1423 * Success: S_OK.
1424 * Failure: E_INVALIDARG, if the source value is invalid
1425 * DISP_E_OVERFLOW, if the value will not fit in the destination
1427 HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut)
1429 LONG64 i64;
1430 HRESULT hRet;
1432 hRet = VarI8FromDec(pdecIn, &i64);
1434 if (SUCCEEDED(hRet))
1435 hRet = _VarUI2FromI8(i64, pusOut);
1436 return hRet;
1439 /************************************************************************
1440 * VarUI2FromI8 (OLEAUT32.378)
1442 * Convert a VT_I8 to a VT_UI2.
1444 * PARAMS
1445 * llIn [I] Source
1446 * pusOut [O] Destination
1448 * RETURNS
1449 * Success: S_OK.
1450 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1452 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
1454 return _VarUI2FromI8(llIn, pusOut);
1457 /************************************************************************
1458 * VarUI2FromUI8 (OLEAUT32.379)
1460 * Convert a VT_UI8 to a VT_UI2.
1462 * PARAMS
1463 * ullIn [I] Source
1464 * pusOut [O] Destination
1466 * RETURNS
1467 * Success: S_OK.
1468 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1470 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
1472 return _VarUI2FromUI8(ullIn, pusOut);
1475 /* I4
1478 /************************************************************************
1479 * VarI4FromUI1 (OLEAUT32.58)
1481 * Convert a VT_UI1 to a VT_I4.
1483 * PARAMS
1484 * bIn [I] Source
1485 * piOut [O] Destination
1487 * RETURNS
1488 * S_OK.
1490 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
1492 return _VarI4FromUI1(bIn, piOut);
1495 /************************************************************************
1496 * VarI4FromI2 (OLEAUT32.59)
1498 * Convert a VT_I2 to a VT_I4.
1500 * PARAMS
1501 * sIn [I] Source
1502 * piOut [O] Destination
1504 * RETURNS
1505 * Success: S_OK.
1506 * Failure: E_INVALIDARG, if the source value is invalid
1507 * DISP_E_OVERFLOW, if the value will not fit in the destination
1509 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
1511 return _VarI4FromI2(sIn, piOut);
1514 /************************************************************************
1515 * VarI4FromR4 (OLEAUT32.60)
1517 * Convert a VT_R4 to a VT_I4.
1519 * PARAMS
1520 * fltIn [I] Source
1521 * piOut [O] Destination
1523 * RETURNS
1524 * Success: S_OK.
1525 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1527 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
1529 return VarI4FromR8(fltIn, piOut);
1532 /************************************************************************
1533 * VarI4FromR8 (OLEAUT32.61)
1535 * Convert a VT_R8 to a VT_I4.
1537 * PARAMS
1538 * dblIn [I] Source
1539 * piOut [O] Destination
1541 * RETURNS
1542 * Success: S_OK.
1543 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1545 * NOTES
1546 * See VarI8FromR8() for details concerning rounding.
1548 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
1550 if (dblIn < I4_MIN - 0.5 || dblIn >= I4_MAX + 0.5)
1551 return DISP_E_OVERFLOW;
1552 VARIANT_DutchRound(LONG, dblIn, *piOut);
1553 return S_OK;
1556 /************************************************************************
1557 * VarI4FromCy (OLEAUT32.62)
1559 * Convert a VT_CY to a VT_I4.
1561 * PARAMS
1562 * cyIn [I] Source
1563 * piOut [O] Destination
1565 * RETURNS
1566 * Success: S_OK.
1567 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1569 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
1571 double d = cyIn.int64 / CY_MULTIPLIER_F;
1572 return VarI4FromR8(d, piOut);
1575 /************************************************************************
1576 * VarI4FromDate (OLEAUT32.63)
1578 * Convert a VT_DATE to a VT_I4.
1580 * PARAMS
1581 * dateIn [I] Source
1582 * piOut [O] Destination
1584 * RETURNS
1585 * Success: S_OK.
1586 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1588 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
1590 return VarI4FromR8(dateIn, piOut);
1593 /************************************************************************
1594 * VarI4FromStr (OLEAUT32.64)
1596 * Convert a VT_BSTR to a VT_I4.
1598 * PARAMS
1599 * strIn [I] Source
1600 * lcid [I] LCID for the conversion
1601 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1602 * piOut [O] Destination
1604 * RETURNS
1605 * Success: S_OK.
1606 * Failure: E_INVALIDARG, if any parameter is invalid
1607 * DISP_E_OVERFLOW, if the value will not fit in the destination
1608 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1610 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
1612 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
1615 /************************************************************************
1616 * VarI4FromDisp (OLEAUT32.65)
1618 * Convert a VT_DISPATCH to a VT_I4.
1620 * PARAMS
1621 * pdispIn [I] Source
1622 * lcid [I] LCID for conversion
1623 * piOut [O] Destination
1625 * RETURNS
1626 * Success: S_OK.
1627 * Failure: E_INVALIDARG, if the source value is invalid
1628 * DISP_E_OVERFLOW, if the value will not fit in the destination
1629 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1631 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
1633 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0);
1636 /************************************************************************
1637 * VarI4FromBool (OLEAUT32.66)
1639 * Convert a VT_BOOL to a VT_I4.
1641 * PARAMS
1642 * boolIn [I] Source
1643 * piOut [O] Destination
1645 * RETURNS
1646 * S_OK.
1648 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
1650 return _VarI4FromBool(boolIn, piOut);
1653 /************************************************************************
1654 * VarI4FromI1 (OLEAUT32.209)
1656 * Convert a VT_I1 to a VT_I4.
1658 * PARAMS
1659 * cIn [I] Source
1660 * piOut [O] Destination
1662 * RETURNS
1663 * S_OK.
1665 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
1667 return _VarI4FromI1(cIn, piOut);
1670 /************************************************************************
1671 * VarI4FromUI2 (OLEAUT32.210)
1673 * Convert a VT_UI2 to a VT_I4.
1675 * PARAMS
1676 * usIn [I] Source
1677 * piOut [O] Destination
1679 * RETURNS
1680 * S_OK.
1682 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
1684 return _VarI4FromUI2(usIn, piOut);
1687 /************************************************************************
1688 * VarI4FromUI4 (OLEAUT32.211)
1690 * Convert a VT_UI4 to a VT_I4.
1692 * PARAMS
1693 * ulIn [I] Source
1694 * piOut [O] Destination
1696 * RETURNS
1697 * Success: S_OK.
1698 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1700 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
1702 return _VarI4FromUI4(ulIn, piOut);
1705 /************************************************************************
1706 * VarI4FromDec (OLEAUT32.212)
1708 * Convert a VT_DECIMAL to a VT_I4.
1710 * PARAMS
1711 * pDecIn [I] Source
1712 * piOut [O] Destination
1714 * RETURNS
1715 * Success: S_OK.
1716 * Failure: E_INVALIDARG, if pdecIn is invalid
1717 * DISP_E_OVERFLOW, if the value will not fit in the destination
1719 HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut)
1721 LONG64 i64;
1722 HRESULT hRet;
1724 hRet = VarI8FromDec(pdecIn, &i64);
1726 if (SUCCEEDED(hRet))
1727 hRet = _VarI4FromI8(i64, piOut);
1728 return hRet;
1731 /************************************************************************
1732 * VarI4FromI8 (OLEAUT32.348)
1734 * Convert a VT_I8 to a VT_I4.
1736 * PARAMS
1737 * llIn [I] Source
1738 * piOut [O] Destination
1740 * RETURNS
1741 * Success: S_OK.
1742 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1744 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
1746 return _VarI4FromI8(llIn, piOut);
1749 /************************************************************************
1750 * VarI4FromUI8 (OLEAUT32.349)
1752 * Convert a VT_UI8 to a VT_I4.
1754 * PARAMS
1755 * ullIn [I] Source
1756 * piOut [O] Destination
1758 * RETURNS
1759 * Success: S_OK.
1760 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1762 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
1764 return _VarI4FromUI8(ullIn, piOut);
1767 /* UI4
1770 /************************************************************************
1771 * VarUI4FromUI1 (OLEAUT32.270)
1773 * Convert a VT_UI1 to a VT_UI4.
1775 * PARAMS
1776 * bIn [I] Source
1777 * pulOut [O] Destination
1779 * RETURNS
1780 * S_OK.
1782 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
1784 return _VarUI4FromUI1(bIn, pulOut);
1787 /************************************************************************
1788 * VarUI4FromI2 (OLEAUT32.271)
1790 * Convert a VT_I2 to a VT_UI4.
1792 * PARAMS
1793 * sIn [I] Source
1794 * pulOut [O] Destination
1796 * RETURNS
1797 * Success: S_OK.
1798 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1800 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
1802 return _VarUI4FromI2(sIn, pulOut);
1805 /************************************************************************
1806 * VarUI4FromI4 (OLEAUT32.272)
1808 * Convert a VT_I4 to a VT_UI4.
1810 * PARAMS
1811 * iIn [I] Source
1812 * pulOut [O] Destination
1814 * RETURNS
1815 * Success: S_OK.
1816 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1818 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
1820 return _VarUI4FromI4(iIn, pulOut);
1823 /************************************************************************
1824 * VarUI4FromR4 (OLEAUT32.273)
1826 * Convert a VT_R4 to a VT_UI4.
1828 * PARAMS
1829 * fltIn [I] Source
1830 * pulOut [O] Destination
1832 * RETURNS
1833 * Success: S_OK.
1834 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1836 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
1838 return VarUI4FromR8(fltIn, pulOut);
1841 /************************************************************************
1842 * VarUI4FromR8 (OLEAUT32.274)
1844 * Convert a VT_R8 to a VT_UI4.
1846 * PARAMS
1847 * dblIn [I] Source
1848 * pulOut [O] Destination
1850 * RETURNS
1851 * Success: S_OK.
1852 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1854 * NOTES
1855 * See VarI8FromR8() for details concerning rounding.
1857 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
1859 if (dblIn < -0.5 || dblIn >= UI4_MAX + 0.5)
1860 return DISP_E_OVERFLOW;
1861 VARIANT_DutchRound(ULONG, dblIn, *pulOut);
1862 return S_OK;
1865 /************************************************************************
1866 * VarUI4FromDate (OLEAUT32.275)
1868 * Convert a VT_DATE to a VT_UI4.
1870 * PARAMS
1871 * dateIn [I] Source
1872 * pulOut [O] Destination
1874 * RETURNS
1875 * Success: S_OK.
1876 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1878 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
1880 return VarUI4FromR8(dateIn, pulOut);
1883 /************************************************************************
1884 * VarUI4FromCy (OLEAUT32.276)
1886 * Convert a VT_CY to a VT_UI4.
1888 * PARAMS
1889 * cyIn [I] Source
1890 * pulOut [O] Destination
1892 * RETURNS
1893 * Success: S_OK.
1894 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1896 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
1898 double d = cyIn.int64 / CY_MULTIPLIER_F;
1899 return VarUI4FromR8(d, pulOut);
1902 /************************************************************************
1903 * VarUI4FromStr (OLEAUT32.277)
1905 * Convert a VT_BSTR to a VT_UI4.
1907 * PARAMS
1908 * strIn [I] Source
1909 * lcid [I] LCID for the conversion
1910 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1911 * pulOut [O] Destination
1913 * RETURNS
1914 * Success: S_OK.
1915 * Failure: E_INVALIDARG, if any parameter is invalid
1916 * DISP_E_OVERFLOW, if the value will not fit in the destination
1917 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1919 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
1921 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
1924 /************************************************************************
1925 * VarUI4FromDisp (OLEAUT32.278)
1927 * Convert a VT_DISPATCH to a VT_UI4.
1929 * PARAMS
1930 * pdispIn [I] Source
1931 * lcid [I] LCID for conversion
1932 * pulOut [O] Destination
1934 * RETURNS
1935 * Success: S_OK.
1936 * Failure: E_INVALIDARG, if the source value is invalid
1937 * DISP_E_OVERFLOW, if the value will not fit in the destination
1938 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1940 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
1942 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0);
1945 /************************************************************************
1946 * VarUI4FromBool (OLEAUT32.279)
1948 * Convert a VT_BOOL to a VT_UI4.
1950 * PARAMS
1951 * boolIn [I] Source
1952 * pulOut [O] Destination
1954 * RETURNS
1955 * S_OK.
1957 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
1959 return _VarUI4FromBool(boolIn, pulOut);
1962 /************************************************************************
1963 * VarUI4FromI1 (OLEAUT32.280)
1965 * Convert a VT_I1 to a VT_UI4.
1967 * PARAMS
1968 * cIn [I] Source
1969 * pulOut [O] Destination
1971 * RETURNS
1972 * Success: S_OK.
1973 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1975 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
1977 return _VarUI4FromI1(cIn, pulOut);
1980 /************************************************************************
1981 * VarUI4FromUI2 (OLEAUT32.281)
1983 * Convert a VT_UI2 to a VT_UI4.
1985 * PARAMS
1986 * usIn [I] Source
1987 * pulOut [O] Destination
1989 * RETURNS
1990 * S_OK.
1992 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
1994 return _VarUI4FromUI2(usIn, pulOut);
1997 /************************************************************************
1998 * VarUI4FromDec (OLEAUT32.282)
2000 * Convert a VT_DECIMAL to a VT_UI4.
2002 * PARAMS
2003 * pDecIn [I] Source
2004 * pulOut [O] Destination
2006 * RETURNS
2007 * Success: S_OK.
2008 * Failure: E_INVALIDARG, if pdecIn is invalid
2009 * DISP_E_OVERFLOW, if the value will not fit in the destination
2011 HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut)
2013 LONG64 i64;
2014 HRESULT hRet;
2016 hRet = VarI8FromDec(pdecIn, &i64);
2018 if (SUCCEEDED(hRet))
2019 hRet = _VarUI4FromI8(i64, pulOut);
2020 return hRet;
2023 /************************************************************************
2024 * VarUI4FromI8 (OLEAUT32.425)
2026 * Convert a VT_I8 to a VT_UI4.
2028 * PARAMS
2029 * llIn [I] Source
2030 * pulOut [O] Destination
2032 * RETURNS
2033 * Success: S_OK.
2034 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2036 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
2038 return _VarUI4FromI8(llIn, pulOut);
2041 /************************************************************************
2042 * VarUI4FromUI8 (OLEAUT32.426)
2044 * Convert a VT_UI8 to a VT_UI4.
2046 * PARAMS
2047 * ullIn [I] Source
2048 * pulOut [O] Destination
2050 * RETURNS
2051 * Success: S_OK.
2052 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2054 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
2056 return _VarUI4FromUI8(ullIn, pulOut);
2059 /* I8
2062 /************************************************************************
2063 * VarI8FromUI1 (OLEAUT32.333)
2065 * Convert a VT_UI1 to a VT_I8.
2067 * PARAMS
2068 * bIn [I] Source
2069 * pi64Out [O] Destination
2071 * RETURNS
2072 * S_OK.
2074 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
2076 return _VarI8FromUI1(bIn, pi64Out);
2080 /************************************************************************
2081 * VarI8FromI2 (OLEAUT32.334)
2083 * Convert a VT_I2 to a VT_I8.
2085 * PARAMS
2086 * sIn [I] Source
2087 * pi64Out [O] Destination
2089 * RETURNS
2090 * S_OK.
2092 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
2094 return _VarI8FromI2(sIn, pi64Out);
2097 /************************************************************************
2098 * VarI8FromR4 (OLEAUT32.335)
2100 * Convert a VT_R4 to a VT_I8.
2102 * PARAMS
2103 * fltIn [I] Source
2104 * pi64Out [O] Destination
2106 * RETURNS
2107 * Success: S_OK.
2108 * Failure: E_INVALIDARG, if the source value is invalid
2109 * DISP_E_OVERFLOW, if the value will not fit in the destination
2111 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
2113 return VarI8FromR8(fltIn, pi64Out);
2116 /************************************************************************
2117 * VarI8FromR8 (OLEAUT32.336)
2119 * Convert a VT_R8 to a VT_I8.
2121 * PARAMS
2122 * dblIn [I] Source
2123 * pi64Out [O] Destination
2125 * RETURNS
2126 * Success: S_OK.
2127 * Failure: E_INVALIDARG, if the source value is invalid
2128 * DISP_E_OVERFLOW, if the value will not fit in the destination
2130 * NOTES
2131 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2132 * very high or low values will not be accurately converted.
2134 * Numbers are rounded using Dutch rounding, as follows:
2136 *| Fractional Part Sign Direction Example
2137 *| --------------- ---- --------- -------
2138 *| < 0.5 + Down 0.4 -> 0.0
2139 *| < 0.5 - Up -0.4 -> 0.0
2140 *| > 0.5 + Up 0.6 -> 1.0
2141 *| < 0.5 - Up -0.6 -> -1.0
2142 *| = 0.5 + Up/Down Down if even, Up if odd
2143 *| = 0.5 - Up/Down Up if even, Down if odd
2145 * This system is often used in supermarkets.
2147 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
2149 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
2150 return DISP_E_OVERFLOW;
2151 VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
2152 return S_OK;
2155 /************************************************************************
2156 * VarI8FromCy (OLEAUT32.337)
2158 * Convert a VT_CY to a VT_I8.
2160 * PARAMS
2161 * cyIn [I] Source
2162 * pi64Out [O] Destination
2164 * RETURNS
2165 * S_OK.
2167 * NOTES
2168 * All negative numbers are rounded down by 1, including those that are
2169 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2170 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2171 * for details.
2173 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
2175 *pi64Out = cyIn.int64 / CY_MULTIPLIER;
2177 if (cyIn.int64 < 0)
2178 (*pi64Out)--; /* Mimic Win32 bug */
2179 else
2181 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2183 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1)))
2184 (*pi64Out)++;
2186 return S_OK;
2189 /************************************************************************
2190 * VarI8FromDate (OLEAUT32.338)
2192 * Convert a VT_DATE to a VT_I8.
2194 * PARAMS
2195 * dateIn [I] Source
2196 * pi64Out [O] Destination
2198 * RETURNS
2199 * Success: S_OK.
2200 * Failure: E_INVALIDARG, if the source value is invalid
2201 * DISP_E_OVERFLOW, if the value will not fit in the destination
2202 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2204 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
2206 return VarI8FromR8(dateIn, pi64Out);
2209 /************************************************************************
2210 * VarI8FromStr (OLEAUT32.339)
2212 * Convert a VT_BSTR to a VT_I8.
2214 * PARAMS
2215 * strIn [I] Source
2216 * lcid [I] LCID for the conversion
2217 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2218 * pi64Out [O] Destination
2220 * RETURNS
2221 * Success: S_OK.
2222 * Failure: E_INVALIDARG, if the source value is invalid
2223 * DISP_E_OVERFLOW, if the value will not fit in the destination
2224 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2226 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
2228 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
2231 /************************************************************************
2232 * VarI8FromDisp (OLEAUT32.340)
2234 * Convert a VT_DISPATCH to a VT_I8.
2236 * PARAMS
2237 * pdispIn [I] Source
2238 * lcid [I] LCID for conversion
2239 * pi64Out [O] Destination
2241 * RETURNS
2242 * Success: S_OK.
2243 * Failure: E_INVALIDARG, if the source value is invalid
2244 * DISP_E_OVERFLOW, if the value will not fit in the destination
2245 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2247 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
2249 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0);
2252 /************************************************************************
2253 * VarI8FromBool (OLEAUT32.341)
2255 * Convert a VT_BOOL to a VT_I8.
2257 * PARAMS
2258 * boolIn [I] Source
2259 * pi64Out [O] Destination
2261 * RETURNS
2262 * S_OK.
2264 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
2266 return VarI8FromI2(boolIn, pi64Out);
2269 /************************************************************************
2270 * VarI8FromI1 (OLEAUT32.342)
2272 * Convert a VT_I1 to a VT_I8.
2274 * PARAMS
2275 * cIn [I] Source
2276 * pi64Out [O] Destination
2278 * RETURNS
2279 * S_OK.
2281 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
2283 return _VarI8FromI1(cIn, pi64Out);
2286 /************************************************************************
2287 * VarI8FromUI2 (OLEAUT32.343)
2289 * Convert a VT_UI2 to a VT_I8.
2291 * PARAMS
2292 * usIn [I] Source
2293 * pi64Out [O] Destination
2295 * RETURNS
2296 * S_OK.
2298 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
2300 return _VarI8FromUI2(usIn, pi64Out);
2303 /************************************************************************
2304 * VarI8FromUI4 (OLEAUT32.344)
2306 * Convert a VT_UI4 to a VT_I8.
2308 * PARAMS
2309 * ulIn [I] Source
2310 * pi64Out [O] Destination
2312 * RETURNS
2313 * S_OK.
2315 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
2317 return _VarI8FromUI4(ulIn, pi64Out);
2320 /************************************************************************
2321 * VarI8FromDec (OLEAUT32.345)
2323 * Convert a VT_DECIMAL to a VT_I8.
2325 * PARAMS
2326 * pDecIn [I] Source
2327 * pi64Out [O] Destination
2329 * RETURNS
2330 * Success: S_OK.
2331 * Failure: E_INVALIDARG, if the source value is invalid
2332 * DISP_E_OVERFLOW, if the value will not fit in the destination
2334 HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out)
2336 if (!DEC_SCALE(pdecIn))
2338 /* This decimal is just a 96 bit integer */
2339 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2340 return E_INVALIDARG;
2342 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000)
2343 return DISP_E_OVERFLOW;
2345 if (DEC_SIGN(pdecIn))
2346 *pi64Out = -DEC_LO64(pdecIn);
2347 else
2348 *pi64Out = DEC_LO64(pdecIn);
2349 return S_OK;
2351 else
2353 /* Decimal contains a floating point number */
2354 HRESULT hRet;
2355 double dbl;
2357 hRet = VarR8FromDec(pdecIn, &dbl);
2358 if (SUCCEEDED(hRet))
2359 hRet = VarI8FromR8(dbl, pi64Out);
2360 return hRet;
2364 /************************************************************************
2365 * VarI8FromUI8 (OLEAUT32.427)
2367 * Convert a VT_UI8 to a VT_I8.
2369 * PARAMS
2370 * ullIn [I] Source
2371 * pi64Out [O] Destination
2373 * RETURNS
2374 * Success: S_OK.
2375 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2377 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
2379 return _VarI8FromUI8(ullIn, pi64Out);
2382 /* UI8
2385 /************************************************************************
2386 * VarUI8FromI8 (OLEAUT32.428)
2388 * Convert a VT_I8 to a VT_UI8.
2390 * PARAMS
2391 * ulIn [I] Source
2392 * pui64Out [O] Destination
2394 * RETURNS
2395 * Success: S_OK.
2396 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2398 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
2400 return _VarUI8FromI8(llIn, pui64Out);
2403 /************************************************************************
2404 * VarUI8FromUI1 (OLEAUT32.429)
2406 * Convert a VT_UI1 to a VT_UI8.
2408 * PARAMS
2409 * bIn [I] Source
2410 * pui64Out [O] Destination
2412 * RETURNS
2413 * S_OK.
2415 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
2417 return _VarUI8FromUI1(bIn, pui64Out);
2420 /************************************************************************
2421 * VarUI8FromI2 (OLEAUT32.430)
2423 * Convert a VT_I2 to a VT_UI8.
2425 * PARAMS
2426 * sIn [I] Source
2427 * pui64Out [O] Destination
2429 * RETURNS
2430 * S_OK.
2432 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
2434 return _VarUI8FromI2(sIn, pui64Out);
2437 /************************************************************************
2438 * VarUI8FromR4 (OLEAUT32.431)
2440 * Convert a VT_R4 to a VT_UI8.
2442 * PARAMS
2443 * fltIn [I] Source
2444 * pui64Out [O] Destination
2446 * RETURNS
2447 * Success: S_OK.
2448 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2450 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
2452 return VarUI8FromR8(fltIn, pui64Out);
2455 /************************************************************************
2456 * VarUI8FromR8 (OLEAUT32.432)
2458 * Convert a VT_R8 to a VT_UI8.
2460 * PARAMS
2461 * dblIn [I] Source
2462 * pui64Out [O] Destination
2464 * RETURNS
2465 * Success: S_OK.
2466 * Failure: E_INVALIDARG, if the source value is invalid
2467 * DISP_E_OVERFLOW, if the value will not fit in the destination
2469 * NOTES
2470 * See VarI8FromR8() for details concerning rounding.
2472 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
2474 if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
2475 return DISP_E_OVERFLOW;
2476 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
2477 return S_OK;
2480 /************************************************************************
2481 * VarUI8FromCy (OLEAUT32.433)
2483 * Convert a VT_CY to a VT_UI8.
2485 * PARAMS
2486 * cyIn [I] Source
2487 * pui64Out [O] Destination
2489 * RETURNS
2490 * Success: S_OK.
2491 * Failure: E_INVALIDARG, if the source value is invalid
2492 * DISP_E_OVERFLOW, if the value will not fit in the destination
2494 * NOTES
2495 * Negative values >= -5000 will be converted to 0.
2497 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
2499 if (cyIn.int64 < 0)
2501 if (cyIn.int64 < -CY_HALF)
2502 return DISP_E_OVERFLOW;
2503 *pui64Out = 0;
2505 else
2507 *pui64Out = cyIn.int64 / CY_MULTIPLIER;
2509 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2511 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1)))
2512 (*pui64Out)++;
2514 return S_OK;
2517 /************************************************************************
2518 * VarUI8FromDate (OLEAUT32.434)
2520 * Convert a VT_DATE to a VT_UI8.
2522 * PARAMS
2523 * dateIn [I] Source
2524 * pui64Out [O] Destination
2526 * RETURNS
2527 * Success: S_OK.
2528 * Failure: E_INVALIDARG, if the source value is invalid
2529 * DISP_E_OVERFLOW, if the value will not fit in the destination
2530 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2532 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
2534 return VarUI8FromR8(dateIn, pui64Out);
2537 /************************************************************************
2538 * VarUI8FromStr (OLEAUT32.435)
2540 * Convert a VT_BSTR to a VT_UI8.
2542 * PARAMS
2543 * strIn [I] Source
2544 * lcid [I] LCID for the conversion
2545 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2546 * pui64Out [O] Destination
2548 * RETURNS
2549 * Success: S_OK.
2550 * Failure: E_INVALIDARG, if the source value is invalid
2551 * DISP_E_OVERFLOW, if the value will not fit in the destination
2552 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2554 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
2556 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
2559 /************************************************************************
2560 * VarUI8FromDisp (OLEAUT32.436)
2562 * Convert a VT_DISPATCH to a VT_UI8.
2564 * PARAMS
2565 * pdispIn [I] Source
2566 * lcid [I] LCID for conversion
2567 * pui64Out [O] Destination
2569 * RETURNS
2570 * Success: S_OK.
2571 * Failure: E_INVALIDARG, if the source value is invalid
2572 * DISP_E_OVERFLOW, if the value will not fit in the destination
2573 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2575 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
2577 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0);
2580 /************************************************************************
2581 * VarUI8FromBool (OLEAUT32.437)
2583 * Convert a VT_BOOL to a VT_UI8.
2585 * PARAMS
2586 * boolIn [I] Source
2587 * pui64Out [O] Destination
2589 * RETURNS
2590 * Success: S_OK.
2591 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2593 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
2595 return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
2597 /************************************************************************
2598 * VarUI8FromI1 (OLEAUT32.438)
2600 * Convert a VT_I1 to a VT_UI8.
2602 * PARAMS
2603 * cIn [I] Source
2604 * pui64Out [O] Destination
2606 * RETURNS
2607 * Success: S_OK.
2608 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2610 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
2612 return _VarUI8FromI1(cIn, pui64Out);
2615 /************************************************************************
2616 * VarUI8FromUI2 (OLEAUT32.439)
2618 * Convert a VT_UI2 to a VT_UI8.
2620 * PARAMS
2621 * usIn [I] Source
2622 * pui64Out [O] Destination
2624 * RETURNS
2625 * S_OK.
2627 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
2629 return _VarUI8FromUI2(usIn, pui64Out);
2632 /************************************************************************
2633 * VarUI8FromUI4 (OLEAUT32.440)
2635 * Convert a VT_UI4 to a VT_UI8.
2637 * PARAMS
2638 * ulIn [I] Source
2639 * pui64Out [O] Destination
2641 * RETURNS
2642 * S_OK.
2644 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
2646 return _VarUI8FromUI4(ulIn, pui64Out);
2649 /************************************************************************
2650 * VarUI8FromDec (OLEAUT32.441)
2652 * Convert a VT_DECIMAL to a VT_UI8.
2654 * PARAMS
2655 * pDecIn [I] Source
2656 * pui64Out [O] Destination
2658 * RETURNS
2659 * Success: S_OK.
2660 * Failure: E_INVALIDARG, if the source value is invalid
2661 * DISP_E_OVERFLOW, if the value will not fit in the destination
2663 * NOTES
2664 * Under native Win32, if the source value has a scale of 0, its sign is
2665 * ignored, i.e. this function takes the absolute value rather than fail
2666 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2667 * (use VarAbs() on pDecIn first if you really want this behaviour).
2669 HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out)
2671 if (!DEC_SCALE(pdecIn))
2673 /* This decimal is just a 96 bit integer */
2674 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2675 return E_INVALIDARG;
2677 if (DEC_HI32(pdecIn))
2678 return DISP_E_OVERFLOW;
2680 if (DEC_SIGN(pdecIn))
2682 WARN("Sign would be ignored under Win32!\n");
2683 return DISP_E_OVERFLOW;
2686 *pui64Out = DEC_LO64(pdecIn);
2687 return S_OK;
2689 else
2691 /* Decimal contains a floating point number */
2692 HRESULT hRet;
2693 double dbl;
2695 hRet = VarR8FromDec(pdecIn, &dbl);
2696 if (SUCCEEDED(hRet))
2697 hRet = VarUI8FromR8(dbl, pui64Out);
2698 return hRet;
2702 /* R4
2705 /************************************************************************
2706 * VarR4FromUI1 (OLEAUT32.68)
2708 * Convert a VT_UI1 to a VT_R4.
2710 * PARAMS
2711 * bIn [I] Source
2712 * pFltOut [O] Destination
2714 * RETURNS
2715 * S_OK.
2717 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
2719 return _VarR4FromUI1(bIn, pFltOut);
2722 /************************************************************************
2723 * VarR4FromI2 (OLEAUT32.69)
2725 * Convert a VT_I2 to a VT_R4.
2727 * PARAMS
2728 * sIn [I] Source
2729 * pFltOut [O] Destination
2731 * RETURNS
2732 * S_OK.
2734 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
2736 return _VarR4FromI2(sIn, pFltOut);
2739 /************************************************************************
2740 * VarR4FromI4 (OLEAUT32.70)
2742 * Convert a VT_I4 to a VT_R4.
2744 * PARAMS
2745 * sIn [I] Source
2746 * pFltOut [O] Destination
2748 * RETURNS
2749 * S_OK.
2751 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
2753 return _VarR4FromI4(lIn, pFltOut);
2756 /************************************************************************
2757 * VarR4FromR8 (OLEAUT32.71)
2759 * Convert a VT_R8 to a VT_R4.
2761 * PARAMS
2762 * dblIn [I] Source
2763 * pFltOut [O] Destination
2765 * RETURNS
2766 * Success: S_OK.
2767 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2769 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
2771 double d = dblIn < 0.0 ? -dblIn : dblIn;
2772 if (d > R4_MAX) return DISP_E_OVERFLOW;
2773 *pFltOut = dblIn;
2774 return S_OK;
2777 /************************************************************************
2778 * VarR4FromCy (OLEAUT32.72)
2780 * Convert a VT_CY to a VT_R4.
2782 * PARAMS
2783 * cyIn [I] Source
2784 * pFltOut [O] Destination
2786 * RETURNS
2787 * S_OK.
2789 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
2791 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
2792 return S_OK;
2795 /************************************************************************
2796 * VarR4FromDate (OLEAUT32.73)
2798 * Convert a VT_DATE to a VT_R4.
2800 * PARAMS
2801 * dateIn [I] Source
2802 * pFltOut [O] Destination
2804 * RETURNS
2805 * Success: S_OK.
2806 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2808 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
2810 return VarR4FromR8(dateIn, pFltOut);
2813 /************************************************************************
2814 * VarR4FromStr (OLEAUT32.74)
2816 * Convert a VT_BSTR to a VT_R4.
2818 * PARAMS
2819 * strIn [I] Source
2820 * lcid [I] LCID for the conversion
2821 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2822 * pFltOut [O] Destination
2824 * RETURNS
2825 * Success: S_OK.
2826 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2827 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2829 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
2831 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
2834 /************************************************************************
2835 * VarR4FromDisp (OLEAUT32.75)
2837 * Convert a VT_DISPATCH to a VT_R4.
2839 * PARAMS
2840 * pdispIn [I] Source
2841 * lcid [I] LCID for conversion
2842 * pFltOut [O] Destination
2844 * RETURNS
2845 * Success: S_OK.
2846 * Failure: E_INVALIDARG, if the source value is invalid
2847 * DISP_E_OVERFLOW, if the value will not fit in the destination
2848 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2850 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
2852 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0);
2855 /************************************************************************
2856 * VarR4FromBool (OLEAUT32.76)
2858 * Convert a VT_BOOL to a VT_R4.
2860 * PARAMS
2861 * boolIn [I] Source
2862 * pFltOut [O] Destination
2864 * RETURNS
2865 * S_OK.
2867 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2869 return VarR4FromI2(boolIn, pFltOut);
2872 /************************************************************************
2873 * VarR4FromI1 (OLEAUT32.213)
2875 * Convert a VT_I1 to a VT_R4.
2877 * PARAMS
2878 * cIn [I] Source
2879 * pFltOut [O] Destination
2881 * RETURNS
2882 * Success: S_OK.
2883 * Failure: E_INVALIDARG, if the source value is invalid
2884 * DISP_E_OVERFLOW, if the value will not fit in the destination
2885 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2887 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2889 return _VarR4FromI1(cIn, pFltOut);
2892 /************************************************************************
2893 * VarR4FromUI2 (OLEAUT32.214)
2895 * Convert a VT_UI2 to a VT_R4.
2897 * PARAMS
2898 * usIn [I] Source
2899 * pFltOut [O] Destination
2901 * RETURNS
2902 * Success: S_OK.
2903 * Failure: E_INVALIDARG, if the source value is invalid
2904 * DISP_E_OVERFLOW, if the value will not fit in the destination
2905 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2907 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2909 return _VarR4FromUI2(usIn, pFltOut);
2912 /************************************************************************
2913 * VarR4FromUI4 (OLEAUT32.215)
2915 * Convert a VT_UI4 to a VT_R4.
2917 * PARAMS
2918 * ulIn [I] Source
2919 * pFltOut [O] Destination
2921 * RETURNS
2922 * Success: S_OK.
2923 * Failure: E_INVALIDARG, if the source value is invalid
2924 * DISP_E_OVERFLOW, if the value will not fit in the destination
2925 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2927 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2929 return _VarR4FromUI4(ulIn, pFltOut);
2932 /************************************************************************
2933 * VarR4FromDec (OLEAUT32.216)
2935 * Convert a VT_DECIMAL to a VT_R4.
2937 * PARAMS
2938 * pDecIn [I] Source
2939 * pFltOut [O] Destination
2941 * RETURNS
2942 * Success: S_OK.
2943 * Failure: E_INVALIDARG, if the source value is invalid.
2945 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
2947 BYTE scale = DEC_SCALE(pDecIn);
2948 double divisor = 1.0;
2949 double highPart;
2951 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2952 return E_INVALIDARG;
2954 while (scale--)
2955 divisor *= 10.0;
2957 if (DEC_SIGN(pDecIn))
2958 divisor = -divisor;
2960 if (DEC_HI32(pDecIn))
2962 highPart = (double)DEC_HI32(pDecIn) / divisor;
2963 highPart *= 4294967296.0F;
2964 highPart *= 4294967296.0F;
2966 else
2967 highPart = 0.0;
2969 *pFltOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
2970 return S_OK;
2973 /************************************************************************
2974 * VarR4FromI8 (OLEAUT32.360)
2976 * Convert a VT_I8 to a VT_R4.
2978 * PARAMS
2979 * ullIn [I] Source
2980 * pFltOut [O] Destination
2982 * RETURNS
2983 * S_OK.
2985 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2987 return _VarR4FromI8(llIn, pFltOut);
2990 /************************************************************************
2991 * VarR4FromUI8 (OLEAUT32.361)
2993 * Convert a VT_UI8 to a VT_R4.
2995 * PARAMS
2996 * ullIn [I] Source
2997 * pFltOut [O] Destination
2999 * RETURNS
3000 * S_OK.
3002 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
3004 return _VarR4FromUI8(ullIn, pFltOut);
3007 /************************************************************************
3008 * VarR4CmpR8 (OLEAUT32.316)
3010 * Compare a VT_R4 to a VT_R8.
3012 * PARAMS
3013 * fltLeft [I] Source
3014 * dblRight [I] Value to compare
3016 * RETURNS
3017 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3018 * equal to or greater than dblRight respectively.
3020 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3022 if (fltLeft < dblRight)
3023 return VARCMP_LT;
3024 else if (fltLeft > dblRight)
3025 return VARCMP_GT;
3026 return VARCMP_EQ;
3029 /* R8
3032 /************************************************************************
3033 * VarR8FromUI1 (OLEAUT32.78)
3035 * Convert a VT_UI1 to a VT_R8.
3037 * PARAMS
3038 * bIn [I] Source
3039 * pDblOut [O] Destination
3041 * RETURNS
3042 * S_OK.
3044 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3046 return _VarR8FromUI1(bIn, pDblOut);
3049 /************************************************************************
3050 * VarR8FromI2 (OLEAUT32.79)
3052 * Convert a VT_I2 to a VT_R8.
3054 * PARAMS
3055 * sIn [I] Source
3056 * pDblOut [O] Destination
3058 * RETURNS
3059 * S_OK.
3061 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3063 return _VarR8FromI2(sIn, pDblOut);
3066 /************************************************************************
3067 * VarR8FromI4 (OLEAUT32.80)
3069 * Convert a VT_I4 to a VT_R8.
3071 * PARAMS
3072 * sIn [I] Source
3073 * pDblOut [O] Destination
3075 * RETURNS
3076 * S_OK.
3078 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3080 return _VarR8FromI4(lIn, pDblOut);
3083 /************************************************************************
3084 * VarR8FromR4 (OLEAUT32.81)
3086 * Convert a VT_R4 to a VT_R8.
3088 * PARAMS
3089 * fltIn [I] Source
3090 * pDblOut [O] Destination
3092 * RETURNS
3093 * S_OK.
3095 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3097 return _VarR8FromR4(fltIn, pDblOut);
3100 /************************************************************************
3101 * VarR8FromCy (OLEAUT32.82)
3103 * Convert a VT_CY to a VT_R8.
3105 * PARAMS
3106 * cyIn [I] Source
3107 * pDblOut [O] Destination
3109 * RETURNS
3110 * S_OK.
3112 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3114 return _VarR8FromCy(cyIn, pDblOut);
3117 /************************************************************************
3118 * VarR8FromDate (OLEAUT32.83)
3120 * Convert a VT_DATE to a VT_R8.
3122 * PARAMS
3123 * dateIn [I] Source
3124 * pDblOut [O] Destination
3126 * RETURNS
3127 * S_OK.
3129 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3131 return _VarR8FromDate(dateIn, pDblOut);
3134 /************************************************************************
3135 * VarR8FromStr (OLEAUT32.84)
3137 * Convert a VT_BSTR to a VT_R8.
3139 * PARAMS
3140 * strIn [I] Source
3141 * lcid [I] LCID for the conversion
3142 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3143 * pDblOut [O] Destination
3145 * RETURNS
3146 * Success: S_OK.
3147 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3148 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3150 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3152 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3155 /************************************************************************
3156 * VarR8FromDisp (OLEAUT32.85)
3158 * Convert a VT_DISPATCH to a VT_R8.
3160 * PARAMS
3161 * pdispIn [I] Source
3162 * lcid [I] LCID for conversion
3163 * pDblOut [O] Destination
3165 * RETURNS
3166 * Success: S_OK.
3167 * Failure: E_INVALIDARG, if the source value is invalid
3168 * DISP_E_OVERFLOW, if the value will not fit in the destination
3169 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3171 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3173 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0);
3176 /************************************************************************
3177 * VarR8FromBool (OLEAUT32.86)
3179 * Convert a VT_BOOL to a VT_R8.
3181 * PARAMS
3182 * boolIn [I] Source
3183 * pDblOut [O] Destination
3185 * RETURNS
3186 * S_OK.
3188 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3190 return VarR8FromI2(boolIn, pDblOut);
3193 /************************************************************************
3194 * VarR8FromI1 (OLEAUT32.217)
3196 * Convert a VT_I1 to a VT_R8.
3198 * PARAMS
3199 * cIn [I] Source
3200 * pDblOut [O] Destination
3202 * RETURNS
3203 * Success: S_OK.
3204 * Failure: E_INVALIDARG, if the source value is invalid
3205 * DISP_E_OVERFLOW, if the value will not fit in the destination
3206 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3208 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3210 return _VarR8FromI1(cIn, pDblOut);
3213 /************************************************************************
3214 * VarR8FromUI2 (OLEAUT32.218)
3216 * Convert a VT_UI2 to a VT_R8.
3218 * PARAMS
3219 * usIn [I] Source
3220 * pDblOut [O] Destination
3222 * RETURNS
3223 * Success: S_OK.
3224 * Failure: E_INVALIDARG, if the source value is invalid
3225 * DISP_E_OVERFLOW, if the value will not fit in the destination
3226 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3228 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3230 return _VarR8FromUI2(usIn, pDblOut);
3233 /************************************************************************
3234 * VarR8FromUI4 (OLEAUT32.219)
3236 * Convert a VT_UI4 to a VT_R8.
3238 * PARAMS
3239 * ulIn [I] Source
3240 * pDblOut [O] Destination
3242 * RETURNS
3243 * Success: S_OK.
3244 * Failure: E_INVALIDARG, if the source value is invalid
3245 * DISP_E_OVERFLOW, if the value will not fit in the destination
3246 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3248 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3250 return _VarR8FromUI4(ulIn, pDblOut);
3253 /************************************************************************
3254 * VarR8FromDec (OLEAUT32.220)
3256 * Convert a VT_DECIMAL to a VT_R8.
3258 * PARAMS
3259 * pDecIn [I] Source
3260 * pDblOut [O] Destination
3262 * RETURNS
3263 * Success: S_OK.
3264 * Failure: E_INVALIDARG, if the source value is invalid.
3266 HRESULT WINAPI VarR8FromDec(const DECIMAL* pDecIn, double *pDblOut)
3268 BYTE scale = DEC_SCALE(pDecIn);
3269 double divisor = 1.0, highPart;
3271 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3272 return E_INVALIDARG;
3274 while (scale--)
3275 divisor *= 10;
3277 if (DEC_SIGN(pDecIn))
3278 divisor = -divisor;
3280 if (DEC_HI32(pDecIn))
3282 highPart = (double)DEC_HI32(pDecIn) / divisor;
3283 highPart *= 4294967296.0F;
3284 highPart *= 4294967296.0F;
3286 else
3287 highPart = 0.0;
3289 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3290 return S_OK;
3293 /************************************************************************
3294 * VarR8FromI8 (OLEAUT32.362)
3296 * Convert a VT_I8 to a VT_R8.
3298 * PARAMS
3299 * ullIn [I] Source
3300 * pDblOut [O] Destination
3302 * RETURNS
3303 * S_OK.
3305 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3307 return _VarR8FromI8(llIn, pDblOut);
3310 /************************************************************************
3311 * VarR8FromUI8 (OLEAUT32.363)
3313 * Convert a VT_UI8 to a VT_R8.
3315 * PARAMS
3316 * ullIn [I] Source
3317 * pDblOut [O] Destination
3319 * RETURNS
3320 * S_OK.
3322 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3324 return _VarR8FromUI8(ullIn, pDblOut);
3327 /************************************************************************
3328 * VarR8Pow (OLEAUT32.315)
3330 * Raise a VT_R8 to a power.
3332 * PARAMS
3333 * dblLeft [I] Source
3334 * dblPow [I] Power to raise dblLeft by
3335 * pDblOut [O] Destination
3337 * RETURNS
3338 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3340 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3342 *pDblOut = pow(dblLeft, dblPow);
3343 return S_OK;
3346 /************************************************************************
3347 * VarR8Round (OLEAUT32.317)
3349 * Round a VT_R8 to a given number of decimal points.
3351 * PARAMS
3352 * dblIn [I] Source
3353 * nDig [I] Number of decimal points to round to
3354 * pDblOut [O] Destination for rounded number
3356 * RETURNS
3357 * Success: S_OK. pDblOut is rounded to nDig digits.
3358 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3360 * NOTES
3361 * The native version of this function rounds using the internal
3362 * binary representation of the number. Wine uses the dutch rounding
3363 * convention, so therefore small differences can occur in the value returned.
3364 * MSDN says that you should use your own rounding function if you want
3365 * rounding to be predictable in your application.
3367 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3369 double scale, whole, fract;
3371 if (nDig < 0)
3372 return E_INVALIDARG;
3374 scale = pow(10.0, nDig);
3376 dblIn *= scale;
3377 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3378 fract = dblIn - whole;
3380 if (fract > 0.5)
3381 dblIn = whole + 1.0;
3382 else if (fract == 0.5)
3383 dblIn = whole + fmod(whole, 2.0);
3384 else if (fract >= 0.0)
3385 dblIn = whole;
3386 else if (fract == -0.5)
3387 dblIn = whole - fmod(whole, 2.0);
3388 else if (fract > -0.5)
3389 dblIn = whole;
3390 else
3391 dblIn = whole - 1.0;
3393 *pDblOut = dblIn / scale;
3394 return S_OK;
3397 /* CY
3400 /* Powers of 10 from 0..4 D.P. */
3401 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3402 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3404 /************************************************************************
3405 * VarCyFromUI1 (OLEAUT32.98)
3407 * Convert a VT_UI1 to a VT_CY.
3409 * PARAMS
3410 * bIn [I] Source
3411 * pCyOut [O] Destination
3413 * RETURNS
3414 * Success: S_OK.
3415 * Failure: E_INVALIDARG, if the source value is invalid
3416 * DISP_E_OVERFLOW, if the value will not fit in the destination
3417 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3419 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3421 pCyOut->int64 = (ULONG64)bIn * CY_MULTIPLIER;
3422 return S_OK;
3425 /************************************************************************
3426 * VarCyFromI2 (OLEAUT32.99)
3428 * Convert a VT_I2 to a VT_CY.
3430 * PARAMS
3431 * sIn [I] Source
3432 * pCyOut [O] Destination
3434 * RETURNS
3435 * Success: S_OK.
3436 * Failure: E_INVALIDARG, if the source value is invalid
3437 * DISP_E_OVERFLOW, if the value will not fit in the destination
3438 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3440 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3442 pCyOut->int64 = (LONG64)sIn * CY_MULTIPLIER;
3443 return S_OK;
3446 /************************************************************************
3447 * VarCyFromI4 (OLEAUT32.100)
3449 * Convert a VT_I4 to a VT_CY.
3451 * PARAMS
3452 * sIn [I] Source
3453 * pCyOut [O] Destination
3455 * RETURNS
3456 * Success: S_OK.
3457 * Failure: E_INVALIDARG, if the source value is invalid
3458 * DISP_E_OVERFLOW, if the value will not fit in the destination
3459 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3461 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3463 pCyOut->int64 = (LONG64)lIn * CY_MULTIPLIER;
3464 return S_OK;
3467 /************************************************************************
3468 * VarCyFromR4 (OLEAUT32.101)
3470 * Convert a VT_R4 to a VT_CY.
3472 * PARAMS
3473 * fltIn [I] Source
3474 * pCyOut [O] Destination
3476 * RETURNS
3477 * Success: S_OK.
3478 * Failure: E_INVALIDARG, if the source value is invalid
3479 * DISP_E_OVERFLOW, if the value will not fit in the destination
3480 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3482 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3484 return VarCyFromR8(fltIn, pCyOut);
3487 /************************************************************************
3488 * VarCyFromR8 (OLEAUT32.102)
3490 * Convert a VT_R8 to a VT_CY.
3492 * PARAMS
3493 * dblIn [I] Source
3494 * pCyOut [O] Destination
3496 * RETURNS
3497 * Success: S_OK.
3498 * Failure: E_INVALIDARG, if the source value is invalid
3499 * DISP_E_OVERFLOW, if the value will not fit in the destination
3500 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3502 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3504 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3505 /* This code gives identical results to Win32 on Intel.
3506 * Here we use fp exceptions to catch overflows when storing the value.
3508 static const unsigned short r8_fpcontrol = 0x137f;
3509 static const double r8_multiplier = CY_MULTIPLIER_F;
3510 unsigned short old_fpcontrol, result_fpstatus;
3512 /* Clear exceptions, save the old fp state and load the new state */
3513 __asm__ __volatile__( "fnclex" );
3514 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3515 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3516 /* Perform the conversion. */
3517 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3518 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3519 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3520 /* Save the resulting fp state, load the old state and clear exceptions */
3521 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3522 __asm__ __volatile__( "fnclex" );
3523 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3525 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3526 return DISP_E_OVERFLOW;
3527 #else
3528 /* This version produces slightly different results for boundary cases */
3529 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3530 return DISP_E_OVERFLOW;
3531 dblIn *= CY_MULTIPLIER_F;
3532 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3533 #endif
3534 return S_OK;
3537 /************************************************************************
3538 * VarCyFromDate (OLEAUT32.103)
3540 * Convert a VT_DATE to a VT_CY.
3542 * PARAMS
3543 * dateIn [I] Source
3544 * pCyOut [O] Destination
3546 * RETURNS
3547 * Success: S_OK.
3548 * Failure: E_INVALIDARG, if the source value is invalid
3549 * DISP_E_OVERFLOW, if the value will not fit in the destination
3550 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3552 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3554 return VarCyFromR8(dateIn, pCyOut);
3557 /************************************************************************
3558 * VarCyFromStr (OLEAUT32.104)
3560 * Convert a VT_BSTR to a VT_CY.
3562 * PARAMS
3563 * strIn [I] Source
3564 * lcid [I] LCID for the conversion
3565 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3566 * pCyOut [O] Destination
3568 * RETURNS
3569 * Success: S_OK.
3570 * Failure: E_INVALIDARG, if the source value is invalid
3571 * DISP_E_OVERFLOW, if the value will not fit in the destination
3572 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3574 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3576 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3579 /************************************************************************
3580 * VarCyFromDisp (OLEAUT32.105)
3582 * Convert a VT_DISPATCH to a VT_CY.
3584 * PARAMS
3585 * pdispIn [I] Source
3586 * lcid [I] LCID for conversion
3587 * pCyOut [O] Destination
3589 * RETURNS
3590 * Success: S_OK.
3591 * Failure: E_INVALIDARG, if the source value is invalid
3592 * DISP_E_OVERFLOW, if the value will not fit in the destination
3593 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3595 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3597 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0);
3600 /************************************************************************
3601 * VarCyFromBool (OLEAUT32.106)
3603 * Convert a VT_BOOL to a VT_CY.
3605 * PARAMS
3606 * boolIn [I] Source
3607 * pCyOut [O] Destination
3609 * RETURNS
3610 * Success: S_OK.
3611 * Failure: E_INVALIDARG, if the source value is invalid
3612 * DISP_E_OVERFLOW, if the value will not fit in the destination
3613 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3615 * NOTES
3616 * While the sign of the boolean is stored in the currency, the value is
3617 * converted to either 0 or 1.
3619 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3621 pCyOut->int64 = (LONG64)boolIn * CY_MULTIPLIER;
3622 return S_OK;
3625 /************************************************************************
3626 * VarCyFromI1 (OLEAUT32.225)
3628 * Convert a VT_I1 to a VT_CY.
3630 * PARAMS
3631 * cIn [I] Source
3632 * pCyOut [O] Destination
3634 * RETURNS
3635 * Success: S_OK.
3636 * Failure: E_INVALIDARG, if the source value is invalid
3637 * DISP_E_OVERFLOW, if the value will not fit in the destination
3638 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3640 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3642 pCyOut->int64 = (LONG64)cIn * CY_MULTIPLIER;
3643 return S_OK;
3646 /************************************************************************
3647 * VarCyFromUI2 (OLEAUT32.226)
3649 * Convert a VT_UI2 to a VT_CY.
3651 * PARAMS
3652 * usIn [I] Source
3653 * pCyOut [O] Destination
3655 * RETURNS
3656 * Success: S_OK.
3657 * Failure: E_INVALIDARG, if the source value is invalid
3658 * DISP_E_OVERFLOW, if the value will not fit in the destination
3659 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3661 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3663 pCyOut->int64 = (ULONG64)usIn * CY_MULTIPLIER;
3664 return S_OK;
3667 /************************************************************************
3668 * VarCyFromUI4 (OLEAUT32.227)
3670 * Convert a VT_UI4 to a VT_CY.
3672 * PARAMS
3673 * ulIn [I] Source
3674 * pCyOut [O] Destination
3676 * RETURNS
3677 * Success: S_OK.
3678 * Failure: E_INVALIDARG, if the source value is invalid
3679 * DISP_E_OVERFLOW, if the value will not fit in the destination
3680 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3682 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3684 pCyOut->int64 = (ULONG64)ulIn * CY_MULTIPLIER;
3685 return S_OK;
3688 /************************************************************************
3689 * VarCyFromDec (OLEAUT32.228)
3691 * Convert a VT_DECIMAL to a VT_CY.
3693 * PARAMS
3694 * pdecIn [I] Source
3695 * pCyOut [O] Destination
3697 * RETURNS
3698 * Success: S_OK.
3699 * Failure: E_INVALIDARG, if the source value is invalid
3700 * DISP_E_OVERFLOW, if the value will not fit in the destination
3701 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3703 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
3705 DECIMAL rounded;
3706 HRESULT hRet;
3708 hRet = VarDecRound(pdecIn, 4, &rounded);
3710 if (SUCCEEDED(hRet))
3712 double d;
3714 if (DEC_HI32(&rounded))
3715 return DISP_E_OVERFLOW;
3717 /* Note: Without the casts this promotes to int64 which loses precision */
3718 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3719 if (DEC_SIGN(&rounded))
3720 d = -d;
3721 return VarCyFromR8(d, pCyOut);
3723 return hRet;
3726 /************************************************************************
3727 * VarCyFromI8 (OLEAUT32.366)
3729 * Convert a VT_I8 to a VT_CY.
3731 * PARAMS
3732 * ullIn [I] Source
3733 * pCyOut [O] Destination
3735 * RETURNS
3736 * Success: S_OK.
3737 * Failure: E_INVALIDARG, if the source value is invalid
3738 * DISP_E_OVERFLOW, if the value will not fit in the destination
3739 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3741 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3743 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3744 pCyOut->int64 = llIn * CY_MULTIPLIER;
3745 return S_OK;
3748 /************************************************************************
3749 * VarCyFromUI8 (OLEAUT32.375)
3751 * Convert a VT_UI8 to a VT_CY.
3753 * PARAMS
3754 * ullIn [I] Source
3755 * pCyOut [O] Destination
3757 * RETURNS
3758 * Success: S_OK.
3759 * Failure: E_INVALIDARG, if the source value is invalid
3760 * DISP_E_OVERFLOW, if the value will not fit in the destination
3761 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3763 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3765 if (ullIn > (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3766 pCyOut->int64 = ullIn * CY_MULTIPLIER;
3767 return S_OK;
3770 /************************************************************************
3771 * VarCyAdd (OLEAUT32.299)
3773 * Add one CY to another.
3775 * PARAMS
3776 * cyLeft [I] Source
3777 * cyRight [I] Value to add
3778 * pCyOut [O] Destination
3780 * RETURNS
3781 * Success: S_OK.
3782 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3784 HRESULT WINAPI VarCyAdd(CY cyLeft, CY cyRight, CY* pCyOut)
3786 double l,r;
3787 _VarR8FromCy(cyLeft, &l);
3788 _VarR8FromCy(cyRight, &r);
3789 l = l + r;
3790 return VarCyFromR8(l, pCyOut);
3793 /************************************************************************
3794 * VarCyMul (OLEAUT32.303)
3796 * Multiply one CY by another.
3798 * PARAMS
3799 * cyLeft [I] Source
3800 * cyRight [I] Value to multiply by
3801 * pCyOut [O] Destination
3803 * RETURNS
3804 * Success: S_OK.
3805 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3807 HRESULT WINAPI VarCyMul(CY cyLeft, CY cyRight, CY* pCyOut)
3809 double l,r;
3810 _VarR8FromCy(cyLeft, &l);
3811 _VarR8FromCy(cyRight, &r);
3812 l = l * r;
3813 return VarCyFromR8(l, pCyOut);
3816 /************************************************************************
3817 * VarCyMulI4 (OLEAUT32.304)
3819 * Multiply one CY by a VT_I4.
3821 * PARAMS
3822 * cyLeft [I] Source
3823 * lRight [I] Value to multiply by
3824 * pCyOut [O] Destination
3826 * RETURNS
3827 * Success: S_OK.
3828 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3830 HRESULT WINAPI VarCyMulI4(CY cyLeft, LONG lRight, CY* pCyOut)
3832 double d;
3834 _VarR8FromCy(cyLeft, &d);
3835 d = d * lRight;
3836 return VarCyFromR8(d, pCyOut);
3839 /************************************************************************
3840 * VarCySub (OLEAUT32.305)
3842 * Subtract one CY from another.
3844 * PARAMS
3845 * cyLeft [I] Source
3846 * cyRight [I] Value to subtract
3847 * pCyOut [O] Destination
3849 * RETURNS
3850 * Success: S_OK.
3851 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3853 HRESULT WINAPI VarCySub(CY cyLeft, CY cyRight, CY* pCyOut)
3855 double l,r;
3856 _VarR8FromCy(cyLeft, &l);
3857 _VarR8FromCy(cyRight, &r);
3858 l = l - r;
3859 return VarCyFromR8(l, pCyOut);
3862 /************************************************************************
3863 * VarCyAbs (OLEAUT32.306)
3865 * Convert a VT_CY into its absolute value.
3867 * PARAMS
3868 * cyIn [I] Source
3869 * pCyOut [O] Destination
3871 * RETURNS
3872 * Success: S_OK. pCyOut contains the absolute value.
3873 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3875 HRESULT WINAPI VarCyAbs(CY cyIn, CY* pCyOut)
3877 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3878 return DISP_E_OVERFLOW;
3880 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3881 return S_OK;
3884 /************************************************************************
3885 * VarCyFix (OLEAUT32.307)
3887 * Return the integer part of a VT_CY.
3889 * PARAMS
3890 * cyIn [I] Source
3891 * pCyOut [O] Destination
3893 * RETURNS
3894 * Success: S_OK.
3895 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3897 * NOTES
3898 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3899 * negative numbers away from 0, while this function rounds them towards zero.
3901 HRESULT WINAPI VarCyFix(CY cyIn, CY* pCyOut)
3903 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3904 pCyOut->int64 *= CY_MULTIPLIER;
3905 return S_OK;
3908 /************************************************************************
3909 * VarCyInt (OLEAUT32.308)
3911 * Return the integer part of a VT_CY.
3913 * PARAMS
3914 * cyIn [I] Source
3915 * pCyOut [O] Destination
3917 * RETURNS
3918 * Success: S_OK.
3919 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3921 * NOTES
3922 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3923 * negative numbers towards 0, while this function rounds them away from zero.
3925 HRESULT WINAPI VarCyInt(CY cyIn, CY* pCyOut)
3927 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3928 pCyOut->int64 *= CY_MULTIPLIER;
3930 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3932 pCyOut->int64 -= CY_MULTIPLIER;
3934 return S_OK;
3937 /************************************************************************
3938 * VarCyNeg (OLEAUT32.309)
3940 * Change the sign of a VT_CY.
3942 * PARAMS
3943 * cyIn [I] Source
3944 * pCyOut [O] Destination
3946 * RETURNS
3947 * Success: S_OK.
3948 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3950 HRESULT WINAPI VarCyNeg(CY cyIn, CY* pCyOut)
3952 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3953 return DISP_E_OVERFLOW;
3955 pCyOut->int64 = -cyIn.int64;
3956 return S_OK;
3959 /************************************************************************
3960 * VarCyRound (OLEAUT32.310)
3962 * Change the precision of a VT_CY.
3964 * PARAMS
3965 * cyIn [I] Source
3966 * cDecimals [I] New number of decimals to keep
3967 * pCyOut [O] Destination
3969 * RETURNS
3970 * Success: S_OK.
3971 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3973 HRESULT WINAPI VarCyRound(CY cyIn, int cDecimals, CY* pCyOut)
3975 if (cDecimals < 0)
3976 return E_INVALIDARG;
3978 if (cDecimals > 3)
3980 /* Rounding to more precision than we have */
3981 *pCyOut = cyIn;
3982 return S_OK;
3984 else
3986 double d, div = CY_Divisors[cDecimals];
3988 _VarR8FromCy(cyIn, &d);
3989 d = d * div;
3990 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3991 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3992 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3993 return S_OK;
3997 /************************************************************************
3998 * VarCyCmp (OLEAUT32.311)
4000 * Compare two VT_CY values.
4002 * PARAMS
4003 * cyLeft [I] Source
4004 * cyRight [I] Value to compare
4006 * RETURNS
4007 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4008 * compare is less, equal or greater than source respectively.
4009 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4011 HRESULT WINAPI VarCyCmp(CY cyLeft, CY cyRight)
4013 HRESULT hRet;
4014 CY result;
4016 /* Subtract right from left, and compare the result to 0 */
4017 hRet = VarCySub(cyLeft, cyRight, &result);
4019 if (SUCCEEDED(hRet))
4021 if (result.int64 < 0)
4022 hRet = (HRESULT)VARCMP_LT;
4023 else if (result.int64 > 0)
4024 hRet = (HRESULT)VARCMP_GT;
4025 else
4026 hRet = (HRESULT)VARCMP_EQ;
4028 return hRet;
4031 /************************************************************************
4032 * VarCyCmpR8 (OLEAUT32.312)
4034 * Compare a VT_CY to a double
4036 * PARAMS
4037 * cyLeft [I] Currency Source
4038 * dblRight [I] double to compare to cyLeft
4040 * RETURNS
4041 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4042 * less than, equal to or greater than cyLeft respectively.
4043 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4045 HRESULT WINAPI VarCyCmpR8(CY cyLeft, double dblRight)
4047 HRESULT hRet;
4048 CY cyRight;
4050 hRet = VarCyFromR8(dblRight, &cyRight);
4052 if (SUCCEEDED(hRet))
4053 hRet = VarCyCmp(cyLeft, cyRight);
4055 return hRet;
4058 /************************************************************************
4059 * VarCyMulI8 (OLEAUT32.329)
4061 * Multiply a VT_CY by a VT_I8.
4063 * PARAMS
4064 * cyLeft [I] Source
4065 * llRight [I] Value to multiply by
4066 * pCyOut [O] Destination
4068 * RETURNS
4069 * Success: S_OK.
4070 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4072 HRESULT WINAPI VarCyMulI8(CY cyLeft, LONG64 llRight, CY* pCyOut)
4074 double d;
4076 _VarR8FromCy(cyLeft, &d);
4077 d = d * (double)llRight;
4078 return VarCyFromR8(d, pCyOut);
4081 /* DECIMAL
4084 /************************************************************************
4085 * VarDecFromUI1 (OLEAUT32.190)
4087 * Convert a VT_UI1 to a DECIMAL.
4089 * PARAMS
4090 * bIn [I] Source
4091 * pDecOut [O] Destination
4093 * RETURNS
4094 * S_OK.
4096 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4098 return VarDecFromUI4(bIn, pDecOut);
4101 /************************************************************************
4102 * VarDecFromI2 (OLEAUT32.191)
4104 * Convert a VT_I2 to a DECIMAL.
4106 * PARAMS
4107 * sIn [I] Source
4108 * pDecOut [O] Destination
4110 * RETURNS
4111 * S_OK.
4113 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4115 return VarDecFromI4(sIn, pDecOut);
4118 /************************************************************************
4119 * VarDecFromI4 (OLEAUT32.192)
4121 * Convert a VT_I4 to a DECIMAL.
4123 * PARAMS
4124 * sIn [I] Source
4125 * pDecOut [O] Destination
4127 * RETURNS
4128 * S_OK.
4130 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4132 DEC_HI32(pDecOut) = 0;
4133 DEC_MID32(pDecOut) = 0;
4135 if (lIn < 0)
4137 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4138 DEC_LO32(pDecOut) = -lIn;
4140 else
4142 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4143 DEC_LO32(pDecOut) = lIn;
4145 return S_OK;
4148 /* internal representation of the value stored in a DECIMAL. The bytes are
4149 stored from LSB at index 0 to MSB at index 11
4151 typedef struct DECIMAL_internal
4153 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4154 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4155 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4156 } VARIANT_DI;
4158 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest);
4159 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest);
4160 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to);
4161 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to);
4162 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor);
4163 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n);
4165 /************************************************************************
4166 * VarDecFromR4 (OLEAUT32.193)
4168 * Convert a VT_R4 to a DECIMAL.
4170 * PARAMS
4171 * fltIn [I] Source
4172 * pDecOut [O] Destination
4174 * RETURNS
4175 * S_OK.
4177 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4179 VARIANT_DI di;
4180 HRESULT hres;
4182 hres = VARIANT_DI_FromR4(fltIn, &di);
4183 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4184 return hres;
4187 /************************************************************************
4188 * VarDecFromR8 (OLEAUT32.194)
4190 * Convert a VT_R8 to a DECIMAL.
4192 * PARAMS
4193 * dblIn [I] Source
4194 * pDecOut [O] Destination
4196 * RETURNS
4197 * S_OK.
4199 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4201 VARIANT_DI di;
4202 HRESULT hres;
4204 hres = VARIANT_DI_FromR8(dblIn, &di);
4205 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4206 return hres;
4209 /************************************************************************
4210 * VarDecFromDate (OLEAUT32.195)
4212 * Convert a VT_DATE to a DECIMAL.
4214 * PARAMS
4215 * dateIn [I] Source
4216 * pDecOut [O] Destination
4218 * RETURNS
4219 * S_OK.
4221 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4223 return VarDecFromR8(dateIn, pDecOut);
4226 /************************************************************************
4227 * VarDecFromCy (OLEAUT32.196)
4229 * Convert a VT_CY to a DECIMAL.
4231 * PARAMS
4232 * cyIn [I] Source
4233 * pDecOut [O] Destination
4235 * RETURNS
4236 * S_OK.
4238 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4240 DEC_HI32(pDecOut) = 0;
4242 /* Note: This assumes 2s complement integer representation */
4243 if (cyIn.s.Hi & 0x80000000)
4245 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4246 DEC_LO64(pDecOut) = -cyIn.int64;
4248 else
4250 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4251 DEC_MID32(pDecOut) = cyIn.s.Hi;
4252 DEC_LO32(pDecOut) = cyIn.s.Lo;
4254 return S_OK;
4257 /************************************************************************
4258 * VarDecFromStr (OLEAUT32.197)
4260 * Convert a VT_BSTR to a DECIMAL.
4262 * PARAMS
4263 * strIn [I] Source
4264 * lcid [I] LCID for the conversion
4265 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4266 * pDecOut [O] Destination
4268 * RETURNS
4269 * Success: S_OK.
4270 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4272 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4274 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4277 /************************************************************************
4278 * VarDecFromDisp (OLEAUT32.198)
4280 * Convert a VT_DISPATCH to a DECIMAL.
4282 * PARAMS
4283 * pdispIn [I] Source
4284 * lcid [I] LCID for conversion
4285 * pDecOut [O] Destination
4287 * RETURNS
4288 * Success: S_OK.
4289 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4291 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4293 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0);
4296 /************************************************************************
4297 * VarDecFromBool (OLEAUT32.199)
4299 * Convert a VT_BOOL to a DECIMAL.
4301 * PARAMS
4302 * bIn [I] Source
4303 * pDecOut [O] Destination
4305 * RETURNS
4306 * S_OK.
4308 * NOTES
4309 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4311 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4313 DEC_HI32(pDecOut) = 0;
4314 DEC_MID32(pDecOut) = 0;
4315 if (bIn)
4317 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4318 DEC_LO32(pDecOut) = 1;
4320 else
4322 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4323 DEC_LO32(pDecOut) = 0;
4325 return S_OK;
4328 /************************************************************************
4329 * VarDecFromI1 (OLEAUT32.241)
4331 * Convert a VT_I1 to a DECIMAL.
4333 * PARAMS
4334 * cIn [I] Source
4335 * pDecOut [O] Destination
4337 * RETURNS
4338 * S_OK.
4340 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4342 return VarDecFromI4(cIn, pDecOut);
4345 /************************************************************************
4346 * VarDecFromUI2 (OLEAUT32.242)
4348 * Convert a VT_UI2 to a DECIMAL.
4350 * PARAMS
4351 * usIn [I] Source
4352 * pDecOut [O] Destination
4354 * RETURNS
4355 * S_OK.
4357 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4359 return VarDecFromUI4(usIn, pDecOut);
4362 /************************************************************************
4363 * VarDecFromUI4 (OLEAUT32.243)
4365 * Convert a VT_UI4 to a DECIMAL.
4367 * PARAMS
4368 * ulIn [I] Source
4369 * pDecOut [O] Destination
4371 * RETURNS
4372 * S_OK.
4374 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4376 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4377 DEC_HI32(pDecOut) = 0;
4378 DEC_MID32(pDecOut) = 0;
4379 DEC_LO32(pDecOut) = ulIn;
4380 return S_OK;
4383 /************************************************************************
4384 * VarDecFromI8 (OLEAUT32.374)
4386 * Convert a VT_I8 to a DECIMAL.
4388 * PARAMS
4389 * llIn [I] Source
4390 * pDecOut [O] Destination
4392 * RETURNS
4393 * S_OK.
4395 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4397 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4399 DEC_HI32(pDecOut) = 0;
4401 /* Note: This assumes 2s complement integer representation */
4402 if (pLi->u.HighPart & 0x80000000)
4404 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4405 DEC_LO64(pDecOut) = -pLi->QuadPart;
4407 else
4409 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4410 DEC_MID32(pDecOut) = pLi->u.HighPart;
4411 DEC_LO32(pDecOut) = pLi->u.LowPart;
4413 return S_OK;
4416 /************************************************************************
4417 * VarDecFromUI8 (OLEAUT32.375)
4419 * Convert a VT_UI8 to a DECIMAL.
4421 * PARAMS
4422 * ullIn [I] Source
4423 * pDecOut [O] Destination
4425 * RETURNS
4426 * S_OK.
4428 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4430 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4431 DEC_HI32(pDecOut) = 0;
4432 DEC_LO64(pDecOut) = ullIn;
4433 return S_OK;
4436 /* Make two DECIMALS the same scale; used by math functions below */
4437 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4438 const DECIMAL** ppDecRight,
4439 DECIMAL pDecOut[2])
4441 static DECIMAL scaleFactor;
4442 unsigned char remainder;
4443 DECIMAL decTemp;
4444 VARIANT_DI di;
4445 int scaleAmount, i;
4447 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4448 return E_INVALIDARG;
4450 DEC_LO32(&scaleFactor) = 10;
4452 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4454 if (!scaleAmount)
4455 return S_OK; /* Same scale */
4457 if (scaleAmount > 0)
4459 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4460 *ppDecRight = &pDecOut[0];
4462 else
4464 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4465 *ppDecLeft = &pDecOut[0];
4466 i = -scaleAmount;
4469 /* Multiply up the value to be scaled by the correct amount (if possible) */
4470 while (i > 0 && SUCCEEDED(VarDecMul(&decTemp, &scaleFactor, &pDecOut[0])))
4472 decTemp = pDecOut[0];
4473 i--;
4476 if (!i)
4478 DEC_SCALE(&pDecOut[0]) += (scaleAmount > 0) ? scaleAmount : (-scaleAmount);
4479 return S_OK; /* Same scale */
4482 /* Scaling further not possible, reduce accuracy of other argument */
4483 pDecOut[0] = decTemp;
4484 if (scaleAmount > 0)
4486 DEC_SCALE(&pDecOut[0]) += scaleAmount - i;
4487 VARIANT_DIFromDec(*ppDecLeft, &di);
4488 *ppDecLeft = &pDecOut[1];
4490 else
4492 DEC_SCALE(&pDecOut[0]) += (-scaleAmount) - i;
4493 VARIANT_DIFromDec(*ppDecRight, &di);
4494 *ppDecRight = &pDecOut[1];
4497 di.scale -= i;
4498 remainder = 0;
4499 while (i-- > 0 && !VARIANT_int_iszero(di.bitsnum, ARRAY_SIZE(di.bitsnum)))
4501 remainder = VARIANT_int_divbychar(di.bitsnum, ARRAY_SIZE(di.bitsnum), 10);
4502 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4505 /* round up the result - native oleaut32 does this */
4506 if (remainder >= 5) {
4507 for (remainder = 1, i = 0; i < ARRAY_SIZE(di.bitsnum) && remainder; i++) {
4508 ULONGLONG digit = di.bitsnum[i] + 1;
4509 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4510 di.bitsnum[i] = digit & 0xFFFFFFFF;
4514 VARIANT_DecFromDI(&di, &pDecOut[1]);
4515 return S_OK;
4518 /* Add two unsigned 32 bit values with overflow */
4519 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4521 ULARGE_INTEGER ul64;
4523 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4524 *pulHigh = ul64.u.HighPart;
4525 return ul64.u.LowPart;
4528 /* Subtract two unsigned 32 bit values with underflow */
4529 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4531 BOOL invert = FALSE;
4532 ULARGE_INTEGER ul64;
4534 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4535 if (ulLeft < ulRight)
4536 invert = TRUE;
4538 if (ul64.QuadPart > (ULONG64)*pulHigh)
4539 ul64.QuadPart -= (ULONG64)*pulHigh;
4540 else
4542 ul64.QuadPart -= (ULONG64)*pulHigh;
4543 invert = TRUE;
4545 if (invert)
4546 ul64.u.HighPart = -ul64.u.HighPart ;
4548 *pulHigh = ul64.u.HighPart;
4549 return ul64.u.LowPart;
4552 /* Multiply two unsigned 32 bit values with overflow */
4553 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4555 ULARGE_INTEGER ul64;
4557 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4558 *pulHigh = ul64.u.HighPart;
4559 return ul64.u.LowPart;
4562 /* Compare two decimals that have the same scale */
4563 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4565 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4566 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4567 return -1;
4568 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4569 return 0;
4570 return 1;
4573 /************************************************************************
4574 * VarDecAdd (OLEAUT32.177)
4576 * Add one DECIMAL to another.
4578 * PARAMS
4579 * pDecLeft [I] Source
4580 * pDecRight [I] Value to add
4581 * pDecOut [O] Destination
4583 * RETURNS
4584 * Success: S_OK.
4585 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4587 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4589 HRESULT hRet;
4590 DECIMAL scaled[2];
4592 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, scaled);
4594 if (SUCCEEDED(hRet))
4596 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4597 ULONG overflow = 0;
4598 BYTE sign = DECIMAL_POS;
4599 int cmp;
4601 /* Correct for the sign of the result */
4602 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4604 /* -x + -y : Negative */
4605 sign = DECIMAL_NEG;
4606 goto VarDecAdd_AsPositive;
4608 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4610 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4612 /* -x + y : Negative if x > y */
4613 if (cmp > 0)
4615 sign = DECIMAL_NEG;
4616 VarDecAdd_AsNegative:
4617 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4618 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4619 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4621 else
4623 VarDecAdd_AsInvertedNegative:
4624 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4625 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4626 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4629 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4631 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4633 /* x + -y : Negative if x <= y */
4634 if (cmp <= 0)
4636 sign = DECIMAL_NEG;
4637 goto VarDecAdd_AsInvertedNegative;
4639 goto VarDecAdd_AsNegative;
4641 else
4643 /* x + y : Positive */
4644 VarDecAdd_AsPositive:
4645 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4646 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4647 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4650 if (overflow)
4651 return DISP_E_OVERFLOW; /* overflowed */
4653 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4654 DEC_SIGN(pDecOut) = sign;
4656 return hRet;
4659 /* translate from external DECIMAL format into an internal representation */
4660 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4662 to->scale = DEC_SCALE(from);
4663 to->sign = DEC_SIGN(from) ? 1 : 0;
4665 to->bitsnum[0] = DEC_LO32(from);
4666 to->bitsnum[1] = DEC_MID32(from);
4667 to->bitsnum[2] = DEC_HI32(from);
4670 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to)
4672 if (from->sign) {
4673 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4674 } else {
4675 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4678 DEC_LO32(to) = from->bitsnum[0];
4679 DEC_MID32(to) = from->bitsnum[1];
4680 DEC_HI32(to) = from->bitsnum[2];
4683 /* clear an internal representation of a DECIMAL */
4684 static void VARIANT_DI_clear(VARIANT_DI * i)
4686 memset(i, 0, sizeof(VARIANT_DI));
4689 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4690 size is supported. The value in p is replaced by the quotient of the division, and
4691 the remainder is returned as a result. This routine is most often used with a divisor
4692 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4694 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4696 if (divisor == 0) {
4697 /* division by 0 */
4698 return 0xFF;
4699 } else if (divisor == 1) {
4700 /* dividend remains unchanged */
4701 return 0;
4702 } else {
4703 unsigned char remainder = 0;
4704 ULONGLONG iTempDividend;
4705 signed int i;
4707 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4708 for (; i >= 0; i--) {
4709 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4710 remainder = iTempDividend % divisor;
4711 p[i] = iTempDividend / divisor;
4714 return remainder;
4718 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4719 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n)
4721 for (; n > 0; n--) if (*p++ != 0) return FALSE;
4722 return TRUE;
4725 /* multiply two DECIMALS, without changing either one, and place result in third
4726 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4727 digits when scale > 0 in order to fit an overflowing result. Final overflow
4728 flag is returned.
4730 static int VARIANT_DI_mul(const VARIANT_DI * a, const VARIANT_DI * b, VARIANT_DI * result)
4732 BOOL r_overflow = FALSE;
4733 DWORD running[6];
4734 signed int mulstart;
4736 VARIANT_DI_clear(result);
4737 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4739 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4740 of the result is formed by adding the scales of the operands.
4742 result->scale = a->scale + b->scale;
4743 memset(running, 0, sizeof(running));
4745 /* count number of leading zero-bytes in operand A */
4746 for (mulstart = ARRAY_SIZE(a->bitsnum) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4747 if (mulstart < 0) {
4748 /* result is 0, because operand A is 0 */
4749 result->scale = 0;
4750 result->sign = 0;
4751 } else {
4752 unsigned char remainder = 0;
4753 int iA;
4755 /* perform actual multiplication */
4756 for (iA = 0; iA <= mulstart; iA++) {
4757 ULONG iOverflowMul;
4758 int iB;
4760 for (iOverflowMul = 0, iB = 0; iB < ARRAY_SIZE(b->bitsnum); iB++) {
4761 ULONG iRV;
4762 int iR;
4764 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4765 iR = iA + iB;
4766 do {
4767 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4768 iR++;
4769 } while (iRV);
4773 /* Too bad - native oleaut does not do this, so we should not either */
4774 #if 0
4775 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4776 This operation should not lose significant digits, and gives an
4777 opportunity to reduce the possibility of overflows in future
4778 operations issued by the application.
4780 while (result->scale > 0) {
4781 memcpy(quotient, running, sizeof(quotient));
4782 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4783 if (remainder > 0) break;
4784 memcpy(running, quotient, sizeof(quotient));
4785 result->scale--;
4787 #endif
4788 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4789 This operation *will* lose significant digits of the result because
4790 all the factors of 10 were consumed by the previous operation.
4792 while (result->scale > 0 && !VARIANT_int_iszero(running + ARRAY_SIZE(result->bitsnum),
4793 ARRAY_SIZE(running) - ARRAY_SIZE(result->bitsnum))) {
4795 remainder = VARIANT_int_divbychar(running, ARRAY_SIZE(running), 10);
4796 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4797 result->scale--;
4800 /* round up the result - native oleaut32 does this */
4801 if (remainder >= 5) {
4802 unsigned int i;
4803 for (remainder = 1, i = 0; i < ARRAY_SIZE(running) && remainder; i++) {
4804 ULONGLONG digit = running[i] + 1;
4805 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4806 running[i] = digit & 0xFFFFFFFF;
4810 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4811 and copy result bits into result structure
4813 r_overflow = !VARIANT_int_iszero(running + ARRAY_SIZE(result->bitsnum),
4814 ARRAY_SIZE(running) - ARRAY_SIZE(result->bitsnum));
4815 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4817 return r_overflow;
4820 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4821 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4822 success, FALSE if insufficient space in output buffer.
4824 static BOOL VARIANT_DI_tostringW(const VARIANT_DI * a, WCHAR * s, unsigned int n)
4826 BOOL overflow = FALSE;
4827 DWORD quotient[3];
4828 unsigned char remainder;
4829 unsigned int i;
4831 /* place negative sign */
4832 if (!VARIANT_int_iszero(a->bitsnum, ARRAY_SIZE(a->bitsnum)) && a->sign) {
4833 if (n > 0) {
4834 *s++ = '-';
4835 n--;
4837 else overflow = TRUE;
4840 /* prepare initial 0 */
4841 if (!overflow) {
4842 if (n >= 2) {
4843 s[0] = '0';
4844 s[1] = '\0';
4845 } else overflow = TRUE;
4848 i = 0;
4849 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4850 while (!overflow && !VARIANT_int_iszero(quotient, ARRAY_SIZE(quotient))) {
4851 remainder = VARIANT_int_divbychar(quotient, ARRAY_SIZE(quotient), 10);
4852 if (i + 2 > n) {
4853 overflow = TRUE;
4854 } else {
4855 s[i++] = '0' + remainder;
4856 s[i] = '\0';
4860 if (!overflow && !VARIANT_int_iszero(a->bitsnum, ARRAY_SIZE(a->bitsnum))) {
4862 /* reverse order of digits */
4863 WCHAR * x = s; WCHAR * y = s + i - 1;
4864 while (x < y) {
4865 *x ^= *y;
4866 *y ^= *x;
4867 *x++ ^= *y--;
4870 /* check for decimal point. "i" now has string length */
4871 if (i <= a->scale) {
4872 unsigned int numzeroes = a->scale + 1 - i;
4873 if (i + 1 + numzeroes >= n) {
4874 overflow = TRUE;
4875 } else {
4876 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4877 i += numzeroes;
4878 while (numzeroes > 0) {
4879 s[--numzeroes] = '0';
4884 /* place decimal point */
4885 if (a->scale > 0) {
4886 unsigned int periodpos = i - a->scale;
4887 if (i + 2 >= n) {
4888 overflow = TRUE;
4889 } else {
4890 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4891 s[periodpos] = '.'; i++;
4893 /* remove extra zeros at the end, if any */
4894 while (s[i - 1] == '0') s[--i] = '\0';
4895 if (s[i - 1] == '.') s[--i] = '\0';
4900 return !overflow;
4903 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4904 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4906 DWORD shifted;
4907 unsigned int i;
4909 /* shift whole DWORDs to the left */
4910 while (shift >= 32)
4912 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4913 *p = 0; shift -= 32;
4916 /* shift remainder (1..31 bits) */
4917 shifted = 0;
4918 if (shift > 0) for (i = 0; i < n; i++)
4920 DWORD b;
4921 b = p[i] >> (32 - shift);
4922 p[i] = (p[i] << shift) | shifted;
4923 shifted = b;
4927 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4928 Value at v is incremented by the value at p. Any size is supported, provided
4929 that v is not shorter than p. Any unapplied carry is returned as a result.
4931 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, const DWORD * p,
4932 unsigned int np)
4934 unsigned char carry = 0;
4936 if (nv >= np) {
4937 ULONGLONG sum;
4938 unsigned int i;
4940 for (i = 0; i < np; i++) {
4941 sum = (ULONGLONG)v[i]
4942 + (ULONGLONG)p[i]
4943 + (ULONGLONG)carry;
4944 v[i] = sum & 0xffffffff;
4945 carry = sum >> 32;
4947 for (; i < nv && carry; i++) {
4948 sum = (ULONGLONG)v[i]
4949 + (ULONGLONG)carry;
4950 v[i] = sum & 0xffffffff;
4951 carry = sum >> 32;
4954 return carry;
4957 /* perform integral division with operand p as dividend. Parameter n indicates
4958 number of available DWORDs in divisor p, but available space in p must be
4959 actually at least 2 * n DWORDs, because the remainder of the integral
4960 division is built in the next n DWORDs past the start of the quotient. This
4961 routine replaces the dividend in p with the quotient, and appends n
4962 additional DWORDs for the remainder.
4964 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4965 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4966 source code to the VLI (Very Large Integer) division operator. This algorithm
4967 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4968 variably-scaled integers such as the MS DECIMAL representation.
4970 static void VARIANT_int_div(DWORD * p, unsigned int n, const DWORD * divisor,
4971 unsigned int dn)
4973 unsigned int i;
4974 DWORD tempsub[8];
4975 DWORD * negdivisor = tempsub + n;
4977 /* build 2s-complement of divisor */
4978 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
4979 p[n] = 1;
4980 VARIANT_int_add(negdivisor, n, p + n, 1);
4981 memset(p + n, 0, n * sizeof(DWORD));
4983 /* skip all leading zero DWORDs in quotient */
4984 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
4985 /* i is now number of DWORDs left to process */
4986 for (i <<= 5; i < (n << 5); i++) {
4987 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
4989 /* trial subtraction */
4990 memcpy(tempsub, p + n, n * sizeof(DWORD));
4991 VARIANT_int_add(tempsub, n, negdivisor, n);
4993 /* check whether result of subtraction was negative */
4994 if ((tempsub[n - 1] & 0x80000000) == 0) {
4995 memcpy(p + n, tempsub, n * sizeof(DWORD));
4996 p[0] |= 1;
5001 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
5002 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
5004 unsigned int i;
5005 ULONG iOverflowMul;
5007 for (iOverflowMul = 0, i = 0; i < n; i++)
5008 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
5009 return (unsigned char)iOverflowMul;
5012 /* increment value in A by the value indicated in B, with scale adjusting.
5013 Modifies parameters by adjusting scales. Returns 0 if addition was
5014 successful, nonzero if a parameter underflowed before it could be
5015 successfully used in the addition.
5017 static int VARIANT_int_addlossy(
5018 DWORD * a, int * ascale, unsigned int an,
5019 DWORD * b, int * bscale, unsigned int bn)
5021 int underflow = 0;
5023 if (VARIANT_int_iszero(a, an)) {
5024 /* if A is zero, copy B into A, after removing digits */
5025 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
5026 VARIANT_int_divbychar(b, bn, 10);
5027 (*bscale)--;
5029 memcpy(a, b, an * sizeof(DWORD));
5030 *ascale = *bscale;
5031 } else if (!VARIANT_int_iszero(b, bn)) {
5032 unsigned int tn = an + 1;
5033 DWORD t[5];
5035 if (bn + 1 > tn) tn = bn + 1;
5036 if (*ascale != *bscale) {
5037 /* first (optimistic) try - try to scale down the one with the bigger
5038 scale, while this number is divisible by 10 */
5039 DWORD * digitchosen;
5040 unsigned int nchosen;
5041 int * scalechosen;
5042 int targetscale;
5044 if (*ascale < *bscale) {
5045 targetscale = *ascale;
5046 scalechosen = bscale;
5047 digitchosen = b;
5048 nchosen = bn;
5049 } else {
5050 targetscale = *bscale;
5051 scalechosen = ascale;
5052 digitchosen = a;
5053 nchosen = an;
5055 memset(t, 0, tn * sizeof(DWORD));
5056 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5058 /* divide by 10 until target scale is reached */
5059 while (*scalechosen > targetscale) {
5060 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5061 if (!remainder) {
5062 (*scalechosen)--;
5063 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5064 } else break;
5068 if (*ascale != *bscale) {
5069 DWORD * digitchosen;
5070 unsigned int nchosen;
5071 int * scalechosen;
5072 int targetscale;
5074 /* try to scale up the one with the smaller scale */
5075 if (*ascale > *bscale) {
5076 targetscale = *ascale;
5077 scalechosen = bscale;
5078 digitchosen = b;
5079 nchosen = bn;
5080 } else {
5081 targetscale = *bscale;
5082 scalechosen = ascale;
5083 digitchosen = a;
5084 nchosen = an;
5086 memset(t, 0, tn * sizeof(DWORD));
5087 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5089 /* multiply by 10 until target scale is reached, or
5090 significant bytes overflow the number
5092 while (*scalechosen < targetscale && t[nchosen] == 0) {
5093 VARIANT_int_mulbychar(t, tn, 10);
5094 if (t[nchosen] == 0) {
5095 /* still does not overflow */
5096 (*scalechosen)++;
5097 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5102 if (*ascale != *bscale) {
5103 /* still different? try to scale down the one with the bigger scale
5104 (this *will* lose significant digits) */
5105 DWORD * digitchosen;
5106 unsigned int nchosen;
5107 int * scalechosen;
5108 int targetscale;
5110 if (*ascale < *bscale) {
5111 targetscale = *ascale;
5112 scalechosen = bscale;
5113 digitchosen = b;
5114 nchosen = bn;
5115 } else {
5116 targetscale = *bscale;
5117 scalechosen = ascale;
5118 digitchosen = a;
5119 nchosen = an;
5121 memset(t, 0, tn * sizeof(DWORD));
5122 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5124 /* divide by 10 until target scale is reached */
5125 while (*scalechosen > targetscale) {
5126 VARIANT_int_divbychar(t, tn, 10);
5127 (*scalechosen)--;
5128 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5132 /* check whether any of the operands still has significant digits
5133 (underflow case 1)
5135 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5136 underflow = 1;
5137 } else {
5138 /* at this step, both numbers have the same scale and can be added
5139 as integers. However, the result might not fit in A, so further
5140 scaling down might be necessary.
5142 while (!underflow) {
5143 memset(t, 0, tn * sizeof(DWORD));
5144 memcpy(t, a, an * sizeof(DWORD));
5146 VARIANT_int_add(t, tn, b, bn);
5147 if (VARIANT_int_iszero(t + an, tn - an)) {
5148 /* addition was successful */
5149 memcpy(a, t, an * sizeof(DWORD));
5150 break;
5151 } else {
5152 /* addition overflowed - remove significant digits
5153 from both operands and try again */
5154 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5155 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5156 /* check whether any operand keeps significant digits after
5157 scaledown (underflow case 2)
5159 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5164 return underflow;
5167 /* perform complete DECIMAL division in the internal representation. Returns
5168 0 if the division was completed (even if quotient is set to 0), or nonzero
5169 in case of quotient overflow.
5171 static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * divisor,
5172 VARIANT_DI * quotient, BOOL round_remainder)
5174 HRESULT r_overflow = S_OK;
5176 if (VARIANT_int_iszero(divisor->bitsnum, ARRAY_SIZE(divisor->bitsnum))) {
5177 /* division by 0 */
5178 r_overflow = DISP_E_DIVBYZERO;
5179 } else if (VARIANT_int_iszero(dividend->bitsnum, ARRAY_SIZE(dividend->bitsnum))) {
5180 VARIANT_DI_clear(quotient);
5181 } else {
5182 int quotientscale, remainderscale, tempquotientscale;
5183 DWORD remainderplusquotient[8];
5184 int underflow;
5186 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5187 tempquotientscale = quotientscale;
5188 VARIANT_DI_clear(quotient);
5189 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5191 /* The following strategy is used for division
5192 1) if there was a nonzero remainder from previous iteration, use it as
5193 dividend for this iteration, else (for first iteration) use intended
5194 dividend
5195 2) perform integer division in temporary buffer, develop quotient in
5196 low-order part, remainder in high-order part
5197 3) add quotient from step 2 to final result, with possible loss of
5198 significant digits
5199 4) multiply integer part of remainder by 10, while incrementing the
5200 scale of the remainder. This operation preserves the intended value
5201 of the remainder.
5202 5) loop to step 1 until one of the following is true:
5203 a) remainder is zero (exact division achieved)
5204 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5206 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5207 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5208 do {
5209 VARIANT_int_div(remainderplusquotient, 4, divisor->bitsnum, ARRAY_SIZE(divisor->bitsnum));
5210 underflow = VARIANT_int_addlossy( quotient->bitsnum, &quotientscale,
5211 ARRAY_SIZE(quotient->bitsnum), remainderplusquotient, &tempquotientscale, 4);
5212 if (round_remainder) {
5213 if(remainderplusquotient[4] >= 5){
5214 unsigned int i;
5215 unsigned char remainder = 1;
5216 for (i = 0; i < ARRAY_SIZE(quotient->bitsnum) && remainder; i++) {
5217 ULONGLONG digit = quotient->bitsnum[i] + 1;
5218 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5219 quotient->bitsnum[i] = digit & 0xFFFFFFFF;
5222 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5223 } else {
5224 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5225 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5227 tempquotientscale = ++remainderscale;
5228 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5230 /* quotient scale might now be negative (extremely big number). If, so, try
5231 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5232 until scale is 0. If this cannot be done, it is a real overflow.
5234 while (r_overflow == S_OK && quotientscale < 0) {
5235 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5236 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5237 VARIANT_int_mulbychar(remainderplusquotient, ARRAY_SIZE(remainderplusquotient), 10);
5238 if (VARIANT_int_iszero(remainderplusquotient + ARRAY_SIZE(quotient->bitsnum),
5239 ARRAY_SIZE(remainderplusquotient) - ARRAY_SIZE(quotient->bitsnum))) {
5240 quotientscale++;
5241 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5242 } else r_overflow = DISP_E_OVERFLOW;
5244 if (r_overflow == S_OK) {
5245 if (quotientscale <= 255) quotient->scale = quotientscale;
5246 else VARIANT_DI_clear(quotient);
5249 return r_overflow;
5252 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5253 with an undefined scale, which will be assigned to (if possible). It also
5254 receives an exponent of 2. This procedure will then manipulate the mantissa
5255 and calculate a corresponding scale, so that the exponent2 value is assimilated
5256 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5257 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5258 a DECIMAL. */
5259 static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, BOOL isDouble)
5261 HRESULT hres = S_OK;
5262 int exponent5, exponent10;
5264 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5265 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5266 exponent10 might be used to set the VARIANT_DI scale directly. However,
5267 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5268 exponent5 = -exponent2;
5269 exponent10 = exponent2;
5271 /* Handle exponent5 > 0 */
5272 while (exponent5 > 0) {
5273 char bPrevCarryBit;
5274 char bCurrCarryBit;
5276 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5277 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5278 somehow the mantissa should be divided by 2. */
5279 if ((val->bitsnum[0] & 1) == 0) {
5280 /* The mantissa is divisible by 2. Therefore the division can be done
5281 without losing significant digits. */
5282 exponent10++; exponent5--;
5284 /* Shift right */
5285 bPrevCarryBit = val->bitsnum[2] & 1;
5286 val->bitsnum[2] >>= 1;
5287 bCurrCarryBit = val->bitsnum[1] & 1;
5288 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5289 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5290 } else {
5291 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5292 be multiplied by 5, unless the multiplication overflows. */
5293 DWORD temp_bitsnum[3];
5295 exponent5--;
5297 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5298 if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) {
5299 /* Multiplication succeeded without overflow, so copy result back
5300 into VARIANT_DI */
5301 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5303 /* Mask out 3 extraneous bits introduced by the multiply */
5304 } else {
5305 /* Multiplication by 5 overflows. The mantissa should be divided
5306 by 2, and therefore will lose significant digits. */
5307 exponent10++;
5309 /* Shift right */
5310 bPrevCarryBit = val->bitsnum[2] & 1;
5311 val->bitsnum[2] >>= 1;
5312 bCurrCarryBit = val->bitsnum[1] & 1;
5313 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5314 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5319 /* Handle exponent5 < 0 */
5320 while (exponent5 < 0) {
5321 /* In order to divide the value represented by the VARIANT_DI by 5, it
5322 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5323 and the mantissa should be multiplied by 2 */
5324 if ((val->bitsnum[2] & 0x80000000) == 0) {
5325 /* The mantissa can withstand a shift-left without overflowing */
5326 exponent10--; exponent5++;
5327 VARIANT_int_shiftleft(val->bitsnum, 3, 1);
5328 } else {
5329 /* The mantissa would overflow if shifted. Therefore it should be
5330 directly divided by 5. This will lose significant digits, unless
5331 by chance the mantissa happens to be divisible by 5 */
5332 exponent5++;
5333 VARIANT_int_divbychar(val->bitsnum, 3, 5);
5337 /* At this point, the mantissa has assimilated the exponent5, but the
5338 exponent10 might not be suitable for assignment. The exponent10 must be
5339 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5340 down appropriately. */
5341 while (hres == S_OK && exponent10 > 0) {
5342 /* In order to bring exponent10 down to 0, the mantissa should be
5343 multiplied by 10 to compensate. If the exponent10 is too big, this
5344 will cause the mantissa to overflow. */
5345 if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) {
5346 exponent10--;
5347 } else {
5348 hres = DISP_E_OVERFLOW;
5351 while (exponent10 < -DEC_MAX_SCALE) {
5352 int rem10;
5353 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5354 be divided by 10 to compensate. If the exponent10 is too small, this
5355 will cause the mantissa to underflow and become 0 */
5356 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5357 exponent10++;
5358 if (VARIANT_int_iszero(val->bitsnum, 3)) {
5359 /* Underflow, unable to keep dividing */
5360 exponent10 = 0;
5361 } else if (rem10 >= 5) {
5362 DWORD x = 1;
5363 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5366 /* This step is required in order to remove excess bits of precision from the
5367 end of the bit representation, down to the precision guaranteed by the
5368 floating point number. */
5369 if (isDouble) {
5370 while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[1] & 0xFFE00000) != 0)) {
5371 int rem10;
5373 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5374 exponent10++;
5375 if (rem10 >= 5) {
5376 DWORD x = 1;
5377 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5380 } else {
5381 while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 ||
5382 (val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) {
5383 int rem10;
5385 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5386 exponent10++;
5387 if (rem10 >= 5) {
5388 DWORD x = 1;
5389 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5393 /* Remove multiples of 10 from the representation */
5394 while (exponent10 < 0) {
5395 DWORD temp_bitsnum[3];
5397 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5398 if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) {
5399 exponent10++;
5400 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5401 } else break;
5404 /* Scale assignment */
5405 if (hres == S_OK) val->scale = -exponent10;
5407 return hres;
5410 typedef union
5412 struct
5414 unsigned int m : 23;
5415 unsigned int exp_bias : 8;
5416 unsigned int sign : 1;
5417 } i;
5418 float f;
5419 } R4_FIELDS;
5421 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5422 intermediate string step. */
5423 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest)
5425 HRESULT hres = S_OK;
5426 R4_FIELDS fx;
5428 fx.f = source;
5430 /* Detect special cases */
5431 if (fx.i.m == 0 && fx.i.exp_bias == 0) {
5432 /* Floating-point zero */
5433 VARIANT_DI_clear(dest);
5434 } else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) {
5435 /* Floating-point infinity */
5436 hres = DISP_E_OVERFLOW;
5437 } else if (fx.i.exp_bias == 0xFF) {
5438 /* Floating-point NaN */
5439 hres = DISP_E_BADVARTYPE;
5440 } else {
5441 int exponent2;
5442 VARIANT_DI_clear(dest);
5444 exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */
5445 dest->sign = fx.i.sign; /* Sign is simply copied */
5447 /* Copy significant bits to VARIANT_DI mantissa */
5448 dest->bitsnum[0] = fx.i.m;
5449 dest->bitsnum[0] &= 0x007FFFFF;
5450 if (fx.i.exp_bias == 0) {
5451 /* Denormalized number - correct exponent */
5452 exponent2++;
5453 } else {
5454 /* Add hidden bit to mantissa */
5455 dest->bitsnum[0] |= 0x00800000;
5458 /* The act of copying a FP mantissa as integer bits is equivalent to
5459 shifting left the mantissa 23 bits. The exponent2 is reduced to
5460 compensate. */
5461 exponent2 -= 23;
5463 hres = VARIANT_DI_normalize(dest, exponent2, FALSE);
5466 return hres;
5469 typedef union
5471 struct
5473 unsigned int m_lo : 32; /* 52 bits of precision */
5474 unsigned int m_hi : 20;
5475 unsigned int exp_bias : 11; /* bias == 1023 */
5476 unsigned int sign : 1;
5477 } i;
5478 double d;
5479 } R8_FIELDS;
5481 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5482 intermediate string step. */
5483 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest)
5485 HRESULT hres = S_OK;
5486 R8_FIELDS fx;
5488 fx.d = source;
5490 /* Detect special cases */
5491 if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) {
5492 /* Floating-point zero */
5493 VARIANT_DI_clear(dest);
5494 } else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) {
5495 /* Floating-point infinity */
5496 hres = DISP_E_OVERFLOW;
5497 } else if (fx.i.exp_bias == 0x7FF) {
5498 /* Floating-point NaN */
5499 hres = DISP_E_BADVARTYPE;
5500 } else {
5501 int exponent2;
5502 VARIANT_DI_clear(dest);
5504 exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */
5505 dest->sign = fx.i.sign; /* Sign is simply copied */
5507 /* Copy significant bits to VARIANT_DI mantissa */
5508 dest->bitsnum[0] = fx.i.m_lo;
5509 dest->bitsnum[1] = fx.i.m_hi;
5510 dest->bitsnum[1] &= 0x000FFFFF;
5511 if (fx.i.exp_bias == 0) {
5512 /* Denormalized number - correct exponent */
5513 exponent2++;
5514 } else {
5515 /* Add hidden bit to mantissa */
5516 dest->bitsnum[1] |= 0x00100000;
5519 /* The act of copying a FP mantissa as integer bits is equivalent to
5520 shifting left the mantissa 52 bits. The exponent2 is reduced to
5521 compensate. */
5522 exponent2 -= 52;
5524 hres = VARIANT_DI_normalize(dest, exponent2, TRUE);
5527 return hres;
5530 static HRESULT VARIANT_do_division(const DECIMAL *pDecLeft, const DECIMAL *pDecRight, DECIMAL *pDecOut,
5531 BOOL round)
5533 HRESULT hRet = S_OK;
5534 VARIANT_DI di_left, di_right, di_result;
5535 HRESULT divresult;
5537 VARIANT_DIFromDec(pDecLeft, &di_left);
5538 VARIANT_DIFromDec(pDecRight, &di_right);
5539 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result, round);
5540 if (divresult != S_OK)
5542 /* division actually overflowed */
5543 hRet = divresult;
5545 else
5547 hRet = S_OK;
5549 if (di_result.scale > DEC_MAX_SCALE)
5551 unsigned char remainder = 0;
5553 /* division underflowed. In order to comply with the MSDN
5554 specifications for DECIMAL ranges, some significant digits
5555 must be removed
5557 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5558 di_result.scale);
5559 while (di_result.scale > DEC_MAX_SCALE &&
5560 !VARIANT_int_iszero(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum)))
5562 remainder = VARIANT_int_divbychar(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum), 10);
5563 di_result.scale--;
5565 if (di_result.scale > DEC_MAX_SCALE)
5567 WARN("result underflowed, setting to 0\n");
5568 di_result.scale = 0;
5569 di_result.sign = 0;
5571 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5573 unsigned int i;
5574 for (remainder = 1, i = 0; i < ARRAY_SIZE(di_result.bitsnum) && remainder; i++) {
5575 ULONGLONG digit = di_result.bitsnum[i] + 1;
5576 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5577 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5581 VARIANT_DecFromDI(&di_result, pDecOut);
5583 return hRet;
5586 /************************************************************************
5587 * VarDecDiv (OLEAUT32.178)
5589 * Divide one DECIMAL by another.
5591 * PARAMS
5592 * pDecLeft [I] Source
5593 * pDecRight [I] Value to divide by
5594 * pDecOut [O] Destination
5596 * RETURNS
5597 * Success: S_OK.
5598 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5600 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5602 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5604 return VARIANT_do_division(pDecLeft, pDecRight, pDecOut, FALSE);
5607 /************************************************************************
5608 * VarDecMul (OLEAUT32.179)
5610 * Multiply one DECIMAL by another.
5612 * PARAMS
5613 * pDecLeft [I] Source
5614 * pDecRight [I] Value to multiply by
5615 * pDecOut [O] Destination
5617 * RETURNS
5618 * Success: S_OK.
5619 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5621 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5623 HRESULT hRet = S_OK;
5624 VARIANT_DI di_left, di_right, di_result;
5625 int mulresult;
5627 VARIANT_DIFromDec(pDecLeft, &di_left);
5628 VARIANT_DIFromDec(pDecRight, &di_right);
5629 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5630 if (mulresult)
5632 /* multiplication actually overflowed */
5633 hRet = DISP_E_OVERFLOW;
5635 else
5637 if (di_result.scale > DEC_MAX_SCALE)
5639 /* multiplication underflowed. In order to comply with the MSDN
5640 specifications for DECIMAL ranges, some significant digits
5641 must be removed
5643 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5644 di_result.scale);
5645 while (di_result.scale > DEC_MAX_SCALE &&
5646 !VARIANT_int_iszero(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum)))
5648 VARIANT_int_divbychar(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum), 10);
5649 di_result.scale--;
5651 if (di_result.scale > DEC_MAX_SCALE)
5653 WARN("result underflowed, setting to 0\n");
5654 di_result.scale = 0;
5655 di_result.sign = 0;
5658 VARIANT_DecFromDI(&di_result, pDecOut);
5660 return hRet;
5663 /************************************************************************
5664 * VarDecSub (OLEAUT32.181)
5666 * Subtract one DECIMAL from another.
5668 * PARAMS
5669 * pDecLeft [I] Source
5670 * pDecRight [I] DECIMAL to subtract from pDecLeft
5671 * pDecOut [O] Destination
5673 * RETURNS
5674 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5676 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5678 DECIMAL decRight;
5680 /* Implement as addition of the negative */
5681 VarDecNeg(pDecRight, &decRight);
5682 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5685 /************************************************************************
5686 * VarDecAbs (OLEAUT32.182)
5688 * Convert a DECIMAL into its absolute value.
5690 * PARAMS
5691 * pDecIn [I] Source
5692 * pDecOut [O] Destination
5694 * RETURNS
5695 * S_OK. This function does not fail.
5697 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5699 *pDecOut = *pDecIn;
5700 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5701 return S_OK;
5704 /************************************************************************
5705 * VarDecFix (OLEAUT32.187)
5707 * Return the integer portion of a DECIMAL.
5709 * PARAMS
5710 * pDecIn [I] Source
5711 * pDecOut [O] Destination
5713 * RETURNS
5714 * Success: S_OK.
5715 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5717 * NOTES
5718 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5719 * negative numbers away from 0, while this function rounds them towards zero.
5721 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5723 double dbl;
5724 HRESULT hr;
5726 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5727 return E_INVALIDARG;
5729 if (!DEC_SCALE(pDecIn))
5731 *pDecOut = *pDecIn; /* Already an integer */
5732 return S_OK;
5735 hr = VarR8FromDec(pDecIn, &dbl);
5736 if (SUCCEEDED(hr)) {
5737 LONGLONG rounded = dbl;
5739 hr = VarDecFromI8(rounded, pDecOut);
5741 return hr;
5744 /************************************************************************
5745 * VarDecInt (OLEAUT32.188)
5747 * Return the integer portion of a DECIMAL.
5749 * PARAMS
5750 * pDecIn [I] Source
5751 * pDecOut [O] Destination
5753 * RETURNS
5754 * Success: S_OK.
5755 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5757 * NOTES
5758 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5759 * negative numbers towards 0, while this function rounds them away from zero.
5761 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5763 double dbl;
5764 HRESULT hr;
5766 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5767 return E_INVALIDARG;
5769 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5770 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5772 hr = VarR8FromDec(pDecIn, &dbl);
5773 if (SUCCEEDED(hr)) {
5774 LONGLONG rounded = dbl >= 0.0 ? dbl + 0.5 : dbl - 0.5;
5776 hr = VarDecFromI8(rounded, pDecOut);
5778 return hr;
5781 /************************************************************************
5782 * VarDecNeg (OLEAUT32.189)
5784 * Change the sign of a DECIMAL.
5786 * PARAMS
5787 * pDecIn [I] Source
5788 * pDecOut [O] Destination
5790 * RETURNS
5791 * S_OK. This function does not fail.
5793 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5795 *pDecOut = *pDecIn;
5796 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5797 return S_OK;
5800 /************************************************************************
5801 * VarDecRound (OLEAUT32.203)
5803 * Change the precision of a DECIMAL.
5805 * PARAMS
5806 * pDecIn [I] Source
5807 * cDecimals [I] New number of decimals to keep
5808 * pDecOut [O] Destination
5810 * RETURNS
5811 * Success: S_OK. pDecOut contains the rounded value.
5812 * Failure: E_INVALIDARG if any argument is invalid.
5814 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5816 DECIMAL divisor, tmp;
5817 HRESULT hr;
5818 unsigned int i;
5820 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5821 return E_INVALIDARG;
5823 if (cDecimals >= DEC_SCALE(pDecIn))
5825 *pDecOut = *pDecIn; /* More precision than we have */
5826 return S_OK;
5829 /* truncate significant digits and rescale */
5830 memset(&divisor, 0, sizeof(divisor));
5831 DEC_LO64(&divisor) = 1;
5833 memset(&tmp, 0, sizeof(tmp));
5834 DEC_LO64(&tmp) = 10;
5835 for (i = 0; i < DEC_SCALE(pDecIn) - cDecimals; ++i)
5837 hr = VarDecMul(&divisor, &tmp, &divisor);
5838 if (FAILED(hr))
5839 return hr;
5842 hr = VARIANT_do_division(pDecIn, &divisor, pDecOut, TRUE);
5843 if (FAILED(hr))
5844 return hr;
5846 DEC_SCALE(pDecOut) = cDecimals;
5848 return S_OK;
5851 /************************************************************************
5852 * VarDecCmp (OLEAUT32.204)
5854 * Compare two DECIMAL values.
5856 * PARAMS
5857 * pDecLeft [I] Source
5858 * pDecRight [I] Value to compare
5860 * RETURNS
5861 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5862 * is less than, equal to or greater than pDecRight respectively.
5863 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5865 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5867 HRESULT hRet;
5868 DECIMAL result;
5870 if (!pDecLeft || !pDecRight)
5871 return VARCMP_NULL;
5873 if ((!(DEC_SIGN(pDecLeft) & DECIMAL_NEG)) && (DEC_SIGN(pDecRight) & DECIMAL_NEG) &&
5874 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5875 return VARCMP_GT;
5876 else if ((DEC_SIGN(pDecLeft) & DECIMAL_NEG) && (!(DEC_SIGN(pDecRight) & DECIMAL_NEG)) &&
5877 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5878 return VARCMP_LT;
5880 /* Subtract right from left, and compare the result to 0 */
5881 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5883 if (SUCCEEDED(hRet))
5885 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5887 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5888 hRet = (HRESULT)VARCMP_LT;
5889 else if (non_zero)
5890 hRet = (HRESULT)VARCMP_GT;
5891 else
5892 hRet = (HRESULT)VARCMP_EQ;
5894 return hRet;
5897 /************************************************************************
5898 * VarDecCmpR8 (OLEAUT32.298)
5900 * Compare a DECIMAL to a double
5902 * PARAMS
5903 * pDecLeft [I] DECIMAL Source
5904 * dblRight [I] double to compare to pDecLeft
5906 * RETURNS
5907 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5908 * is less than, equal to or greater than pDecLeft respectively.
5909 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5911 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5913 HRESULT hRet;
5914 DECIMAL decRight;
5916 hRet = VarDecFromR8(dblRight, &decRight);
5918 if (SUCCEEDED(hRet))
5919 hRet = VarDecCmp(pDecLeft, &decRight);
5921 return hRet;
5924 /* BOOL
5927 /************************************************************************
5928 * VarBoolFromUI1 (OLEAUT32.118)
5930 * Convert a VT_UI1 to a VT_BOOL.
5932 * PARAMS
5933 * bIn [I] Source
5934 * pBoolOut [O] Destination
5936 * RETURNS
5937 * S_OK.
5939 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5941 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5942 return S_OK;
5945 /************************************************************************
5946 * VarBoolFromI2 (OLEAUT32.119)
5948 * Convert a VT_I2 to a VT_BOOL.
5950 * PARAMS
5951 * sIn [I] Source
5952 * pBoolOut [O] Destination
5954 * RETURNS
5955 * S_OK.
5957 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5959 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5960 return S_OK;
5963 /************************************************************************
5964 * VarBoolFromI4 (OLEAUT32.120)
5966 * Convert a VT_I4 to a VT_BOOL.
5968 * PARAMS
5969 * sIn [I] Source
5970 * pBoolOut [O] Destination
5972 * RETURNS
5973 * S_OK.
5975 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
5977 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
5978 return S_OK;
5981 /************************************************************************
5982 * VarBoolFromR4 (OLEAUT32.121)
5984 * Convert a VT_R4 to a VT_BOOL.
5986 * PARAMS
5987 * fltIn [I] Source
5988 * pBoolOut [O] Destination
5990 * RETURNS
5991 * S_OK.
5993 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
5995 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
5996 return S_OK;
5999 /************************************************************************
6000 * VarBoolFromR8 (OLEAUT32.122)
6002 * Convert a VT_R8 to a VT_BOOL.
6004 * PARAMS
6005 * dblIn [I] Source
6006 * pBoolOut [O] Destination
6008 * RETURNS
6009 * S_OK.
6011 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
6013 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
6014 return S_OK;
6017 /************************************************************************
6018 * VarBoolFromDate (OLEAUT32.123)
6020 * Convert a VT_DATE to a VT_BOOL.
6022 * PARAMS
6023 * dateIn [I] Source
6024 * pBoolOut [O] Destination
6026 * RETURNS
6027 * S_OK.
6029 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
6031 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
6032 return S_OK;
6035 /************************************************************************
6036 * VarBoolFromCy (OLEAUT32.124)
6038 * Convert a VT_CY to a VT_BOOL.
6040 * PARAMS
6041 * cyIn [I] Source
6042 * pBoolOut [O] Destination
6044 * RETURNS
6045 * S_OK.
6047 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
6049 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
6050 return S_OK;
6053 /************************************************************************
6054 * VARIANT_GetLocalisedText [internal]
6056 * Get a localized string from the resources
6059 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
6061 HRSRC hrsrc;
6063 hrsrc = FindResourceExW( hProxyDll, (LPWSTR)RT_STRING,
6064 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
6065 if (hrsrc)
6067 HGLOBAL hmem = LoadResource( hProxyDll, hrsrc );
6069 if (hmem)
6071 const WCHAR *p;
6072 unsigned int i;
6074 p = LockResource( hmem );
6075 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
6077 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
6078 lpszDest[*p] = '\0';
6079 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
6080 return TRUE;
6083 return FALSE;
6086 /************************************************************************
6087 * VarBoolFromStr (OLEAUT32.125)
6089 * Convert a VT_BSTR to a VT_BOOL.
6091 * PARAMS
6092 * strIn [I] Source
6093 * lcid [I] LCID for the conversion
6094 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6095 * pBoolOut [O] Destination
6097 * RETURNS
6098 * Success: S_OK.
6099 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6100 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6102 * NOTES
6103 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6104 * it may contain (in any case mapping) the text "true" or "false".
6105 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6106 * localised text of "True" or "False" in the language specified by lcid.
6107 * - If none of these matches occur, the string is treated as a numeric string
6108 * and the boolean pBoolOut will be set according to whether the number is zero
6109 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6110 * - If the text is not numeric and does not match any of the above, then
6111 * DISP_E_TYPEMISMATCH is returned.
6113 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
6115 /* Any VB/VBA programmers out there should recognise these strings... */
6116 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
6117 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
6118 WCHAR szBuff[64];
6119 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6120 HRESULT hRes = S_OK;
6122 if (!strIn || !pBoolOut)
6123 return DISP_E_TYPEMISMATCH;
6125 /* Check if we should be comparing against localised text */
6126 if (dwFlags & VAR_LOCALBOOL)
6128 /* Convert our LCID into a usable value */
6129 lcid = ConvertDefaultLocale(lcid);
6131 langId = LANGIDFROMLCID(lcid);
6133 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6134 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6136 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6137 * I don't think this is needed unless any of the localised text strings
6138 * contain characters that can be so mapped. In the event that this is
6139 * true for a given language (possibly some Asian languages), then strIn
6140 * should be mapped here _only_ if langId is an Id for which this can occur.
6144 /* Note that if we are not comparing against localised strings, langId
6145 * will have its default value of LANG_ENGLISH. This allows us to mimic
6146 * the native behaviour of always checking against English strings even
6147 * after we've checked for localised ones.
6149 VarBoolFromStr_CheckLocalised:
6150 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
6152 /* Compare against localised strings, ignoring case */
6153 if (!strcmpiW(strIn, szBuff))
6155 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
6156 return hRes;
6158 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
6159 if (!strcmpiW(strIn, szBuff))
6161 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
6162 return hRes;
6166 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6168 /* We have checked the localised text, now check English */
6169 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6170 goto VarBoolFromStr_CheckLocalised;
6173 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6174 if (!strcmpW(strIn, szFalse))
6175 *pBoolOut = VARIANT_FALSE;
6176 else if (!strcmpW(strIn, szTrue))
6177 *pBoolOut = VARIANT_TRUE;
6178 else
6180 double d;
6182 /* If this string is a number, convert it as one */
6183 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
6184 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
6186 return hRes;
6189 /************************************************************************
6190 * VarBoolFromDisp (OLEAUT32.126)
6192 * Convert a VT_DISPATCH to a VT_BOOL.
6194 * PARAMS
6195 * pdispIn [I] Source
6196 * lcid [I] LCID for conversion
6197 * pBoolOut [O] Destination
6199 * RETURNS
6200 * Success: S_OK.
6201 * Failure: E_INVALIDARG, if the source value is invalid
6202 * DISP_E_OVERFLOW, if the value will not fit in the destination
6203 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6205 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
6207 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
6210 /************************************************************************
6211 * VarBoolFromI1 (OLEAUT32.233)
6213 * Convert a VT_I1 to a VT_BOOL.
6215 * PARAMS
6216 * cIn [I] Source
6217 * pBoolOut [O] Destination
6219 * RETURNS
6220 * S_OK.
6222 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
6224 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
6225 return S_OK;
6228 /************************************************************************
6229 * VarBoolFromUI2 (OLEAUT32.234)
6231 * Convert a VT_UI2 to a VT_BOOL.
6233 * PARAMS
6234 * usIn [I] Source
6235 * pBoolOut [O] Destination
6237 * RETURNS
6238 * S_OK.
6240 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
6242 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
6243 return S_OK;
6246 /************************************************************************
6247 * VarBoolFromUI4 (OLEAUT32.235)
6249 * Convert a VT_UI4 to a VT_BOOL.
6251 * PARAMS
6252 * ulIn [I] Source
6253 * pBoolOut [O] Destination
6255 * RETURNS
6256 * S_OK.
6258 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
6260 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
6261 return S_OK;
6264 /************************************************************************
6265 * VarBoolFromDec (OLEAUT32.236)
6267 * Convert a VT_DECIMAL to a VT_BOOL.
6269 * PARAMS
6270 * pDecIn [I] Source
6271 * pBoolOut [O] Destination
6273 * RETURNS
6274 * Success: S_OK.
6275 * Failure: E_INVALIDARG, if pDecIn is invalid.
6277 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
6279 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
6280 return E_INVALIDARG;
6282 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
6283 *pBoolOut = VARIANT_TRUE;
6284 else
6285 *pBoolOut = VARIANT_FALSE;
6286 return S_OK;
6289 /************************************************************************
6290 * VarBoolFromI8 (OLEAUT32.370)
6292 * Convert a VT_I8 to a VT_BOOL.
6294 * PARAMS
6295 * ullIn [I] Source
6296 * pBoolOut [O] Destination
6298 * RETURNS
6299 * S_OK.
6301 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
6303 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
6304 return S_OK;
6307 /************************************************************************
6308 * VarBoolFromUI8 (OLEAUT32.371)
6310 * Convert a VT_UI8 to a VT_BOOL.
6312 * PARAMS
6313 * ullIn [I] Source
6314 * pBoolOut [O] Destination
6316 * RETURNS
6317 * S_OK.
6319 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
6321 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
6322 return S_OK;
6325 /* BSTR
6328 /* Write a number from a UI8 and sign */
6329 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
6333 WCHAR ulNextDigit = ulVal % 10;
6335 *szOut-- = '0' + ulNextDigit;
6336 ulVal = (ulVal - ulNextDigit) / 10;
6337 } while (ulVal);
6339 szOut++;
6340 return szOut;
6343 /* Create a (possibly localised) BSTR from a UI8 and sign */
6344 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
6346 WCHAR szConverted[256];
6348 if (dwFlags & VAR_NEGATIVE)
6349 *--szOut = '-';
6351 if (dwFlags & LOCALE_USE_NLS)
6353 /* Format the number for the locale */
6354 szConverted[0] = '\0';
6355 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6356 szOut, NULL, szConverted, ARRAY_SIZE(szConverted));
6357 szOut = szConverted;
6359 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
6362 /* Create a (possibly localised) BSTR from a UI8 and sign */
6363 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
6365 WCHAR szBuff[64], *szOut = szBuff + ARRAY_SIZE(szBuff) - 1;
6367 if (!pbstrOut)
6368 return E_INVALIDARG;
6370 /* Create the basic number string */
6371 *szOut-- = '\0';
6372 szOut = VARIANT_WriteNumber(ulVal, szOut);
6374 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
6375 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6376 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6379 /******************************************************************************
6380 * VarBstrFromUI1 (OLEAUT32.108)
6382 * Convert a VT_UI1 to a VT_BSTR.
6384 * PARAMS
6385 * bIn [I] Source
6386 * lcid [I] LCID for the conversion
6387 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6388 * pbstrOut [O] Destination
6390 * RETURNS
6391 * Success: S_OK.
6392 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6393 * E_OUTOFMEMORY, if memory allocation fails.
6395 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6397 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6400 /******************************************************************************
6401 * VarBstrFromI2 (OLEAUT32.109)
6403 * Convert a VT_I2 to a VT_BSTR.
6405 * PARAMS
6406 * sIn [I] Source
6407 * lcid [I] LCID for the conversion
6408 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6409 * pbstrOut [O] Destination
6411 * RETURNS
6412 * Success: S_OK.
6413 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6414 * E_OUTOFMEMORY, if memory allocation fails.
6416 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6418 ULONG64 ul64 = sIn;
6420 if (sIn < 0)
6422 ul64 = -sIn;
6423 dwFlags |= VAR_NEGATIVE;
6425 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6428 /******************************************************************************
6429 * VarBstrFromI4 (OLEAUT32.110)
6431 * Convert a VT_I4 to a VT_BSTR.
6433 * PARAMS
6434 * lIn [I] Source
6435 * lcid [I] LCID for the conversion
6436 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6437 * pbstrOut [O] Destination
6439 * RETURNS
6440 * Success: S_OK.
6441 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6442 * E_OUTOFMEMORY, if memory allocation fails.
6444 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6446 ULONG64 ul64 = lIn;
6448 if (lIn < 0)
6450 ul64 = -(LONG64)lIn;
6451 dwFlags |= VAR_NEGATIVE;
6453 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6456 static BSTR VARIANT_BstrReplaceDecimal(const WCHAR * buff, LCID lcid, ULONG dwFlags)
6458 BSTR bstrOut;
6459 WCHAR lpDecimalSep[16];
6461 /* Native oleaut32 uses the locale-specific decimal separator even in the
6462 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6463 American locales will see "one thousand and one tenth" as "1000,1"
6464 instead of "1000.1" (notice the comma). The following code checks for
6465 the need to replace the decimal separator, and if so, will prepare an
6466 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6468 GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE),
6469 lpDecimalSep, ARRAY_SIZE(lpDecimalSep));
6470 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6472 /* locale is compatible with English - return original string */
6473 bstrOut = SysAllocString(buff);
6475 else
6477 WCHAR *p;
6478 WCHAR numbuff[256];
6479 WCHAR empty[] = {'\0'};
6480 NUMBERFMTW minFormat;
6482 minFormat.NumDigits = 0;
6483 minFormat.LeadingZero = 0;
6484 minFormat.Grouping = 0;
6485 minFormat.lpDecimalSep = lpDecimalSep;
6486 minFormat.lpThousandSep = empty;
6487 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6489 /* count number of decimal digits in string */
6490 p = strchrW( buff, '.' );
6491 if (p) minFormat.NumDigits = strlenW(p + 1);
6493 numbuff[0] = '\0';
6494 if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, ARRAY_SIZE(numbuff)))
6496 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6497 bstrOut = SysAllocString(buff);
6499 else
6501 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6502 bstrOut = SysAllocString(numbuff);
6505 return bstrOut;
6508 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6509 BSTR* pbstrOut, LPCWSTR lpszFormat)
6511 WCHAR buff[256];
6513 if (!pbstrOut)
6514 return E_INVALIDARG;
6516 sprintfW( buff, lpszFormat, dblIn );
6518 /* Negative zeroes are disallowed (some applications depend on this).
6519 If buff starts with a minus, and then nothing follows but zeroes
6520 and/or a period, it is a negative zero and is replaced with a
6521 canonical zero. This duplicates native oleaut32 behavior.
6523 if (buff[0] == '-')
6525 const WCHAR szAccept[] = {'0', '.', '\0'};
6526 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
6527 { buff[0] = '0'; buff[1] = '\0'; }
6530 TRACE("created string %s\n", debugstr_w(buff));
6531 if (dwFlags & LOCALE_USE_NLS)
6533 WCHAR numbuff[256];
6535 /* Format the number for the locale */
6536 numbuff[0] = '\0';
6537 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6538 buff, NULL, numbuff, ARRAY_SIZE(numbuff));
6539 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6540 *pbstrOut = SysAllocString(numbuff);
6542 else
6544 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6546 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6549 /******************************************************************************
6550 * VarBstrFromR4 (OLEAUT32.111)
6552 * Convert a VT_R4 to a VT_BSTR.
6554 * PARAMS
6555 * fltIn [I] Source
6556 * lcid [I] LCID for the conversion
6557 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6558 * pbstrOut [O] Destination
6560 * RETURNS
6561 * Success: S_OK.
6562 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6563 * E_OUTOFMEMORY, if memory allocation fails.
6565 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6567 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
6570 /******************************************************************************
6571 * VarBstrFromR8 (OLEAUT32.112)
6573 * Convert a VT_R8 to a VT_BSTR.
6575 * PARAMS
6576 * dblIn [I] Source
6577 * lcid [I] LCID for the conversion
6578 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6579 * pbstrOut [O] Destination
6581 * RETURNS
6582 * Success: S_OK.
6583 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6584 * E_OUTOFMEMORY, if memory allocation fails.
6586 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6588 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
6591 /******************************************************************************
6592 * VarBstrFromCy [OLEAUT32.113]
6594 * Convert a VT_CY to a VT_BSTR.
6596 * PARAMS
6597 * cyIn [I] Source
6598 * lcid [I] LCID for the conversion
6599 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6600 * pbstrOut [O] Destination
6602 * RETURNS
6603 * Success: S_OK.
6604 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6605 * E_OUTOFMEMORY, if memory allocation fails.
6607 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6609 WCHAR buff[256];
6610 VARIANT_DI decVal;
6612 if (!pbstrOut)
6613 return E_INVALIDARG;
6615 decVal.scale = 4;
6616 decVal.sign = 0;
6617 decVal.bitsnum[0] = cyIn.s.Lo;
6618 decVal.bitsnum[1] = cyIn.s.Hi;
6619 if (cyIn.s.Hi & 0x80000000UL) {
6620 DWORD one = 1;
6622 /* Negative number! */
6623 decVal.sign = 1;
6624 decVal.bitsnum[0] = ~decVal.bitsnum[0];
6625 decVal.bitsnum[1] = ~decVal.bitsnum[1];
6626 VARIANT_int_add(decVal.bitsnum, 3, &one, 1);
6628 decVal.bitsnum[2] = 0;
6629 VARIANT_DI_tostringW(&decVal, buff, ARRAY_SIZE(buff));
6631 if (dwFlags & LOCALE_USE_NLS)
6633 WCHAR cybuff[256];
6635 /* Format the currency for the locale */
6636 cybuff[0] = '\0';
6637 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6638 buff, NULL, cybuff, ARRAY_SIZE(cybuff));
6639 *pbstrOut = SysAllocString(cybuff);
6641 else
6642 *pbstrOut = VARIANT_BstrReplaceDecimal(buff,lcid,dwFlags);
6644 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6647 static inline int output_int_len(int o, int min_len, WCHAR *date, int date_len)
6649 int len, tmp;
6651 if(min_len >= date_len)
6652 return -1;
6654 for(len=0, tmp=o; tmp; tmp/=10) len++;
6655 if(!len) len++;
6656 if(len >= date_len)
6657 return -1;
6659 for(tmp=min_len-len; tmp>0; tmp--)
6660 *date++ = '0';
6661 for(tmp=len; tmp>0; tmp--, o/=10)
6662 date[tmp-1] = '0' + o%10;
6663 return min_len>len ? min_len : len;
6666 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6667 BOOL get_date_format(LCID lcid, DWORD flags, const SYSTEMTIME *st,
6668 const WCHAR *fmt, WCHAR *date, int date_len)
6670 static const LCTYPE dayname[] = {
6671 LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
6672 LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6
6674 static const LCTYPE sdayname[] = {
6675 LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
6676 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
6677 LOCALE_SABBREVDAYNAME6
6679 static const LCTYPE monthname[] = {
6680 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
6681 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
6682 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12
6684 static const LCTYPE smonthname[] = {
6685 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
6686 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
6687 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
6688 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12
6691 if(flags & ~(LOCALE_NOUSEROVERRIDE|VAR_DATEVALUEONLY))
6692 FIXME("ignoring flags %x\n", flags);
6693 flags &= LOCALE_NOUSEROVERRIDE;
6695 while(*fmt && date_len) {
6696 int count = 1;
6698 switch(*fmt) {
6699 case 'd':
6700 case 'M':
6701 case 'y':
6702 case 'g':
6703 while(*fmt == *(fmt+count))
6704 count++;
6705 fmt += count-1;
6708 switch(*fmt) {
6709 case 'd':
6710 if(count >= 4)
6711 count = GetLocaleInfoW(lcid, dayname[st->wDayOfWeek] | flags, date, date_len)-1;
6712 else if(count == 3)
6713 count = GetLocaleInfoW(lcid, sdayname[st->wDayOfWeek] | flags, date, date_len)-1;
6714 else
6715 count = output_int_len(st->wDay, count, date, date_len);
6716 break;
6717 case 'M':
6718 if(count >= 4)
6719 count = GetLocaleInfoW(lcid, monthname[st->wMonth-1] | flags, date, date_len)-1;
6720 else if(count == 3)
6721 count = GetLocaleInfoW(lcid, smonthname[st->wMonth-1] | flags, date, date_len)-1;
6722 else
6723 count = output_int_len(st->wMonth, count, date, date_len);
6724 break;
6725 case 'y':
6726 if(count >= 3)
6727 count = output_int_len(st->wYear, 0, date, date_len);
6728 else
6729 count = output_int_len(st->wYear%100, count, date, date_len);
6730 break;
6731 case 'g':
6732 if(count == 2) {
6733 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6735 *date++ = 'A';
6736 date_len--;
6737 if(date_len)
6738 *date = 'D';
6739 else
6740 count = -1;
6741 break;
6743 /* fall through */
6744 default:
6745 *date = *fmt;
6748 if(count < 0)
6749 break;
6750 fmt++;
6751 date += count;
6752 date_len -= count;
6755 if(!date_len)
6756 return FALSE;
6757 *date++ = 0;
6758 return TRUE;
6761 /******************************************************************************
6762 * VarBstrFromDate [OLEAUT32.114]
6764 * Convert a VT_DATE to a VT_BSTR.
6766 * PARAMS
6767 * dateIn [I] Source
6768 * lcid [I] LCID for the conversion
6769 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6770 * pbstrOut [O] Destination
6772 * RETURNS
6773 * Success: S_OK.
6774 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6775 * E_OUTOFMEMORY, if memory allocation fails.
6777 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6779 SYSTEMTIME st;
6780 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6781 WCHAR date[128], fmt_buff[80], *time;
6783 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
6785 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6786 return E_INVALIDARG;
6788 *pbstrOut = NULL;
6790 if (dwFlags & VAR_CALENDAR_THAI)
6791 st.wYear += 553; /* Use the Thai buddhist calendar year */
6792 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6793 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6795 if (dwFlags & LOCALE_USE_NLS)
6796 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6797 else
6799 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6800 double partial = dateIn - whole;
6802 if (whole == 0.0)
6803 dwFlags |= VAR_TIMEVALUEONLY;
6804 else if (partial > -1e-12 && partial < 1e-12)
6805 dwFlags |= VAR_DATEVALUEONLY;
6808 if (dwFlags & VAR_TIMEVALUEONLY)
6809 date[0] = '\0';
6810 else
6811 if (!GetLocaleInfoW(lcid, LOCALE_SSHORTDATE, fmt_buff, ARRAY_SIZE(fmt_buff)) ||
6812 !get_date_format(lcid, dwFlags, &st, fmt_buff, date, ARRAY_SIZE(date)))
6813 return E_INVALIDARG;
6815 if (!(dwFlags & VAR_DATEVALUEONLY))
6817 time = date + strlenW(date);
6818 if (time != date)
6819 *time++ = ' ';
6820 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time, ARRAY_SIZE(date)-(time-date)))
6821 return E_INVALIDARG;
6824 *pbstrOut = SysAllocString(date);
6825 if (*pbstrOut)
6826 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6827 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6830 /******************************************************************************
6831 * VarBstrFromBool (OLEAUT32.116)
6833 * Convert a VT_BOOL to a VT_BSTR.
6835 * PARAMS
6836 * boolIn [I] Source
6837 * lcid [I] LCID for the conversion
6838 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6839 * pbstrOut [O] Destination
6841 * RETURNS
6842 * Success: S_OK.
6843 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6844 * E_OUTOFMEMORY, if memory allocation fails.
6846 * NOTES
6847 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6848 * localised text of "True" or "False". To convert a bool into a
6849 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6851 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6853 WCHAR szBuff[64];
6854 DWORD dwResId = IDS_TRUE;
6855 LANGID langId;
6857 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn, lcid, dwFlags, pbstrOut);
6859 if (!pbstrOut)
6860 return E_INVALIDARG;
6862 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6863 * for variant formatting */
6864 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6866 case VAR_BOOLONOFF:
6867 dwResId = IDS_ON;
6868 break;
6869 case VAR_BOOLYESNO:
6870 dwResId = IDS_YES;
6871 break;
6872 case VAR_LOCALBOOL:
6873 break;
6874 default:
6875 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6878 lcid = ConvertDefaultLocale(lcid);
6879 langId = LANGIDFROMLCID(lcid);
6880 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6881 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6883 if (boolIn == VARIANT_FALSE)
6884 dwResId++; /* Use negative form */
6886 VarBstrFromBool_GetLocalised:
6887 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6889 *pbstrOut = SysAllocString(szBuff);
6890 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6893 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6895 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6896 goto VarBstrFromBool_GetLocalised;
6899 /* Should never get here */
6900 WARN("Failed to load bool text!\n");
6901 return E_OUTOFMEMORY;
6904 /******************************************************************************
6905 * VarBstrFromI1 (OLEAUT32.229)
6907 * Convert a VT_I1 to a VT_BSTR.
6909 * PARAMS
6910 * cIn [I] Source
6911 * lcid [I] LCID for the conversion
6912 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6913 * pbstrOut [O] Destination
6915 * RETURNS
6916 * Success: S_OK.
6917 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6918 * E_OUTOFMEMORY, if memory allocation fails.
6920 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6922 ULONG64 ul64 = cIn;
6924 if (cIn < 0)
6926 ul64 = -cIn;
6927 dwFlags |= VAR_NEGATIVE;
6929 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6932 /******************************************************************************
6933 * VarBstrFromUI2 (OLEAUT32.230)
6935 * Convert a VT_UI2 to a VT_BSTR.
6937 * PARAMS
6938 * usIn [I] Source
6939 * lcid [I] LCID for the conversion
6940 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6941 * pbstrOut [O] Destination
6943 * RETURNS
6944 * Success: S_OK.
6945 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6946 * E_OUTOFMEMORY, if memory allocation fails.
6948 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6950 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6953 /******************************************************************************
6954 * VarBstrFromUI4 (OLEAUT32.231)
6956 * Convert a VT_UI4 to a VT_BSTR.
6958 * PARAMS
6959 * ulIn [I] Source
6960 * lcid [I] LCID for the conversion
6961 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6962 * pbstrOut [O] Destination
6964 * RETURNS
6965 * Success: S_OK.
6966 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6967 * E_OUTOFMEMORY, if memory allocation fails.
6969 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6971 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
6974 /******************************************************************************
6975 * VarBstrFromDec (OLEAUT32.232)
6977 * Convert a VT_DECIMAL to a VT_BSTR.
6979 * PARAMS
6980 * pDecIn [I] Source
6981 * lcid [I] LCID for the conversion
6982 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6983 * pbstrOut [O] Destination
6985 * RETURNS
6986 * Success: S_OK.
6987 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6988 * E_OUTOFMEMORY, if memory allocation fails.
6990 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6992 WCHAR buff[256];
6993 VARIANT_DI temp;
6995 if (!pbstrOut)
6996 return E_INVALIDARG;
6998 VARIANT_DIFromDec(pDecIn, &temp);
6999 VARIANT_DI_tostringW(&temp, buff, 256);
7001 if (dwFlags & LOCALE_USE_NLS)
7003 WCHAR numbuff[256];
7005 /* Format the number for the locale */
7006 numbuff[0] = '\0';
7007 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
7008 buff, NULL, numbuff, ARRAY_SIZE(numbuff));
7009 TRACE("created NLS string %s\n", debugstr_w(numbuff));
7010 *pbstrOut = SysAllocString(numbuff);
7012 else
7014 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
7017 TRACE("returning %s\n", debugstr_w(*pbstrOut));
7018 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
7021 /************************************************************************
7022 * VarBstrFromI8 (OLEAUT32.370)
7024 * Convert a VT_I8 to a VT_BSTR.
7026 * PARAMS
7027 * llIn [I] Source
7028 * lcid [I] LCID for the conversion
7029 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7030 * pbstrOut [O] Destination
7032 * RETURNS
7033 * Success: S_OK.
7034 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7035 * E_OUTOFMEMORY, if memory allocation fails.
7037 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7039 ULONG64 ul64 = llIn;
7041 if (llIn < 0)
7043 ul64 = -llIn;
7044 dwFlags |= VAR_NEGATIVE;
7046 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
7049 /************************************************************************
7050 * VarBstrFromUI8 (OLEAUT32.371)
7052 * Convert a VT_UI8 to a VT_BSTR.
7054 * PARAMS
7055 * ullIn [I] Source
7056 * lcid [I] LCID for the conversion
7057 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7058 * pbstrOut [O] Destination
7060 * RETURNS
7061 * Success: S_OK.
7062 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7063 * E_OUTOFMEMORY, if memory allocation fails.
7065 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7067 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
7070 /************************************************************************
7071 * VarBstrFromDisp (OLEAUT32.115)
7073 * Convert a VT_DISPATCH to a BSTR.
7075 * PARAMS
7076 * pdispIn [I] Source
7077 * lcid [I] LCID for conversion
7078 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7079 * pbstrOut [O] Destination
7081 * RETURNS
7082 * Success: S_OK.
7083 * Failure: E_INVALIDARG, if the source value is invalid
7084 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7086 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7088 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
7091 /**********************************************************************
7092 * VarBstrCat (OLEAUT32.313)
7094 * Concatenate two BSTR values.
7096 * PARAMS
7097 * pbstrLeft [I] Source
7098 * pbstrRight [I] Value to concatenate
7099 * pbstrOut [O] Destination
7101 * RETURNS
7102 * Success: S_OK.
7103 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7104 * E_OUTOFMEMORY, if memory allocation fails.
7106 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
7108 unsigned int lenLeft, lenRight;
7110 TRACE("%s,%s,%p\n",
7111 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7112 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
7114 if (!pbstrOut)
7115 return E_INVALIDARG;
7117 /* use byte length here to properly handle ansi-allocated BSTRs */
7118 lenLeft = pbstrLeft ? SysStringByteLen(pbstrLeft) : 0;
7119 lenRight = pbstrRight ? SysStringByteLen(pbstrRight) : 0;
7121 *pbstrOut = SysAllocStringByteLen(NULL, lenLeft + lenRight);
7122 if (!*pbstrOut)
7123 return E_OUTOFMEMORY;
7125 (*pbstrOut)[0] = '\0';
7127 if (pbstrLeft)
7128 memcpy(*pbstrOut, pbstrLeft, lenLeft);
7130 if (pbstrRight)
7131 memcpy((CHAR*)*pbstrOut + lenLeft, pbstrRight, lenRight);
7133 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
7134 return S_OK;
7137 /**********************************************************************
7138 * VarBstrCmp (OLEAUT32.314)
7140 * Compare two BSTR values.
7142 * PARAMS
7143 * pbstrLeft [I] Source
7144 * pbstrRight [I] Value to compare
7145 * lcid [I] LCID for the comparison
7146 * dwFlags [I] Flags to pass directly to CompareStringW().
7148 * RETURNS
7149 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7150 * than, equal to or greater than pbstrRight respectively.
7152 * NOTES
7153 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7154 * states. A NULL BSTR pointer is equivalent to an empty string.
7155 * If LCID is equal to 0, a byte by byte comparison is performed.
7157 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
7159 HRESULT hres;
7160 int ret;
7162 TRACE("%s,%s,%d,%08x\n",
7163 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7164 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
7166 if (!pbstrLeft || !*pbstrLeft)
7168 if (pbstrRight && *pbstrRight)
7169 return VARCMP_LT;
7171 else if (!pbstrRight || !*pbstrRight)
7172 return VARCMP_GT;
7174 if (lcid == 0)
7176 unsigned int lenLeft = SysStringByteLen(pbstrLeft);
7177 unsigned int lenRight = SysStringByteLen(pbstrRight);
7178 ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight));
7179 if (ret < 0)
7180 return VARCMP_LT;
7181 if (ret > 0)
7182 return VARCMP_GT;
7183 if (lenLeft < lenRight)
7184 return VARCMP_LT;
7185 if (lenLeft > lenRight)
7186 return VARCMP_GT;
7187 return VARCMP_EQ;
7189 else
7191 unsigned int lenLeft = SysStringLen(pbstrLeft);
7192 unsigned int lenRight = SysStringLen(pbstrRight);
7194 if (lenLeft == 0 || lenRight == 0)
7196 if (lenLeft == 0 && lenRight == 0) return VARCMP_EQ;
7197 return lenLeft < lenRight ? VARCMP_LT : VARCMP_GT;
7200 hres = CompareStringW(lcid, dwFlags, pbstrLeft, lenLeft,
7201 pbstrRight, lenRight) - CSTR_LESS_THAN;
7202 TRACE("%d\n", hres);
7203 return hres;
7208 * DATE
7211 /******************************************************************************
7212 * VarDateFromUI1 (OLEAUT32.88)
7214 * Convert a VT_UI1 to a VT_DATE.
7216 * PARAMS
7217 * bIn [I] Source
7218 * pdateOut [O] Destination
7220 * RETURNS
7221 * S_OK.
7223 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
7225 return VarR8FromUI1(bIn, pdateOut);
7228 /******************************************************************************
7229 * VarDateFromI2 (OLEAUT32.89)
7231 * Convert a VT_I2 to a VT_DATE.
7233 * PARAMS
7234 * sIn [I] Source
7235 * pdateOut [O] Destination
7237 * RETURNS
7238 * S_OK.
7240 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
7242 return VarR8FromI2(sIn, pdateOut);
7245 /******************************************************************************
7246 * VarDateFromI4 (OLEAUT32.90)
7248 * Convert a VT_I4 to a VT_DATE.
7250 * PARAMS
7251 * lIn [I] Source
7252 * pdateOut [O] Destination
7254 * RETURNS
7255 * S_OK.
7257 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
7259 return VarDateFromR8(lIn, pdateOut);
7262 /******************************************************************************
7263 * VarDateFromR4 (OLEAUT32.91)
7265 * Convert a VT_R4 to a VT_DATE.
7267 * PARAMS
7268 * fltIn [I] Source
7269 * pdateOut [O] Destination
7271 * RETURNS
7272 * S_OK.
7274 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
7276 return VarR8FromR4(fltIn, pdateOut);
7279 /******************************************************************************
7280 * VarDateFromR8 (OLEAUT32.92)
7282 * Convert a VT_R8 to a VT_DATE.
7284 * PARAMS
7285 * dblIn [I] Source
7286 * pdateOut [O] Destination
7288 * RETURNS
7289 * S_OK.
7291 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
7293 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
7294 *pdateOut = (DATE)dblIn;
7295 return S_OK;
7298 /**********************************************************************
7299 * VarDateFromDisp (OLEAUT32.95)
7301 * Convert a VT_DISPATCH to a VT_DATE.
7303 * PARAMS
7304 * pdispIn [I] Source
7305 * lcid [I] LCID for conversion
7306 * pdateOut [O] Destination
7308 * RETURNS
7309 * Success: S_OK.
7310 * Failure: E_INVALIDARG, if the source value is invalid
7311 * DISP_E_OVERFLOW, if the value will not fit in the destination
7312 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7314 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
7316 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
7319 /******************************************************************************
7320 * VarDateFromBool (OLEAUT32.96)
7322 * Convert a VT_BOOL to a VT_DATE.
7324 * PARAMS
7325 * boolIn [I] Source
7326 * pdateOut [O] Destination
7328 * RETURNS
7329 * S_OK.
7331 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
7333 return VarR8FromBool(boolIn, pdateOut);
7336 /**********************************************************************
7337 * VarDateFromCy (OLEAUT32.93)
7339 * Convert a VT_CY to a VT_DATE.
7341 * PARAMS
7342 * lIn [I] Source
7343 * pdateOut [O] Destination
7345 * RETURNS
7346 * S_OK.
7348 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
7350 return VarR8FromCy(cyIn, pdateOut);
7353 /* Date string parsing */
7354 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7355 #define DP_DATESEP 0x02 /* Date separator */
7356 #define DP_MONTH 0x04 /* Month name */
7357 #define DP_AM 0x08 /* AM */
7358 #define DP_PM 0x10 /* PM */
7360 typedef struct tagDATEPARSE
7362 DWORD dwCount; /* Number of fields found so far (maximum 6) */
7363 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
7364 DWORD dwFlags[6]; /* Flags for each field */
7365 DWORD dwValues[6]; /* Value of each field */
7366 } DATEPARSE;
7368 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7370 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7372 /* Determine if a day is valid in a given month of a given year */
7373 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
7375 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7377 if (day && month && month < 13)
7379 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
7380 return TRUE;
7382 return FALSE;
7385 /* Possible orders for 3 numbers making up a date */
7386 #define ORDER_MDY 0x01
7387 #define ORDER_YMD 0x02
7388 #define ORDER_YDM 0x04
7389 #define ORDER_DMY 0x08
7390 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7392 /* Determine a date for a particular locale, from 3 numbers */
7393 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
7394 DWORD offset, SYSTEMTIME *st)
7396 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
7398 if (!dp->dwCount)
7400 v1 = 30; /* Default to (Variant) 0 date part */
7401 v2 = 12;
7402 v3 = 1899;
7403 goto VARIANT_MakeDate_OK;
7406 v1 = dp->dwValues[offset + 0];
7407 v2 = dp->dwValues[offset + 1];
7408 if (dp->dwCount == 2)
7410 SYSTEMTIME current;
7411 GetSystemTime(&current);
7412 v3 = current.wYear;
7414 else
7415 v3 = dp->dwValues[offset + 2];
7417 TRACE("(%d,%d,%d,%d,%d)\n", v1, v2, v3, iDate, offset);
7419 /* If one number must be a month (Because a month name was given), then only
7420 * consider orders with the month in that position.
7421 * If we took the current year as 'v3', then only allow a year in that position.
7423 if (dp->dwFlags[offset + 0] & DP_MONTH)
7425 dwAllOrders = ORDER_MDY;
7427 else if (dp->dwFlags[offset + 1] & DP_MONTH)
7429 dwAllOrders = ORDER_DMY;
7430 if (dp->dwCount > 2)
7431 dwAllOrders |= ORDER_YMD;
7433 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
7435 dwAllOrders = ORDER_YDM;
7437 else
7439 dwAllOrders = ORDER_MDY|ORDER_DMY;
7440 if (dp->dwCount > 2)
7441 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
7444 VARIANT_MakeDate_Start:
7445 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders);
7447 while (dwAllOrders)
7449 DWORD dwTemp;
7451 if (dwCount == 0)
7453 /* First: Try the order given by iDate */
7454 switch (iDate)
7456 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
7457 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
7458 default: dwTry = dwAllOrders & ORDER_YMD; break;
7461 else if (dwCount == 1)
7463 /* Second: Try all the orders compatible with iDate */
7464 switch (iDate)
7466 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7467 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YDM|ORDER_MYD); break;
7468 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7471 else
7473 /* Finally: Try any remaining orders */
7474 dwTry = dwAllOrders;
7477 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount, dwTry);
7479 dwCount++;
7480 if (!dwTry)
7481 continue;
7483 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7485 if (dwTry & ORDER_MDY)
7487 if (VARIANT_IsValidMonthDay(v2,v1,v3))
7489 DATE_SWAP(v1,v2);
7490 goto VARIANT_MakeDate_OK;
7492 dwAllOrders &= ~ORDER_MDY;
7494 if (dwTry & ORDER_YMD)
7496 if (VARIANT_IsValidMonthDay(v3,v2,v1))
7498 DATE_SWAP(v1,v3);
7499 goto VARIANT_MakeDate_OK;
7501 dwAllOrders &= ~ORDER_YMD;
7503 if (dwTry & ORDER_YDM)
7505 if (VARIANT_IsValidMonthDay(v2,v3,v1))
7507 DATE_SWAP(v1,v2);
7508 DATE_SWAP(v2,v3);
7509 goto VARIANT_MakeDate_OK;
7511 dwAllOrders &= ~ORDER_YDM;
7513 if (dwTry & ORDER_DMY)
7515 if (VARIANT_IsValidMonthDay(v1,v2,v3))
7516 goto VARIANT_MakeDate_OK;
7517 dwAllOrders &= ~ORDER_DMY;
7519 if (dwTry & ORDER_MYD)
7521 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7522 if (VARIANT_IsValidMonthDay(v3,v1,v2))
7524 DATE_SWAP(v1,v3);
7525 DATE_SWAP(v2,v3);
7526 goto VARIANT_MakeDate_OK;
7528 dwAllOrders &= ~ORDER_MYD;
7532 if (dp->dwCount == 2)
7534 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7535 v3 = 1; /* 1st of the month */
7536 dwAllOrders = ORDER_YMD|ORDER_MYD;
7537 dp->dwCount = 0; /* Don't return to this code path again */
7538 dwCount = 0;
7539 goto VARIANT_MakeDate_Start;
7542 /* No valid dates were able to be constructed */
7543 return DISP_E_TYPEMISMATCH;
7545 VARIANT_MakeDate_OK:
7547 /* Check that the time part is ok */
7548 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
7549 return DISP_E_TYPEMISMATCH;
7551 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7552 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
7553 st->wHour += 12;
7554 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
7555 st->wHour = 0;
7556 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7558 st->wDay = v1;
7559 st->wMonth = v2;
7560 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7561 * be retrieved from:
7562 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7563 * But Wine doesn't have/use that key as at the time of writing.
7565 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
7566 TRACE("Returning date %d/%d/%d\n", v1, v2, st->wYear);
7567 return S_OK;
7570 /******************************************************************************
7571 * VarDateFromStr [OLEAUT32.94]
7573 * Convert a VT_BSTR to at VT_DATE.
7575 * PARAMS
7576 * strIn [I] String to convert
7577 * lcid [I] Locale identifier for the conversion
7578 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7579 * pdateOut [O] Destination for the converted value
7581 * RETURNS
7582 * Success: S_OK. pdateOut contains the converted value.
7583 * FAILURE: An HRESULT error code indicating the problem.
7585 * NOTES
7586 * Any date format that can be created using the date formats from lcid
7587 * (Either from kernel Nls functions, variant conversion or formatting) is a
7588 * valid input to this function. In addition, a few more esoteric formats are
7589 * also supported for compatibility with the native version. The date is
7590 * interpreted according to the date settings in the control panel, unless
7591 * the date is invalid in that format, in which the most compatible format
7592 * that produces a valid date will be used.
7594 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7596 static const USHORT ParseDateTokens[] =
7598 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7599 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7600 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7601 LOCALE_SMONTHNAME13,
7602 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7603 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7604 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7605 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7606 LOCALE_SABBREVMONTHNAME13,
7607 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7608 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7609 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7610 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7611 LOCALE_SABBREVDAYNAME7,
7612 LOCALE_S1159, LOCALE_S2359,
7613 LOCALE_SDATE
7615 static const BYTE ParseDateMonths[] =
7617 1,2,3,4,5,6,7,8,9,10,11,12,13,
7618 1,2,3,4,5,6,7,8,9,10,11,12,13
7620 unsigned int i;
7621 BSTR tokens[ARRAY_SIZE(ParseDateTokens)];
7622 DATEPARSE dp;
7623 DWORD dwDateSeps = 0, iDate = 0;
7624 HRESULT hRet = S_OK;
7626 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7627 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7628 return E_INVALIDARG;
7630 if (!strIn)
7631 return DISP_E_TYPEMISMATCH;
7633 *pdateOut = 0.0;
7635 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7637 memset(&dp, 0, sizeof(dp));
7639 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7640 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7641 TRACE("iDate is %d\n", iDate);
7643 /* Get the month/day/am/pm tokens for this locale */
7644 for (i = 0; i < ARRAY_SIZE(tokens); i++)
7646 WCHAR buff[128];
7647 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7649 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7650 * GetAltMonthNames(). We should really cache these strings too.
7652 buff[0] = '\0';
7653 GetLocaleInfoW(lcid, lctype, buff, ARRAY_SIZE(buff));
7654 tokens[i] = SysAllocString(buff);
7655 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7658 /* Parse the string into our structure */
7659 while (*strIn)
7661 if (isdigitW(*strIn))
7663 if (dp.dwCount >= 6)
7665 hRet = DISP_E_TYPEMISMATCH;
7666 break;
7668 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
7669 dp.dwCount++;
7670 strIn--;
7672 else if (isalphaW(*strIn))
7674 BOOL bFound = FALSE;
7676 for (i = 0; i < ARRAY_SIZE(tokens); i++)
7678 DWORD dwLen = strlenW(tokens[i]);
7679 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
7681 if (i <= 25)
7683 if (dp.dwCount >= 6)
7684 hRet = DISP_E_TYPEMISMATCH;
7685 else
7687 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7688 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7689 dp.dwCount++;
7692 else if (i > 39 && i < 42)
7694 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7695 hRet = DISP_E_TYPEMISMATCH;
7696 else
7698 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7699 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7702 strIn += (dwLen - 1);
7703 bFound = TRUE;
7704 break;
7708 if (!bFound)
7710 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7711 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7713 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7714 if (*strIn == 'a' || *strIn == 'A')
7716 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7717 dp.dwParseFlags |= DP_AM;
7719 else
7721 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7722 dp.dwParseFlags |= DP_PM;
7724 strIn++;
7726 else
7728 TRACE("No matching token for %s\n", debugstr_w(strIn));
7729 hRet = DISP_E_TYPEMISMATCH;
7730 break;
7734 else if (*strIn == ':' || *strIn == '.')
7736 if (!dp.dwCount || !strIn[1])
7737 hRet = DISP_E_TYPEMISMATCH;
7738 else
7739 if (tokens[42][0] == *strIn)
7741 dwDateSeps++;
7742 if (dwDateSeps > 2)
7743 hRet = DISP_E_TYPEMISMATCH;
7744 else
7745 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7747 else
7748 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7750 else if (*strIn == '-' || *strIn == '/')
7752 dwDateSeps++;
7753 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7754 hRet = DISP_E_TYPEMISMATCH;
7755 else
7756 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7758 else if (*strIn == ',' || isspaceW(*strIn))
7760 if (*strIn == ',' && !strIn[1])
7761 hRet = DISP_E_TYPEMISMATCH;
7763 else
7765 hRet = DISP_E_TYPEMISMATCH;
7767 strIn++;
7770 if (!dp.dwCount || dp.dwCount > 6 ||
7771 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7772 hRet = DISP_E_TYPEMISMATCH;
7774 if (SUCCEEDED(hRet))
7776 SYSTEMTIME st;
7777 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7779 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7781 /* Figure out which numbers correspond to which fields.
7783 * This switch statement works based on the fact that native interprets any
7784 * fields that are not joined with a time separator ('.' or ':') as date
7785 * fields. Thus we construct a value from 0-32 where each set bit indicates
7786 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7787 * For valid permutations, we set dwOffset to point to the first date field
7788 * and shorten dp.dwCount by the number of time fields found. The real
7789 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7790 * each date number must represent in the context of iDate.
7792 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7794 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7796 case 0x1: /* TT TTDD TTDDD */
7797 if (dp.dwCount > 3 &&
7798 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7799 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7800 hRet = DISP_E_TYPEMISMATCH;
7801 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7802 hRet = DISP_E_TYPEMISMATCH;
7803 st.wHour = dp.dwValues[0];
7804 st.wMinute = dp.dwValues[1];
7805 dp.dwCount -= 2;
7806 dwOffset = 2;
7807 break;
7809 case 0x3: /* TTT TTTDD TTTDDD */
7810 if (dp.dwCount > 4 &&
7811 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7812 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7813 hRet = DISP_E_TYPEMISMATCH;
7814 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7815 hRet = DISP_E_TYPEMISMATCH;
7816 st.wHour = dp.dwValues[0];
7817 st.wMinute = dp.dwValues[1];
7818 st.wSecond = dp.dwValues[2];
7819 dwOffset = 3;
7820 dp.dwCount -= 3;
7821 break;
7823 case 0x4: /* DDTT */
7824 if (dp.dwCount != 4 ||
7825 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7826 hRet = DISP_E_TYPEMISMATCH;
7828 st.wHour = dp.dwValues[2];
7829 st.wMinute = dp.dwValues[3];
7830 dp.dwCount -= 2;
7831 break;
7833 case 0x0: /* T DD DDD TDDD TDDD */
7834 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7836 st.wHour = dp.dwValues[0]; /* T */
7837 dp.dwCount = 0;
7838 break;
7840 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7842 hRet = DISP_E_TYPEMISMATCH;
7844 else if (dp.dwCount == 3)
7846 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7848 dp.dwCount = 2;
7849 st.wHour = dp.dwValues[0];
7850 dwOffset = 1;
7851 break;
7853 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7855 dp.dwCount = 2;
7856 st.wHour = dp.dwValues[2];
7857 break;
7859 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7860 hRet = DISP_E_TYPEMISMATCH;
7862 else if (dp.dwCount == 4)
7864 dp.dwCount = 3;
7865 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7867 st.wHour = dp.dwValues[0];
7868 dwOffset = 1;
7870 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7872 st.wHour = dp.dwValues[3];
7874 else
7875 hRet = DISP_E_TYPEMISMATCH;
7876 break;
7878 /* .. fall through .. */
7880 case 0x8: /* DDDTT */
7881 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7882 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7883 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7884 dp.dwCount == 4 || dp.dwCount == 6)
7885 hRet = DISP_E_TYPEMISMATCH;
7886 st.wHour = dp.dwValues[3];
7887 st.wMinute = dp.dwValues[4];
7888 if (dp.dwCount == 5)
7889 dp.dwCount -= 2;
7890 break;
7892 case 0xC: /* DDTTT */
7893 if (dp.dwCount != 5 ||
7894 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7895 hRet = DISP_E_TYPEMISMATCH;
7896 st.wHour = dp.dwValues[2];
7897 st.wMinute = dp.dwValues[3];
7898 st.wSecond = dp.dwValues[4];
7899 dp.dwCount -= 3;
7900 break;
7902 case 0x18: /* DDDTTT */
7903 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7904 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7905 hRet = DISP_E_TYPEMISMATCH;
7906 st.wHour = dp.dwValues[3];
7907 st.wMinute = dp.dwValues[4];
7908 st.wSecond = dp.dwValues[5];
7909 dp.dwCount -= 3;
7910 break;
7912 default:
7913 hRet = DISP_E_TYPEMISMATCH;
7914 break;
7917 if (SUCCEEDED(hRet))
7919 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7921 if (dwFlags & VAR_TIMEVALUEONLY)
7923 st.wYear = 1899;
7924 st.wMonth = 12;
7925 st.wDay = 30;
7927 else if (dwFlags & VAR_DATEVALUEONLY)
7928 st.wHour = st.wMinute = st.wSecond = 0;
7930 /* Finally, convert the value to a VT_DATE */
7931 if (SUCCEEDED(hRet))
7932 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7936 for (i = 0; i < ARRAY_SIZE(tokens); i++)
7937 SysFreeString(tokens[i]);
7938 return hRet;
7941 /******************************************************************************
7942 * VarDateFromI1 (OLEAUT32.221)
7944 * Convert a VT_I1 to a VT_DATE.
7946 * PARAMS
7947 * cIn [I] Source
7948 * pdateOut [O] Destination
7950 * RETURNS
7951 * S_OK.
7953 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7955 return VarR8FromI1(cIn, pdateOut);
7958 /******************************************************************************
7959 * VarDateFromUI2 (OLEAUT32.222)
7961 * Convert a VT_UI2 to a VT_DATE.
7963 * PARAMS
7964 * uiIn [I] Source
7965 * pdateOut [O] Destination
7967 * RETURNS
7968 * S_OK.
7970 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7972 return VarR8FromUI2(uiIn, pdateOut);
7975 /******************************************************************************
7976 * VarDateFromUI4 (OLEAUT32.223)
7978 * Convert a VT_UI4 to a VT_DATE.
7980 * PARAMS
7981 * ulIn [I] Source
7982 * pdateOut [O] Destination
7984 * RETURNS
7985 * S_OK.
7987 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7989 return VarDateFromR8(ulIn, pdateOut);
7992 /**********************************************************************
7993 * VarDateFromDec (OLEAUT32.224)
7995 * Convert a VT_DECIMAL to a VT_DATE.
7997 * PARAMS
7998 * pdecIn [I] Source
7999 * pdateOut [O] Destination
8001 * RETURNS
8002 * S_OK.
8004 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
8006 return VarR8FromDec(pdecIn, pdateOut);
8009 /******************************************************************************
8010 * VarDateFromI8 (OLEAUT32.364)
8012 * Convert a VT_I8 to a VT_DATE.
8014 * PARAMS
8015 * llIn [I] Source
8016 * pdateOut [O] Destination
8018 * RETURNS
8019 * Success: S_OK.
8020 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8022 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
8024 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
8025 *pdateOut = (DATE)llIn;
8026 return S_OK;
8029 /******************************************************************************
8030 * VarDateFromUI8 (OLEAUT32.365)
8032 * Convert a VT_UI8 to a VT_DATE.
8034 * PARAMS
8035 * ullIn [I] Source
8036 * pdateOut [O] Destination
8038 * RETURNS
8039 * Success: S_OK.
8040 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8042 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
8044 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
8045 *pdateOut = (DATE)ullIn;
8046 return S_OK;