oleaut32: Handle BSTRs in VARIANT_CopyData.
[wine/multimedia.git] / dlls / oleaut32 / vartype.c
blobdf70e905a6f31b74a807b146c37e07618d99076b
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 OLEAUT32_hModule;
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 = sizeof(rgb) / sizeof(BYTE);
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 const 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 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
126 (DISPPARAMS*)&emptyParams, &srcVar, NULL, NULL);
128 if (SUCCEEDED(hRet))
130 /* Convert the property to the requested type */
131 V_VT(&dstVar) = VT_EMPTY;
132 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt);
133 VariantClear(&srcVar);
135 if (SUCCEEDED(hRet))
137 VARIANT_CopyData(&dstVar, vt, pOut);
138 VariantClear(&srcVar);
141 else
142 hRet = DISP_E_TYPEMISMATCH;
143 return hRet;
146 /* Inline return type */
147 #define RETTYP inline static HRESULT
150 /* Simple compiler cast from one type to another */
151 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
152 *out = in; return S_OK; }
154 /* Compiler cast where input cannot be negative */
155 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
156 if (in < (src)0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
158 /* Compiler cast where input cannot be > some number */
159 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
160 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
162 /* Compiler cast where input cannot be < some number or >= some other number */
163 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
164 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
166 /* I1 */
167 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX);
168 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX);
169 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX);
170 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool);
171 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX);
172 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX);
173 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX);
174 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX);
176 /* UI1 */
177 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX);
178 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool);
179 NEGTST(BYTE, signed char, VarUI1FromI1);
180 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX);
181 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX);
182 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX);
183 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX);
184 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX);
186 /* I2 */
187 SIMPLE(SHORT, BYTE, VarI2FromUI1);
188 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX);
189 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool);
190 SIMPLE(SHORT, signed char, VarI2FromI1);
191 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX);
192 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX);
193 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX);
194 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX);
196 /* UI2 */
197 SIMPLE(USHORT, BYTE, VarUI2FromUI1);
198 NEGTST(USHORT, SHORT, VarUI2FromI2);
199 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX);
200 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool);
201 NEGTST(USHORT, signed char, VarUI2FromI1);
202 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX);
203 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX);
204 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX);
206 /* I4 */
207 SIMPLE(LONG, BYTE, VarI4FromUI1);
208 SIMPLE(LONG, SHORT, VarI4FromI2);
209 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool);
210 SIMPLE(LONG, signed char, VarI4FromI1);
211 SIMPLE(LONG, USHORT, VarI4FromUI2);
212 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX);
213 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX);
214 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX);
216 /* UI4 */
217 SIMPLE(ULONG, BYTE, VarUI4FromUI1);
218 NEGTST(ULONG, SHORT, VarUI4FromI2);
219 NEGTST(ULONG, LONG, VarUI4FromI4);
220 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool);
221 NEGTST(ULONG, signed char, VarUI4FromI1);
222 SIMPLE(ULONG, USHORT, VarUI4FromUI2);
223 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX);
224 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX);
226 /* I8 */
227 SIMPLE(LONG64, BYTE, VarI8FromUI1);
228 SIMPLE(LONG64, SHORT, VarI8FromI2);
229 SIMPLE(LONG64, signed char, VarI8FromI1);
230 SIMPLE(LONG64, USHORT, VarI8FromUI2);
231 SIMPLE(LONG64, LONG, VarI8FromI4);
232 SIMPLE(LONG64, ULONG, VarI8FromUI4);
233 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX);
235 /* UI8 */
236 SIMPLE(ULONG64, BYTE, VarUI8FromUI1);
237 NEGTST(ULONG64, SHORT, VarUI8FromI2);
238 NEGTST(ULONG64, signed char, VarUI8FromI1);
239 SIMPLE(ULONG64, USHORT, VarUI8FromUI2);
240 NEGTST(ULONG64, LONG, VarUI8FromI4);
241 SIMPLE(ULONG64, ULONG, VarUI8FromUI4);
242 NEGTST(ULONG64, LONG64, VarUI8FromI8);
244 /* R4 (float) */
245 SIMPLE(float, BYTE, VarR4FromUI1);
246 SIMPLE(float, SHORT, VarR4FromI2);
247 SIMPLE(float, signed char, VarR4FromI1);
248 SIMPLE(float, USHORT, VarR4FromUI2);
249 SIMPLE(float, LONG, VarR4FromI4);
250 SIMPLE(float, ULONG, VarR4FromUI4);
251 SIMPLE(float, LONG64, VarR4FromI8);
252 SIMPLE(float, ULONG64, VarR4FromUI8);
254 /* R8 (double) */
255 SIMPLE(double, BYTE, VarR8FromUI1);
256 SIMPLE(double, SHORT, VarR8FromI2);
257 SIMPLE(double, float, VarR8FromR4);
258 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
259 SIMPLE(double, DATE, VarR8FromDate);
260 SIMPLE(double, signed char, VarR8FromI1);
261 SIMPLE(double, USHORT, VarR8FromUI2);
262 SIMPLE(double, LONG, VarR8FromI4);
263 SIMPLE(double, ULONG, VarR8FromUI4);
264 SIMPLE(double, LONG64, VarR8FromI8);
265 SIMPLE(double, ULONG64, VarR8FromUI8);
268 /* I1
271 /************************************************************************
272 * VarI1FromUI1 (OLEAUT32.244)
274 * Convert a VT_UI1 to a VT_I1.
276 * PARAMS
277 * bIn [I] Source
278 * pcOut [O] Destination
280 * RETURNS
281 * Success: S_OK.
282 * Failure: E_INVALIDARG, if the source value is invalid
283 * DISP_E_OVERFLOW, if the value will not fit in the destination
285 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
287 return _VarI1FromUI1(bIn, pcOut);
290 /************************************************************************
291 * VarI1FromI2 (OLEAUT32.245)
293 * Convert a VT_I2 to a VT_I1.
295 * PARAMS
296 * sIn [I] Source
297 * pcOut [O] Destination
299 * RETURNS
300 * Success: S_OK.
301 * Failure: E_INVALIDARG, if the source value is invalid
302 * DISP_E_OVERFLOW, if the value will not fit in the destination
304 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
306 return _VarI1FromI2(sIn, pcOut);
309 /************************************************************************
310 * VarI1FromI4 (OLEAUT32.246)
312 * Convert a VT_I4 to a VT_I1.
314 * PARAMS
315 * iIn [I] Source
316 * pcOut [O] Destination
318 * RETURNS
319 * Success: S_OK.
320 * Failure: E_INVALIDARG, if the source value is invalid
321 * DISP_E_OVERFLOW, if the value will not fit in the destination
323 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
325 return _VarI1FromI4(iIn, pcOut);
328 /************************************************************************
329 * VarI1FromR4 (OLEAUT32.247)
331 * Convert a VT_R4 to a VT_I1.
333 * PARAMS
334 * fltIn [I] Source
335 * pcOut [O] Destination
337 * RETURNS
338 * Success: S_OK.
339 * Failure: E_INVALIDARG, if the source value is invalid
340 * DISP_E_OVERFLOW, if the value will not fit in the destination
342 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
344 return VarI1FromR8(fltIn, pcOut);
347 /************************************************************************
348 * VarI1FromR8 (OLEAUT32.248)
350 * Convert a VT_R8 to a VT_I1.
352 * PARAMS
353 * dblIn [I] Source
354 * pcOut [O] Destination
356 * RETURNS
357 * Success: S_OK.
358 * Failure: E_INVALIDARG, if the source value is invalid
359 * DISP_E_OVERFLOW, if the value will not fit in the destination
361 * NOTES
362 * See VarI8FromR8() for details concerning rounding.
364 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
366 if (dblIn < (double)I1_MIN || dblIn > (double)I1_MAX)
367 return DISP_E_OVERFLOW;
368 VARIANT_DutchRound(CHAR, dblIn, *pcOut);
369 return S_OK;
372 /************************************************************************
373 * VarI1FromDate (OLEAUT32.249)
375 * Convert a VT_DATE to a VT_I1.
377 * PARAMS
378 * dateIn [I] Source
379 * pcOut [O] Destination
381 * RETURNS
382 * Success: S_OK.
383 * Failure: E_INVALIDARG, if the source value is invalid
384 * DISP_E_OVERFLOW, if the value will not fit in the destination
386 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
388 return VarI1FromR8(dateIn, pcOut);
391 /************************************************************************
392 * VarI1FromCy (OLEAUT32.250)
394 * Convert a VT_CY to a VT_I1.
396 * PARAMS
397 * cyIn [I] Source
398 * pcOut [O] Destination
400 * RETURNS
401 * Success: S_OK.
402 * Failure: E_INVALIDARG, if the source value is invalid
403 * DISP_E_OVERFLOW, if the value will not fit in the destination
405 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
407 LONG i = I1_MAX + 1;
409 VarI4FromCy(cyIn, &i);
410 return _VarI1FromI4(i, pcOut);
413 /************************************************************************
414 * VarI1FromStr (OLEAUT32.251)
416 * Convert a VT_BSTR to a VT_I1.
418 * PARAMS
419 * strIn [I] Source
420 * lcid [I] LCID for the conversion
421 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
422 * pcOut [O] Destination
424 * RETURNS
425 * Success: S_OK.
426 * Failure: E_INVALIDARG, if the source value is invalid
427 * DISP_E_OVERFLOW, if the value will not fit in the destination
428 * DISP_E_TYPEMISMATCH, if the type cannot be converted
430 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
432 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
435 /************************************************************************
436 * VarI1FromDisp (OLEAUT32.252)
438 * Convert a VT_DISPATCH to a VT_I1.
440 * PARAMS
441 * pdispIn [I] Source
442 * lcid [I] LCID for conversion
443 * pcOut [O] Destination
445 * RETURNS
446 * Success: S_OK.
447 * Failure: E_INVALIDARG, if the source value is invalid
448 * DISP_E_OVERFLOW, if the value will not fit in the destination
449 * DISP_E_TYPEMISMATCH, if the type cannot be converted
451 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
453 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0);
456 /************************************************************************
457 * VarI1FromBool (OLEAUT32.253)
459 * Convert a VT_BOOL to a VT_I1.
461 * PARAMS
462 * boolIn [I] Source
463 * pcOut [O] Destination
465 * RETURNS
466 * S_OK.
468 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
470 return _VarI1FromBool(boolIn, pcOut);
473 /************************************************************************
474 * VarI1FromUI2 (OLEAUT32.254)
476 * Convert a VT_UI2 to a VT_I1.
478 * PARAMS
479 * usIn [I] Source
480 * pcOut [O] Destination
482 * RETURNS
483 * Success: S_OK.
484 * Failure: E_INVALIDARG, if the source value is invalid
485 * DISP_E_OVERFLOW, if the value will not fit in the destination
487 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
489 return _VarI1FromUI2(usIn, pcOut);
492 /************************************************************************
493 * VarI1FromUI4 (OLEAUT32.255)
495 * Convert a VT_UI4 to a VT_I1.
497 * PARAMS
498 * ulIn [I] Source
499 * pcOut [O] Destination
501 * RETURNS
502 * Success: S_OK.
503 * Failure: E_INVALIDARG, if the source value is invalid
504 * DISP_E_OVERFLOW, if the value will not fit in the destination
505 * DISP_E_TYPEMISMATCH, if the type cannot be converted
507 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
509 return _VarI1FromUI4(ulIn, pcOut);
512 /************************************************************************
513 * VarI1FromDec (OLEAUT32.256)
515 * Convert a VT_DECIMAL to a VT_I1.
517 * PARAMS
518 * pDecIn [I] Source
519 * pcOut [O] Destination
521 * RETURNS
522 * Success: S_OK.
523 * Failure: E_INVALIDARG, if the source value is invalid
524 * DISP_E_OVERFLOW, if the value will not fit in the destination
526 HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut)
528 LONG64 i64;
529 HRESULT hRet;
531 hRet = VarI8FromDec(pdecIn, &i64);
533 if (SUCCEEDED(hRet))
534 hRet = _VarI1FromI8(i64, pcOut);
535 return hRet;
538 /************************************************************************
539 * VarI1FromI8 (OLEAUT32.376)
541 * Convert a VT_I8 to a VT_I1.
543 * PARAMS
544 * llIn [I] Source
545 * pcOut [O] Destination
547 * RETURNS
548 * Success: S_OK.
549 * Failure: E_INVALIDARG, if the source value is invalid
550 * DISP_E_OVERFLOW, if the value will not fit in the destination
552 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
554 return _VarI1FromI8(llIn, pcOut);
557 /************************************************************************
558 * VarI1FromUI8 (OLEAUT32.377)
560 * Convert a VT_UI8 to a VT_I1.
562 * PARAMS
563 * ullIn [I] Source
564 * pcOut [O] Destination
566 * RETURNS
567 * Success: S_OK.
568 * Failure: E_INVALIDARG, if the source value is invalid
569 * DISP_E_OVERFLOW, if the value will not fit in the destination
571 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
573 return _VarI1FromUI8(ullIn, pcOut);
576 /* UI1
579 /************************************************************************
580 * VarUI1FromI2 (OLEAUT32.130)
582 * Convert a VT_I2 to a VT_UI1.
584 * PARAMS
585 * sIn [I] Source
586 * pbOut [O] Destination
588 * RETURNS
589 * Success: S_OK.
590 * Failure: E_INVALIDARG, if the source value is invalid
591 * DISP_E_OVERFLOW, if the value will not fit in the destination
593 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
595 return _VarUI1FromI2(sIn, pbOut);
598 /************************************************************************
599 * VarUI1FromI4 (OLEAUT32.131)
601 * Convert a VT_I4 to a VT_UI1.
603 * PARAMS
604 * iIn [I] Source
605 * pbOut [O] Destination
607 * RETURNS
608 * Success: S_OK.
609 * Failure: E_INVALIDARG, if the source value is invalid
610 * DISP_E_OVERFLOW, if the value will not fit in the destination
612 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
614 return _VarUI1FromI4(iIn, pbOut);
617 /************************************************************************
618 * VarUI1FromR4 (OLEAUT32.132)
620 * Convert a VT_R4 to a VT_UI1.
622 * PARAMS
623 * fltIn [I] Source
624 * pbOut [O] Destination
626 * RETURNS
627 * Success: S_OK.
628 * Failure: E_INVALIDARG, if the source value is invalid
629 * DISP_E_OVERFLOW, if the value will not fit in the destination
630 * DISP_E_TYPEMISMATCH, if the type cannot be converted
632 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
634 return VarUI1FromR8(fltIn, pbOut);
637 /************************************************************************
638 * VarUI1FromR8 (OLEAUT32.133)
640 * Convert a VT_R8 to a VT_UI1.
642 * PARAMS
643 * dblIn [I] Source
644 * pbOut [O] Destination
646 * RETURNS
647 * Success: S_OK.
648 * Failure: E_INVALIDARG, if the source value is invalid
649 * DISP_E_OVERFLOW, if the value will not fit in the destination
651 * NOTES
652 * See VarI8FromR8() for details concerning rounding.
654 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
656 if (dblIn < -0.5 || dblIn > (double)UI1_MAX)
657 return DISP_E_OVERFLOW;
658 VARIANT_DutchRound(BYTE, dblIn, *pbOut);
659 return S_OK;
662 /************************************************************************
663 * VarUI1FromCy (OLEAUT32.134)
665 * Convert a VT_CY to a VT_UI1.
667 * PARAMS
668 * cyIn [I] Source
669 * pbOut [O] Destination
671 * RETURNS
672 * Success: S_OK.
673 * Failure: E_INVALIDARG, if the source value is invalid
674 * DISP_E_OVERFLOW, if the value will not fit in the destination
676 * NOTES
677 * Negative values >= -5000 will be converted to 0.
679 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
681 ULONG i = UI1_MAX + 1;
683 VarUI4FromCy(cyIn, &i);
684 return _VarUI1FromUI4(i, pbOut);
687 /************************************************************************
688 * VarUI1FromDate (OLEAUT32.135)
690 * Convert a VT_DATE to a VT_UI1.
692 * PARAMS
693 * dateIn [I] Source
694 * pbOut [O] Destination
696 * RETURNS
697 * Success: S_OK.
698 * Failure: E_INVALIDARG, if the source value is invalid
699 * DISP_E_OVERFLOW, if the value will not fit in the destination
701 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
703 return VarUI1FromR8(dateIn, pbOut);
706 /************************************************************************
707 * VarUI1FromStr (OLEAUT32.136)
709 * Convert a VT_BSTR to a VT_UI1.
711 * PARAMS
712 * strIn [I] Source
713 * lcid [I] LCID for the conversion
714 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
715 * pbOut [O] Destination
717 * RETURNS
718 * Success: S_OK.
719 * Failure: E_INVALIDARG, if the source value is invalid
720 * DISP_E_OVERFLOW, if the value will not fit in the destination
721 * DISP_E_TYPEMISMATCH, if the type cannot be converted
723 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
725 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
728 /************************************************************************
729 * VarUI1FromDisp (OLEAUT32.137)
731 * Convert a VT_DISPATCH to a VT_UI1.
733 * PARAMS
734 * pdispIn [I] Source
735 * lcid [I] LCID for conversion
736 * pbOut [O] Destination
738 * RETURNS
739 * Success: S_OK.
740 * Failure: E_INVALIDARG, if the source value is invalid
741 * DISP_E_OVERFLOW, if the value will not fit in the destination
742 * DISP_E_TYPEMISMATCH, if the type cannot be converted
744 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
746 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0);
749 /************************************************************************
750 * VarUI1FromBool (OLEAUT32.138)
752 * Convert a VT_BOOL to a VT_UI1.
754 * PARAMS
755 * boolIn [I] Source
756 * pbOut [O] Destination
758 * RETURNS
759 * S_OK.
761 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
763 return _VarUI1FromBool(boolIn, pbOut);
766 /************************************************************************
767 * VarUI1FromI1 (OLEAUT32.237)
769 * Convert a VT_I1 to a VT_UI1.
771 * PARAMS
772 * cIn [I] Source
773 * pbOut [O] Destination
775 * RETURNS
776 * Success: S_OK.
777 * Failure: E_INVALIDARG, if the source value is invalid
778 * DISP_E_OVERFLOW, if the value will not fit in the destination
780 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
782 return _VarUI1FromI1(cIn, pbOut);
785 /************************************************************************
786 * VarUI1FromUI2 (OLEAUT32.238)
788 * Convert a VT_UI2 to a VT_UI1.
790 * PARAMS
791 * usIn [I] Source
792 * pbOut [O] Destination
794 * RETURNS
795 * Success: S_OK.
796 * Failure: E_INVALIDARG, if the source value is invalid
797 * DISP_E_OVERFLOW, if the value will not fit in the destination
799 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
801 return _VarUI1FromUI2(usIn, pbOut);
804 /************************************************************************
805 * VarUI1FromUI4 (OLEAUT32.239)
807 * Convert a VT_UI4 to a VT_UI1.
809 * PARAMS
810 * ulIn [I] Source
811 * pbOut [O] Destination
813 * RETURNS
814 * Success: S_OK.
815 * Failure: E_INVALIDARG, if the source value is invalid
816 * DISP_E_OVERFLOW, if the value will not fit in the destination
818 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
820 return _VarUI1FromUI4(ulIn, pbOut);
823 /************************************************************************
824 * VarUI1FromDec (OLEAUT32.240)
826 * Convert a VT_DECIMAL to a VT_UI1.
828 * PARAMS
829 * pDecIn [I] Source
830 * pbOut [O] Destination
832 * RETURNS
833 * Success: S_OK.
834 * Failure: E_INVALIDARG, if the source value is invalid
835 * DISP_E_OVERFLOW, if the value will not fit in the destination
837 HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut)
839 LONG64 i64;
840 HRESULT hRet;
842 hRet = VarI8FromDec(pdecIn, &i64);
844 if (SUCCEEDED(hRet))
845 hRet = _VarUI1FromI8(i64, pbOut);
846 return hRet;
849 /************************************************************************
850 * VarUI1FromI8 (OLEAUT32.372)
852 * Convert a VT_I8 to a VT_UI1.
854 * PARAMS
855 * llIn [I] Source
856 * pbOut [O] Destination
858 * RETURNS
859 * Success: S_OK.
860 * Failure: E_INVALIDARG, if the source value is invalid
861 * DISP_E_OVERFLOW, if the value will not fit in the destination
863 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
865 return _VarUI1FromI8(llIn, pbOut);
868 /************************************************************************
869 * VarUI1FromUI8 (OLEAUT32.373)
871 * Convert a VT_UI8 to a VT_UI1.
873 * PARAMS
874 * ullIn [I] Source
875 * pbOut [O] Destination
877 * RETURNS
878 * Success: S_OK.
879 * Failure: E_INVALIDARG, if the source value is invalid
880 * DISP_E_OVERFLOW, if the value will not fit in the destination
882 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
884 return _VarUI1FromUI8(ullIn, pbOut);
888 /* I2
891 /************************************************************************
892 * VarI2FromUI1 (OLEAUT32.48)
894 * Convert a VT_UI2 to a VT_I2.
896 * PARAMS
897 * bIn [I] Source
898 * psOut [O] Destination
900 * RETURNS
901 * S_OK.
903 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
905 return _VarI2FromUI1(bIn, psOut);
908 /************************************************************************
909 * VarI2FromI4 (OLEAUT32.49)
911 * Convert a VT_I4 to a VT_I2.
913 * PARAMS
914 * iIn [I] Source
915 * psOut [O] Destination
917 * RETURNS
918 * Success: S_OK.
919 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
921 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
923 return _VarI2FromI4(iIn, psOut);
926 /************************************************************************
927 * VarI2FromR4 (OLEAUT32.50)
929 * Convert a VT_R4 to a VT_I2.
931 * PARAMS
932 * fltIn [I] Source
933 * psOut [O] Destination
935 * RETURNS
936 * Success: S_OK.
937 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
939 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
941 return VarI2FromR8(fltIn, psOut);
944 /************************************************************************
945 * VarI2FromR8 (OLEAUT32.51)
947 * Convert a VT_R8 to a VT_I2.
949 * PARAMS
950 * dblIn [I] Source
951 * psOut [O] Destination
953 * RETURNS
954 * Success: S_OK.
955 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
957 * NOTES
958 * See VarI8FromR8() for details concerning rounding.
960 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
962 if (dblIn < (double)I2_MIN || dblIn > (double)I2_MAX)
963 return DISP_E_OVERFLOW;
964 VARIANT_DutchRound(SHORT, dblIn, *psOut);
965 return S_OK;
968 /************************************************************************
969 * VarI2FromCy (OLEAUT32.52)
971 * Convert a VT_CY to a VT_I2.
973 * PARAMS
974 * cyIn [I] Source
975 * psOut [O] Destination
977 * RETURNS
978 * Success: S_OK.
979 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
981 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
983 LONG i = I2_MAX + 1;
985 VarI4FromCy(cyIn, &i);
986 return _VarI2FromI4(i, psOut);
989 /************************************************************************
990 * VarI2FromDate (OLEAUT32.53)
992 * Convert a VT_DATE to a VT_I2.
994 * PARAMS
995 * dateIn [I] Source
996 * psOut [O] Destination
998 * RETURNS
999 * Success: S_OK.
1000 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1002 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
1004 return VarI2FromR8(dateIn, psOut);
1007 /************************************************************************
1008 * VarI2FromStr (OLEAUT32.54)
1010 * Convert a VT_BSTR to a VT_I2.
1012 * PARAMS
1013 * strIn [I] Source
1014 * lcid [I] LCID for the conversion
1015 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1016 * psOut [O] Destination
1018 * RETURNS
1019 * Success: S_OK.
1020 * Failure: E_INVALIDARG, if any parameter is invalid
1021 * DISP_E_OVERFLOW, if the value will not fit in the destination
1022 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1024 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
1026 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
1029 /************************************************************************
1030 * VarI2FromDisp (OLEAUT32.55)
1032 * Convert a VT_DISPATCH to a VT_I2.
1034 * PARAMS
1035 * pdispIn [I] Source
1036 * lcid [I] LCID for conversion
1037 * psOut [O] Destination
1039 * RETURNS
1040 * Success: S_OK.
1041 * Failure: E_INVALIDARG, if pdispIn is invalid,
1042 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1043 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1045 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
1047 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0);
1050 /************************************************************************
1051 * VarI2FromBool (OLEAUT32.56)
1053 * Convert a VT_BOOL to a VT_I2.
1055 * PARAMS
1056 * boolIn [I] Source
1057 * psOut [O] Destination
1059 * RETURNS
1060 * S_OK.
1062 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
1064 return _VarI2FromBool(boolIn, psOut);
1067 /************************************************************************
1068 * VarI2FromI1 (OLEAUT32.205)
1070 * Convert a VT_I1 to a VT_I2.
1072 * PARAMS
1073 * cIn [I] Source
1074 * psOut [O] Destination
1076 * RETURNS
1077 * S_OK.
1079 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
1081 return _VarI2FromI1(cIn, psOut);
1084 /************************************************************************
1085 * VarI2FromUI2 (OLEAUT32.206)
1087 * Convert a VT_UI2 to a VT_I2.
1089 * PARAMS
1090 * usIn [I] Source
1091 * psOut [O] Destination
1093 * RETURNS
1094 * Success: S_OK.
1095 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1097 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
1099 return _VarI2FromUI2(usIn, psOut);
1102 /************************************************************************
1103 * VarI2FromUI4 (OLEAUT32.207)
1105 * Convert a VT_UI4 to a VT_I2.
1107 * PARAMS
1108 * ulIn [I] Source
1109 * psOut [O] Destination
1111 * RETURNS
1112 * Success: S_OK.
1113 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1115 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
1117 return _VarI2FromUI4(ulIn, psOut);
1120 /************************************************************************
1121 * VarI2FromDec (OLEAUT32.208)
1123 * Convert a VT_DECIMAL to a VT_I2.
1125 * PARAMS
1126 * pDecIn [I] Source
1127 * psOut [O] Destination
1129 * RETURNS
1130 * Success: S_OK.
1131 * Failure: E_INVALIDARG, if the source value is invalid
1132 * DISP_E_OVERFLOW, if the value will not fit in the destination
1134 HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut)
1136 LONG64 i64;
1137 HRESULT hRet;
1139 hRet = VarI8FromDec(pdecIn, &i64);
1141 if (SUCCEEDED(hRet))
1142 hRet = _VarI2FromI8(i64, psOut);
1143 return hRet;
1146 /************************************************************************
1147 * VarI2FromI8 (OLEAUT32.346)
1149 * Convert a VT_I8 to a VT_I2.
1151 * PARAMS
1152 * llIn [I] Source
1153 * psOut [O] Destination
1155 * RETURNS
1156 * Success: S_OK.
1157 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1159 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
1161 return _VarI2FromI8(llIn, psOut);
1164 /************************************************************************
1165 * VarI2FromUI8 (OLEAUT32.347)
1167 * Convert a VT_UI8 to a VT_I2.
1169 * PARAMS
1170 * ullIn [I] Source
1171 * psOut [O] Destination
1173 * RETURNS
1174 * Success: S_OK.
1175 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1177 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
1179 return _VarI2FromUI8(ullIn, psOut);
1182 /* UI2
1185 /************************************************************************
1186 * VarUI2FromUI1 (OLEAUT32.257)
1188 * Convert a VT_UI1 to a VT_UI2.
1190 * PARAMS
1191 * bIn [I] Source
1192 * pusOut [O] Destination
1194 * RETURNS
1195 * S_OK.
1197 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
1199 return _VarUI2FromUI1(bIn, pusOut);
1202 /************************************************************************
1203 * VarUI2FromI2 (OLEAUT32.258)
1205 * Convert a VT_I2 to a VT_UI2.
1207 * PARAMS
1208 * sIn [I] Source
1209 * pusOut [O] Destination
1211 * RETURNS
1212 * Success: S_OK.
1213 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1215 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
1217 return _VarUI2FromI2(sIn, pusOut);
1220 /************************************************************************
1221 * VarUI2FromI4 (OLEAUT32.259)
1223 * Convert a VT_I4 to a VT_UI2.
1225 * PARAMS
1226 * iIn [I] Source
1227 * pusOut [O] Destination
1229 * RETURNS
1230 * Success: S_OK.
1231 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1233 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
1235 return _VarUI2FromI4(iIn, pusOut);
1238 /************************************************************************
1239 * VarUI2FromR4 (OLEAUT32.260)
1241 * Convert a VT_R4 to a VT_UI2.
1243 * PARAMS
1244 * fltIn [I] Source
1245 * pusOut [O] Destination
1247 * RETURNS
1248 * Success: S_OK.
1249 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1251 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
1253 return VarUI2FromR8(fltIn, pusOut);
1256 /************************************************************************
1257 * VarUI2FromR8 (OLEAUT32.261)
1259 * Convert a VT_R8 to a VT_UI2.
1261 * PARAMS
1262 * dblIn [I] Source
1263 * pusOut [O] Destination
1265 * RETURNS
1266 * Success: S_OK.
1267 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1269 * NOTES
1270 * See VarI8FromR8() for details concerning rounding.
1272 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
1274 if (dblIn < -0.5 || dblIn > (double)UI2_MAX)
1275 return DISP_E_OVERFLOW;
1276 VARIANT_DutchRound(USHORT, dblIn, *pusOut);
1277 return S_OK;
1280 /************************************************************************
1281 * VarUI2FromDate (OLEAUT32.262)
1283 * Convert a VT_DATE to a VT_UI2.
1285 * PARAMS
1286 * dateIn [I] Source
1287 * pusOut [O] Destination
1289 * RETURNS
1290 * Success: S_OK.
1291 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1293 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
1295 return VarUI2FromR8(dateIn, pusOut);
1298 /************************************************************************
1299 * VarUI2FromCy (OLEAUT32.263)
1301 * Convert a VT_CY to a VT_UI2.
1303 * PARAMS
1304 * cyIn [I] Source
1305 * pusOut [O] Destination
1307 * RETURNS
1308 * Success: S_OK.
1309 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1311 * NOTES
1312 * Negative values >= -5000 will be converted to 0.
1314 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
1316 ULONG i = UI2_MAX + 1;
1318 VarUI4FromCy(cyIn, &i);
1319 return _VarUI2FromUI4(i, pusOut);
1322 /************************************************************************
1323 * VarUI2FromStr (OLEAUT32.264)
1325 * Convert a VT_BSTR to a VT_UI2.
1327 * PARAMS
1328 * strIn [I] Source
1329 * lcid [I] LCID for the conversion
1330 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1331 * pusOut [O] Destination
1333 * RETURNS
1334 * Success: S_OK.
1335 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1336 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1338 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
1340 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
1343 /************************************************************************
1344 * VarUI2FromDisp (OLEAUT32.265)
1346 * Convert a VT_DISPATCH to a VT_UI2.
1348 * PARAMS
1349 * pdispIn [I] Source
1350 * lcid [I] LCID for conversion
1351 * pusOut [O] Destination
1353 * RETURNS
1354 * Success: S_OK.
1355 * Failure: E_INVALIDARG, if the source value is invalid
1356 * DISP_E_OVERFLOW, if the value will not fit in the destination
1357 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1359 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
1361 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0);
1364 /************************************************************************
1365 * VarUI2FromBool (OLEAUT32.266)
1367 * Convert a VT_BOOL to a VT_UI2.
1369 * PARAMS
1370 * boolIn [I] Source
1371 * pusOut [O] Destination
1373 * RETURNS
1374 * S_OK.
1376 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
1378 return _VarUI2FromBool(boolIn, pusOut);
1381 /************************************************************************
1382 * VarUI2FromI1 (OLEAUT32.267)
1384 * Convert a VT_I1 to a VT_UI2.
1386 * PARAMS
1387 * cIn [I] Source
1388 * pusOut [O] Destination
1390 * RETURNS
1391 * Success: S_OK.
1392 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1394 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
1396 return _VarUI2FromI1(cIn, pusOut);
1399 /************************************************************************
1400 * VarUI2FromUI4 (OLEAUT32.268)
1402 * Convert a VT_UI4 to a VT_UI2.
1404 * PARAMS
1405 * ulIn [I] Source
1406 * pusOut [O] Destination
1408 * RETURNS
1409 * Success: S_OK.
1410 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1412 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
1414 return _VarUI2FromUI4(ulIn, pusOut);
1417 /************************************************************************
1418 * VarUI2FromDec (OLEAUT32.269)
1420 * Convert a VT_DECIMAL to a VT_UI2.
1422 * PARAMS
1423 * pDecIn [I] Source
1424 * pusOut [O] Destination
1426 * RETURNS
1427 * Success: S_OK.
1428 * Failure: E_INVALIDARG, if the source value is invalid
1429 * DISP_E_OVERFLOW, if the value will not fit in the destination
1431 HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut)
1433 LONG64 i64;
1434 HRESULT hRet;
1436 hRet = VarI8FromDec(pdecIn, &i64);
1438 if (SUCCEEDED(hRet))
1439 hRet = _VarUI2FromI8(i64, pusOut);
1440 return hRet;
1443 /************************************************************************
1444 * VarUI2FromI8 (OLEAUT32.378)
1446 * Convert a VT_I8 to a VT_UI2.
1448 * PARAMS
1449 * llIn [I] Source
1450 * pusOut [O] Destination
1452 * RETURNS
1453 * Success: S_OK.
1454 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1456 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
1458 return _VarUI2FromI8(llIn, pusOut);
1461 /************************************************************************
1462 * VarUI2FromUI8 (OLEAUT32.379)
1464 * Convert a VT_UI8 to a VT_UI2.
1466 * PARAMS
1467 * ullIn [I] Source
1468 * pusOut [O] Destination
1470 * RETURNS
1471 * Success: S_OK.
1472 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1474 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
1476 return _VarUI2FromUI8(ullIn, pusOut);
1479 /* I4
1482 /************************************************************************
1483 * VarI4FromUI1 (OLEAUT32.58)
1485 * Convert a VT_UI1 to a VT_I4.
1487 * PARAMS
1488 * bIn [I] Source
1489 * piOut [O] Destination
1491 * RETURNS
1492 * S_OK.
1494 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
1496 return _VarI4FromUI1(bIn, piOut);
1499 /************************************************************************
1500 * VarI4FromI2 (OLEAUT32.59)
1502 * Convert a VT_I2 to a VT_I4.
1504 * PARAMS
1505 * sIn [I] Source
1506 * piOut [O] Destination
1508 * RETURNS
1509 * Success: S_OK.
1510 * Failure: E_INVALIDARG, if the source value is invalid
1511 * DISP_E_OVERFLOW, if the value will not fit in the destination
1513 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
1515 return _VarI4FromI2(sIn, piOut);
1518 /************************************************************************
1519 * VarI4FromR4 (OLEAUT32.60)
1521 * Convert a VT_R4 to a VT_I4.
1523 * PARAMS
1524 * fltIn [I] Source
1525 * piOut [O] Destination
1527 * RETURNS
1528 * Success: S_OK.
1529 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1531 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
1533 return VarI4FromR8(fltIn, piOut);
1536 /************************************************************************
1537 * VarI4FromR8 (OLEAUT32.61)
1539 * Convert a VT_R8 to a VT_I4.
1541 * PARAMS
1542 * dblIn [I] Source
1543 * piOut [O] Destination
1545 * RETURNS
1546 * Success: S_OK.
1547 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1549 * NOTES
1550 * See VarI8FromR8() for details concerning rounding.
1552 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
1554 if (dblIn < (double)I4_MIN || dblIn > (double)I4_MAX)
1555 return DISP_E_OVERFLOW;
1556 VARIANT_DutchRound(LONG, dblIn, *piOut);
1557 return S_OK;
1560 /************************************************************************
1561 * VarI4FromCy (OLEAUT32.62)
1563 * Convert a VT_CY to a VT_I4.
1565 * PARAMS
1566 * cyIn [I] Source
1567 * piOut [O] Destination
1569 * RETURNS
1570 * Success: S_OK.
1571 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1573 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
1575 double d = cyIn.int64 / CY_MULTIPLIER_F;
1576 return VarI4FromR8(d, piOut);
1579 /************************************************************************
1580 * VarI4FromDate (OLEAUT32.63)
1582 * Convert a VT_DATE to a VT_I4.
1584 * PARAMS
1585 * dateIn [I] Source
1586 * piOut [O] Destination
1588 * RETURNS
1589 * Success: S_OK.
1590 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1592 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
1594 return VarI4FromR8(dateIn, piOut);
1597 /************************************************************************
1598 * VarI4FromStr (OLEAUT32.64)
1600 * Convert a VT_BSTR to a VT_I4.
1602 * PARAMS
1603 * strIn [I] Source
1604 * lcid [I] LCID for the conversion
1605 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1606 * piOut [O] Destination
1608 * RETURNS
1609 * Success: S_OK.
1610 * Failure: E_INVALIDARG, if any parameter is invalid
1611 * DISP_E_OVERFLOW, if the value will not fit in the destination
1612 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1614 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
1616 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
1619 /************************************************************************
1620 * VarI4FromDisp (OLEAUT32.65)
1622 * Convert a VT_DISPATCH to a VT_I4.
1624 * PARAMS
1625 * pdispIn [I] Source
1626 * lcid [I] LCID for conversion
1627 * piOut [O] Destination
1629 * RETURNS
1630 * Success: S_OK.
1631 * Failure: E_INVALIDARG, if the source value is invalid
1632 * DISP_E_OVERFLOW, if the value will not fit in the destination
1633 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1635 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
1637 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0);
1640 /************************************************************************
1641 * VarI4FromBool (OLEAUT32.66)
1643 * Convert a VT_BOOL to a VT_I4.
1645 * PARAMS
1646 * boolIn [I] Source
1647 * piOut [O] Destination
1649 * RETURNS
1650 * S_OK.
1652 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
1654 return _VarI4FromBool(boolIn, piOut);
1657 /************************************************************************
1658 * VarI4FromI1 (OLEAUT32.209)
1660 * Convert a VT_I4 to a VT_I4.
1662 * PARAMS
1663 * cIn [I] Source
1664 * piOut [O] Destination
1666 * RETURNS
1667 * S_OK.
1669 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
1671 return _VarI4FromI1(cIn, piOut);
1674 /************************************************************************
1675 * VarI4FromUI2 (OLEAUT32.210)
1677 * Convert a VT_UI2 to a VT_I4.
1679 * PARAMS
1680 * usIn [I] Source
1681 * piOut [O] Destination
1683 * RETURNS
1684 * S_OK.
1686 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
1688 return _VarI4FromUI2(usIn, piOut);
1691 /************************************************************************
1692 * VarI4FromUI4 (OLEAUT32.211)
1694 * Convert a VT_UI4 to a VT_I4.
1696 * PARAMS
1697 * ulIn [I] Source
1698 * piOut [O] Destination
1700 * RETURNS
1701 * Success: S_OK.
1702 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1704 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
1706 return _VarI4FromUI4(ulIn, piOut);
1709 /************************************************************************
1710 * VarI4FromDec (OLEAUT32.212)
1712 * Convert a VT_DECIMAL to a VT_I4.
1714 * PARAMS
1715 * pDecIn [I] Source
1716 * piOut [O] Destination
1718 * RETURNS
1719 * Success: S_OK.
1720 * Failure: E_INVALIDARG, if pdecIn is invalid
1721 * DISP_E_OVERFLOW, if the value will not fit in the destination
1723 HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut)
1725 LONG64 i64;
1726 HRESULT hRet;
1728 hRet = VarI8FromDec(pdecIn, &i64);
1730 if (SUCCEEDED(hRet))
1731 hRet = _VarI4FromI8(i64, piOut);
1732 return hRet;
1735 /************************************************************************
1736 * VarI4FromI8 (OLEAUT32.348)
1738 * Convert a VT_I8 to a VT_I4.
1740 * PARAMS
1741 * llIn [I] Source
1742 * piOut [O] Destination
1744 * RETURNS
1745 * Success: S_OK.
1746 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1748 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
1750 return _VarI4FromI8(llIn, piOut);
1753 /************************************************************************
1754 * VarI4FromUI8 (OLEAUT32.349)
1756 * Convert a VT_UI8 to a VT_I4.
1758 * PARAMS
1759 * ullIn [I] Source
1760 * piOut [O] Destination
1762 * RETURNS
1763 * Success: S_OK.
1764 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1766 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
1768 return _VarI4FromUI8(ullIn, piOut);
1771 /* UI4
1774 /************************************************************************
1775 * VarUI4FromUI1 (OLEAUT32.270)
1777 * Convert a VT_UI1 to a VT_UI4.
1779 * PARAMS
1780 * bIn [I] Source
1781 * pulOut [O] Destination
1783 * RETURNS
1784 * S_OK.
1786 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
1788 return _VarUI4FromUI1(bIn, pulOut);
1791 /************************************************************************
1792 * VarUI4FromI2 (OLEAUT32.271)
1794 * Convert a VT_I2 to a VT_UI4.
1796 * PARAMS
1797 * sIn [I] Source
1798 * pulOut [O] Destination
1800 * RETURNS
1801 * Success: S_OK.
1802 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1804 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
1806 return _VarUI4FromI2(sIn, pulOut);
1809 /************************************************************************
1810 * VarUI4FromI4 (OLEAUT32.272)
1812 * Convert a VT_I4 to a VT_UI4.
1814 * PARAMS
1815 * iIn [I] Source
1816 * pulOut [O] Destination
1818 * RETURNS
1819 * Success: S_OK.
1820 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1822 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
1824 return _VarUI4FromI4(iIn, pulOut);
1827 /************************************************************************
1828 * VarUI4FromR4 (OLEAUT32.273)
1830 * Convert a VT_R4 to a VT_UI4.
1832 * PARAMS
1833 * fltIn [I] Source
1834 * pulOut [O] Destination
1836 * RETURNS
1837 * Success: S_OK.
1838 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1840 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
1842 return VarUI4FromR8(fltIn, pulOut);
1845 /************************************************************************
1846 * VarUI4FromR8 (OLEAUT32.274)
1848 * Convert a VT_R8 to a VT_UI4.
1850 * PARAMS
1851 * dblIn [I] Source
1852 * pulOut [O] Destination
1854 * RETURNS
1855 * Success: S_OK.
1856 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1858 * NOTES
1859 * See VarI8FromR8() for details concerning rounding.
1861 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
1863 if (dblIn < -0.5 || dblIn > (double)UI4_MAX)
1864 return DISP_E_OVERFLOW;
1865 VARIANT_DutchRound(ULONG, dblIn, *pulOut);
1866 return S_OK;
1869 /************************************************************************
1870 * VarUI4FromDate (OLEAUT32.275)
1872 * Convert a VT_DATE to a VT_UI4.
1874 * PARAMS
1875 * dateIn [I] Source
1876 * pulOut [O] Destination
1878 * RETURNS
1879 * Success: S_OK.
1880 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1882 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
1884 return VarUI4FromR8(dateIn, pulOut);
1887 /************************************************************************
1888 * VarUI4FromCy (OLEAUT32.276)
1890 * Convert a VT_CY to a VT_UI4.
1892 * PARAMS
1893 * cyIn [I] Source
1894 * pulOut [O] Destination
1896 * RETURNS
1897 * Success: S_OK.
1898 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1900 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
1902 double d = cyIn.int64 / CY_MULTIPLIER_F;
1903 return VarUI4FromR8(d, pulOut);
1906 /************************************************************************
1907 * VarUI4FromStr (OLEAUT32.277)
1909 * Convert a VT_BSTR to a VT_UI4.
1911 * PARAMS
1912 * strIn [I] Source
1913 * lcid [I] LCID for the conversion
1914 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1915 * pulOut [O] Destination
1917 * RETURNS
1918 * Success: S_OK.
1919 * Failure: E_INVALIDARG, if any parameter is invalid
1920 * DISP_E_OVERFLOW, if the value will not fit in the destination
1921 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1923 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
1925 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
1928 /************************************************************************
1929 * VarUI4FromDisp (OLEAUT32.278)
1931 * Convert a VT_DISPATCH to a VT_UI4.
1933 * PARAMS
1934 * pdispIn [I] Source
1935 * lcid [I] LCID for conversion
1936 * pulOut [O] Destination
1938 * RETURNS
1939 * Success: S_OK.
1940 * Failure: E_INVALIDARG, if the source value is invalid
1941 * DISP_E_OVERFLOW, if the value will not fit in the destination
1942 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1944 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
1946 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0);
1949 /************************************************************************
1950 * VarUI4FromBool (OLEAUT32.279)
1952 * Convert a VT_BOOL to a VT_UI4.
1954 * PARAMS
1955 * boolIn [I] Source
1956 * pulOut [O] Destination
1958 * RETURNS
1959 * S_OK.
1961 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
1963 return _VarUI4FromBool(boolIn, pulOut);
1966 /************************************************************************
1967 * VarUI4FromI1 (OLEAUT32.280)
1969 * Convert a VT_I1 to a VT_UI4.
1971 * PARAMS
1972 * cIn [I] Source
1973 * pulOut [O] Destination
1975 * RETURNS
1976 * Success: S_OK.
1977 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1979 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
1981 return _VarUI4FromI1(cIn, pulOut);
1984 /************************************************************************
1985 * VarUI4FromUI2 (OLEAUT32.281)
1987 * Convert a VT_UI2 to a VT_UI4.
1989 * PARAMS
1990 * usIn [I] Source
1991 * pulOut [O] Destination
1993 * RETURNS
1994 * S_OK.
1996 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
1998 return _VarUI4FromUI2(usIn, pulOut);
2001 /************************************************************************
2002 * VarUI4FromDec (OLEAUT32.282)
2004 * Convert a VT_DECIMAL to a VT_UI4.
2006 * PARAMS
2007 * pDecIn [I] Source
2008 * pulOut [O] Destination
2010 * RETURNS
2011 * Success: S_OK.
2012 * Failure: E_INVALIDARG, if pdecIn is invalid
2013 * DISP_E_OVERFLOW, if the value will not fit in the destination
2015 HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut)
2017 LONG64 i64;
2018 HRESULT hRet;
2020 hRet = VarI8FromDec(pdecIn, &i64);
2022 if (SUCCEEDED(hRet))
2023 hRet = _VarUI4FromI8(i64, pulOut);
2024 return hRet;
2027 /************************************************************************
2028 * VarUI4FromI8 (OLEAUT32.425)
2030 * Convert a VT_I8 to a VT_UI4.
2032 * PARAMS
2033 * llIn [I] Source
2034 * pulOut [O] Destination
2036 * RETURNS
2037 * Success: S_OK.
2038 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2040 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
2042 return _VarUI4FromI8(llIn, pulOut);
2045 /************************************************************************
2046 * VarUI4FromUI8 (OLEAUT32.426)
2048 * Convert a VT_UI8 to a VT_UI4.
2050 * PARAMS
2051 * ullIn [I] Source
2052 * pulOut [O] Destination
2054 * RETURNS
2055 * Success: S_OK.
2056 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2058 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
2060 return _VarUI4FromUI8(ullIn, pulOut);
2063 /* I8
2066 /************************************************************************
2067 * VarI8FromUI1 (OLEAUT32.333)
2069 * Convert a VT_UI1 to a VT_I8.
2071 * PARAMS
2072 * bIn [I] Source
2073 * pi64Out [O] Destination
2075 * RETURNS
2076 * S_OK.
2078 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
2080 return _VarI8FromUI1(bIn, pi64Out);
2084 /************************************************************************
2085 * VarI8FromI2 (OLEAUT32.334)
2087 * Convert a VT_I2 to a VT_I8.
2089 * PARAMS
2090 * sIn [I] Source
2091 * pi64Out [O] Destination
2093 * RETURNS
2094 * S_OK.
2096 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
2098 return _VarI8FromI2(sIn, pi64Out);
2101 /************************************************************************
2102 * VarI8FromR4 (OLEAUT32.335)
2104 * Convert a VT_R4 to a VT_I8.
2106 * PARAMS
2107 * fltIn [I] Source
2108 * pi64Out [O] Destination
2110 * RETURNS
2111 * Success: S_OK.
2112 * Failure: E_INVALIDARG, if the source value is invalid
2113 * DISP_E_OVERFLOW, if the value will not fit in the destination
2115 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
2117 return VarI8FromR8(fltIn, pi64Out);
2120 /************************************************************************
2121 * VarI8FromR8 (OLEAUT32.336)
2123 * Convert a VT_R8 to a VT_I8.
2125 * PARAMS
2126 * dblIn [I] Source
2127 * pi64Out [O] Destination
2129 * RETURNS
2130 * Success: S_OK.
2131 * Failure: E_INVALIDARG, if the source value is invalid
2132 * DISP_E_OVERFLOW, if the value will not fit in the destination
2134 * NOTES
2135 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2136 * very high or low values will not be accurately converted.
2138 * Numbers are rounded using Dutch rounding, as follows:
2140 *| Fractional Part Sign Direction Example
2141 *| --------------- ---- --------- -------
2142 *| < 0.5 + Down 0.4 -> 0.0
2143 *| < 0.5 - Up -0.4 -> 0.0
2144 *| > 0.5 + Up 0.6 -> 1.0
2145 *| < 0.5 - Up -0.6 -> -1.0
2146 *| = 0.5 + Up/Down Down if even, Up if odd
2147 *| = 0.5 - Up/Down Up if even, Down if odd
2149 * This system is often used in supermarkets.
2151 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
2153 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
2154 return DISP_E_OVERFLOW;
2155 VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
2156 return S_OK;
2159 /************************************************************************
2160 * VarI8FromCy (OLEAUT32.337)
2162 * Convert a VT_CY to a VT_I8.
2164 * PARAMS
2165 * cyIn [I] Source
2166 * pi64Out [O] Destination
2168 * RETURNS
2169 * S_OK.
2171 * NOTES
2172 * All negative numbers are rounded down by 1, including those that are
2173 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2174 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2175 * for details.
2177 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
2179 *pi64Out = cyIn.int64 / CY_MULTIPLIER;
2181 if (cyIn.int64 < 0)
2182 (*pi64Out)--; /* Mimic Win32 bug */
2183 else
2185 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2187 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1)))
2188 (*pi64Out)++;
2190 return S_OK;
2193 /************************************************************************
2194 * VarI8FromDate (OLEAUT32.338)
2196 * Convert a VT_DATE to a VT_I8.
2198 * PARAMS
2199 * dateIn [I] Source
2200 * pi64Out [O] Destination
2202 * RETURNS
2203 * Success: S_OK.
2204 * Failure: E_INVALIDARG, if the source value is invalid
2205 * DISP_E_OVERFLOW, if the value will not fit in the destination
2206 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2208 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
2210 return VarI8FromR8(dateIn, pi64Out);
2213 /************************************************************************
2214 * VarI8FromStr (OLEAUT32.339)
2216 * Convert a VT_BSTR to a VT_I8.
2218 * PARAMS
2219 * strIn [I] Source
2220 * lcid [I] LCID for the conversion
2221 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2222 * pi64Out [O] Destination
2224 * RETURNS
2225 * Success: S_OK.
2226 * Failure: E_INVALIDARG, if the source value is invalid
2227 * DISP_E_OVERFLOW, if the value will not fit in the destination
2228 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2230 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
2232 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
2235 /************************************************************************
2236 * VarI8FromDisp (OLEAUT32.340)
2238 * Convert a VT_DISPATCH to a VT_I8.
2240 * PARAMS
2241 * pdispIn [I] Source
2242 * lcid [I] LCID for conversion
2243 * pi64Out [O] Destination
2245 * RETURNS
2246 * Success: S_OK.
2247 * Failure: E_INVALIDARG, if the source value is invalid
2248 * DISP_E_OVERFLOW, if the value will not fit in the destination
2249 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2251 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
2253 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0);
2256 /************************************************************************
2257 * VarI8FromBool (OLEAUT32.341)
2259 * Convert a VT_BOOL to a VT_I8.
2261 * PARAMS
2262 * boolIn [I] Source
2263 * pi64Out [O] Destination
2265 * RETURNS
2266 * S_OK.
2268 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
2270 return VarI8FromI2(boolIn, pi64Out);
2273 /************************************************************************
2274 * VarI8FromI1 (OLEAUT32.342)
2276 * Convert a VT_I1 to a VT_I8.
2278 * PARAMS
2279 * cIn [I] Source
2280 * pi64Out [O] Destination
2282 * RETURNS
2283 * S_OK.
2285 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
2287 return _VarI8FromI1(cIn, pi64Out);
2290 /************************************************************************
2291 * VarI8FromUI2 (OLEAUT32.343)
2293 * Convert a VT_UI2 to a VT_I8.
2295 * PARAMS
2296 * usIn [I] Source
2297 * pi64Out [O] Destination
2299 * RETURNS
2300 * S_OK.
2302 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
2304 return _VarI8FromUI2(usIn, pi64Out);
2307 /************************************************************************
2308 * VarI8FromUI4 (OLEAUT32.344)
2310 * Convert a VT_UI4 to a VT_I8.
2312 * PARAMS
2313 * ulIn [I] Source
2314 * pi64Out [O] Destination
2316 * RETURNS
2317 * S_OK.
2319 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
2321 return _VarI8FromUI4(ulIn, pi64Out);
2324 /************************************************************************
2325 * VarI8FromDec (OLEAUT32.345)
2327 * Convert a VT_DECIMAL to a VT_I8.
2329 * PARAMS
2330 * pDecIn [I] Source
2331 * pi64Out [O] Destination
2333 * RETURNS
2334 * Success: S_OK.
2335 * Failure: E_INVALIDARG, if the source value is invalid
2336 * DISP_E_OVERFLOW, if the value will not fit in the destination
2338 HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out)
2340 if (!DEC_SCALE(pdecIn))
2342 /* This decimal is just a 96 bit integer */
2343 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2344 return E_INVALIDARG;
2346 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000)
2347 return DISP_E_OVERFLOW;
2349 if (DEC_SIGN(pdecIn))
2350 *pi64Out = -DEC_LO64(pdecIn);
2351 else
2352 *pi64Out = DEC_LO64(pdecIn);
2353 return S_OK;
2355 else
2357 /* Decimal contains a floating point number */
2358 HRESULT hRet;
2359 double dbl;
2361 hRet = VarR8FromDec(pdecIn, &dbl);
2362 if (SUCCEEDED(hRet))
2363 hRet = VarI8FromR8(dbl, pi64Out);
2364 return hRet;
2368 /************************************************************************
2369 * VarI8FromUI8 (OLEAUT32.427)
2371 * Convert a VT_UI8 to a VT_I8.
2373 * PARAMS
2374 * ullIn [I] Source
2375 * pi64Out [O] Destination
2377 * RETURNS
2378 * Success: S_OK.
2379 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2381 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
2383 return _VarI8FromUI8(ullIn, pi64Out);
2386 /* UI8
2389 /************************************************************************
2390 * VarUI8FromI8 (OLEAUT32.428)
2392 * Convert a VT_I8 to a VT_UI8.
2394 * PARAMS
2395 * ulIn [I] Source
2396 * pui64Out [O] Destination
2398 * RETURNS
2399 * Success: S_OK.
2400 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2402 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
2404 return _VarUI8FromI8(llIn, pui64Out);
2407 /************************************************************************
2408 * VarUI8FromUI1 (OLEAUT32.429)
2410 * Convert a VT_UI1 to a VT_UI8.
2412 * PARAMS
2413 * bIn [I] Source
2414 * pui64Out [O] Destination
2416 * RETURNS
2417 * S_OK.
2419 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
2421 return _VarUI8FromUI1(bIn, pui64Out);
2424 /************************************************************************
2425 * VarUI8FromI2 (OLEAUT32.430)
2427 * Convert a VT_I2 to a VT_UI8.
2429 * PARAMS
2430 * sIn [I] Source
2431 * pui64Out [O] Destination
2433 * RETURNS
2434 * S_OK.
2436 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
2438 return _VarUI8FromI2(sIn, pui64Out);
2441 /************************************************************************
2442 * VarUI8FromR4 (OLEAUT32.431)
2444 * Convert a VT_R4 to a VT_UI8.
2446 * PARAMS
2447 * fltIn [I] Source
2448 * pui64Out [O] Destination
2450 * RETURNS
2451 * Success: S_OK.
2452 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2454 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
2456 return VarUI8FromR8(fltIn, pui64Out);
2459 /************************************************************************
2460 * VarUI8FromR8 (OLEAUT32.432)
2462 * Convert a VT_R8 to a VT_UI8.
2464 * PARAMS
2465 * dblIn [I] Source
2466 * pui64Out [O] Destination
2468 * RETURNS
2469 * Success: S_OK.
2470 * Failure: E_INVALIDARG, if the source value is invalid
2471 * DISP_E_OVERFLOW, if the value will not fit in the destination
2473 * NOTES
2474 * See VarI8FromR8() for details concerning rounding.
2476 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
2478 if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
2479 return DISP_E_OVERFLOW;
2480 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
2481 return S_OK;
2484 /************************************************************************
2485 * VarUI8FromCy (OLEAUT32.433)
2487 * Convert a VT_CY to a VT_UI8.
2489 * PARAMS
2490 * cyIn [I] Source
2491 * pui64Out [O] Destination
2493 * RETURNS
2494 * Success: S_OK.
2495 * Failure: E_INVALIDARG, if the source value is invalid
2496 * DISP_E_OVERFLOW, if the value will not fit in the destination
2498 * NOTES
2499 * Negative values >= -5000 will be converted to 0.
2501 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
2503 if (cyIn.int64 < 0)
2505 if (cyIn.int64 < -CY_HALF)
2506 return DISP_E_OVERFLOW;
2507 *pui64Out = 0;
2509 else
2511 *pui64Out = cyIn.int64 / CY_MULTIPLIER;
2513 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2515 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1)))
2516 (*pui64Out)++;
2518 return S_OK;
2521 /************************************************************************
2522 * VarUI8FromDate (OLEAUT32.434)
2524 * Convert a VT_DATE to a VT_UI8.
2526 * PARAMS
2527 * dateIn [I] Source
2528 * pui64Out [O] Destination
2530 * RETURNS
2531 * Success: S_OK.
2532 * Failure: E_INVALIDARG, if the source value is invalid
2533 * DISP_E_OVERFLOW, if the value will not fit in the destination
2534 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2536 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
2538 return VarUI8FromR8(dateIn, pui64Out);
2541 /************************************************************************
2542 * VarUI8FromStr (OLEAUT32.435)
2544 * Convert a VT_BSTR to a VT_UI8.
2546 * PARAMS
2547 * strIn [I] Source
2548 * lcid [I] LCID for the conversion
2549 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2550 * pui64Out [O] Destination
2552 * RETURNS
2553 * Success: S_OK.
2554 * Failure: E_INVALIDARG, if the source value is invalid
2555 * DISP_E_OVERFLOW, if the value will not fit in the destination
2556 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2558 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
2560 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
2563 /************************************************************************
2564 * VarUI8FromDisp (OLEAUT32.436)
2566 * Convert a VT_DISPATCH to a VT_UI8.
2568 * PARAMS
2569 * pdispIn [I] Source
2570 * lcid [I] LCID for conversion
2571 * pui64Out [O] Destination
2573 * RETURNS
2574 * Success: S_OK.
2575 * Failure: E_INVALIDARG, if the source value is invalid
2576 * DISP_E_OVERFLOW, if the value will not fit in the destination
2577 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2579 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
2581 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0);
2584 /************************************************************************
2585 * VarUI8FromBool (OLEAUT32.437)
2587 * Convert a VT_BOOL to a VT_UI8.
2589 * PARAMS
2590 * boolIn [I] Source
2591 * pui64Out [O] Destination
2593 * RETURNS
2594 * Success: S_OK.
2595 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2597 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
2599 return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
2601 /************************************************************************
2602 * VarUI8FromI1 (OLEAUT32.438)
2604 * Convert a VT_I1 to a VT_UI8.
2606 * PARAMS
2607 * cIn [I] Source
2608 * pui64Out [O] Destination
2610 * RETURNS
2611 * Success: S_OK.
2612 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2614 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
2616 return _VarUI8FromI1(cIn, pui64Out);
2619 /************************************************************************
2620 * VarUI8FromUI2 (OLEAUT32.439)
2622 * Convert a VT_UI2 to a VT_UI8.
2624 * PARAMS
2625 * usIn [I] Source
2626 * pui64Out [O] Destination
2628 * RETURNS
2629 * S_OK.
2631 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
2633 return _VarUI8FromUI2(usIn, pui64Out);
2636 /************************************************************************
2637 * VarUI8FromUI4 (OLEAUT32.440)
2639 * Convert a VT_UI4 to a VT_UI8.
2641 * PARAMS
2642 * ulIn [I] Source
2643 * pui64Out [O] Destination
2645 * RETURNS
2646 * S_OK.
2648 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
2650 return _VarUI8FromUI4(ulIn, pui64Out);
2653 /************************************************************************
2654 * VarUI8FromDec (OLEAUT32.441)
2656 * Convert a VT_DECIMAL to a VT_UI8.
2658 * PARAMS
2659 * pDecIn [I] Source
2660 * pui64Out [O] Destination
2662 * RETURNS
2663 * Success: S_OK.
2664 * Failure: E_INVALIDARG, if the source value is invalid
2665 * DISP_E_OVERFLOW, if the value will not fit in the destination
2667 * NOTES
2668 * Under native Win32, if the source value has a scale of 0, its sign is
2669 * ignored, i.e. this function takes the absolute value rather than fail
2670 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2671 * (use VarAbs() on pDecIn first if you really want this behaviour).
2673 HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out)
2675 if (!DEC_SCALE(pdecIn))
2677 /* This decimal is just a 96 bit integer */
2678 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2679 return E_INVALIDARG;
2681 if (DEC_HI32(pdecIn))
2682 return DISP_E_OVERFLOW;
2684 if (DEC_SIGN(pdecIn))
2686 WARN("Sign would be ignored under Win32!\n");
2687 return DISP_E_OVERFLOW;
2690 *pui64Out = DEC_LO64(pdecIn);
2691 return S_OK;
2693 else
2695 /* Decimal contains a floating point number */
2696 HRESULT hRet;
2697 double dbl;
2699 hRet = VarR8FromDec(pdecIn, &dbl);
2700 if (SUCCEEDED(hRet))
2701 hRet = VarUI8FromR8(dbl, pui64Out);
2702 return hRet;
2706 /* R4
2709 /************************************************************************
2710 * VarR4FromUI1 (OLEAUT32.68)
2712 * Convert a VT_UI1 to a VT_R4.
2714 * PARAMS
2715 * bIn [I] Source
2716 * pFltOut [O] Destination
2718 * RETURNS
2719 * S_OK.
2721 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
2723 return _VarR4FromUI1(bIn, pFltOut);
2726 /************************************************************************
2727 * VarR4FromI2 (OLEAUT32.69)
2729 * Convert a VT_I2 to a VT_R4.
2731 * PARAMS
2732 * sIn [I] Source
2733 * pFltOut [O] Destination
2735 * RETURNS
2736 * S_OK.
2738 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
2740 return _VarR4FromI2(sIn, pFltOut);
2743 /************************************************************************
2744 * VarR4FromI4 (OLEAUT32.70)
2746 * Convert a VT_I4 to a VT_R4.
2748 * PARAMS
2749 * sIn [I] Source
2750 * pFltOut [O] Destination
2752 * RETURNS
2753 * S_OK.
2755 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
2757 return _VarR4FromI4(lIn, pFltOut);
2760 /************************************************************************
2761 * VarR4FromR8 (OLEAUT32.71)
2763 * Convert a VT_R8 to a VT_R4.
2765 * PARAMS
2766 * dblIn [I] Source
2767 * pFltOut [O] Destination
2769 * RETURNS
2770 * Success: S_OK.
2771 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2773 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
2775 double d = dblIn < 0.0 ? -dblIn : dblIn;
2776 if (d > R4_MAX) return DISP_E_OVERFLOW;
2777 *pFltOut = dblIn;
2778 return S_OK;
2781 /************************************************************************
2782 * VarR4FromCy (OLEAUT32.72)
2784 * Convert a VT_CY to a VT_R4.
2786 * PARAMS
2787 * cyIn [I] Source
2788 * pFltOut [O] Destination
2790 * RETURNS
2791 * S_OK.
2793 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
2795 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
2796 return S_OK;
2799 /************************************************************************
2800 * VarR4FromDate (OLEAUT32.73)
2802 * Convert a VT_DATE to a VT_R4.
2804 * PARAMS
2805 * dateIn [I] Source
2806 * pFltOut [O] Destination
2808 * RETURNS
2809 * Success: S_OK.
2810 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2812 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
2814 return VarR4FromR8(dateIn, pFltOut);
2817 /************************************************************************
2818 * VarR4FromStr (OLEAUT32.74)
2820 * Convert a VT_BSTR to a VT_R4.
2822 * PARAMS
2823 * strIn [I] Source
2824 * lcid [I] LCID for the conversion
2825 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2826 * pFltOut [O] Destination
2828 * RETURNS
2829 * Success: S_OK.
2830 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2831 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2833 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
2835 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
2838 /************************************************************************
2839 * VarR4FromDisp (OLEAUT32.75)
2841 * Convert a VT_DISPATCH to a VT_R4.
2843 * PARAMS
2844 * pdispIn [I] Source
2845 * lcid [I] LCID for conversion
2846 * pFltOut [O] Destination
2848 * RETURNS
2849 * Success: S_OK.
2850 * Failure: E_INVALIDARG, if the source value is invalid
2851 * DISP_E_OVERFLOW, if the value will not fit in the destination
2852 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2854 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
2856 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0);
2859 /************************************************************************
2860 * VarR4FromBool (OLEAUT32.76)
2862 * Convert a VT_BOOL to a VT_R4.
2864 * PARAMS
2865 * boolIn [I] Source
2866 * pFltOut [O] Destination
2868 * RETURNS
2869 * S_OK.
2871 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2873 return VarR4FromI2(boolIn, pFltOut);
2876 /************************************************************************
2877 * VarR4FromI1 (OLEAUT32.213)
2879 * Convert a VT_I1 to a VT_R4.
2881 * PARAMS
2882 * cIn [I] Source
2883 * pFltOut [O] Destination
2885 * RETURNS
2886 * Success: S_OK.
2887 * Failure: E_INVALIDARG, if the source value is invalid
2888 * DISP_E_OVERFLOW, if the value will not fit in the destination
2889 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2891 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2893 return _VarR4FromI1(cIn, pFltOut);
2896 /************************************************************************
2897 * VarR4FromUI2 (OLEAUT32.214)
2899 * Convert a VT_UI2 to a VT_R4.
2901 * PARAMS
2902 * usIn [I] Source
2903 * pFltOut [O] Destination
2905 * RETURNS
2906 * Success: S_OK.
2907 * Failure: E_INVALIDARG, if the source value is invalid
2908 * DISP_E_OVERFLOW, if the value will not fit in the destination
2909 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2911 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2913 return _VarR4FromUI2(usIn, pFltOut);
2916 /************************************************************************
2917 * VarR4FromUI4 (OLEAUT32.215)
2919 * Convert a VT_UI4 to a VT_R4.
2921 * PARAMS
2922 * ulIn [I] Source
2923 * pFltOut [O] Destination
2925 * RETURNS
2926 * Success: S_OK.
2927 * Failure: E_INVALIDARG, if the source value is invalid
2928 * DISP_E_OVERFLOW, if the value will not fit in the destination
2929 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2931 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2933 return _VarR4FromUI4(ulIn, pFltOut);
2936 /************************************************************************
2937 * VarR4FromDec (OLEAUT32.216)
2939 * Convert a VT_DECIMAL to a VT_R4.
2941 * PARAMS
2942 * pDecIn [I] Source
2943 * pFltOut [O] Destination
2945 * RETURNS
2946 * Success: S_OK.
2947 * Failure: E_INVALIDARG, if the source value is invalid.
2949 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
2951 BYTE scale = DEC_SCALE(pDecIn);
2952 int divisor = 1;
2953 double highPart;
2955 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2956 return E_INVALIDARG;
2958 while (scale--)
2959 divisor *= 10;
2961 if (DEC_SIGN(pDecIn))
2962 divisor = -divisor;
2964 if (DEC_HI32(pDecIn))
2966 highPart = (double)DEC_HI32(pDecIn) / (double)divisor;
2967 highPart *= 4294967296.0F;
2968 highPart *= 4294967296.0F;
2970 else
2971 highPart = 0.0;
2973 *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart;
2974 return S_OK;
2977 /************************************************************************
2978 * VarR4FromI8 (OLEAUT32.360)
2980 * Convert a VT_I8 to a VT_R4.
2982 * PARAMS
2983 * ullIn [I] Source
2984 * pFltOut [O] Destination
2986 * RETURNS
2987 * S_OK.
2989 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2991 return _VarR4FromI8(llIn, pFltOut);
2994 /************************************************************************
2995 * VarR4FromUI8 (OLEAUT32.361)
2997 * Convert a VT_UI8 to a VT_R4.
2999 * PARAMS
3000 * ullIn [I] Source
3001 * pFltOut [O] Destination
3003 * RETURNS
3004 * S_OK.
3006 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
3008 return _VarR4FromUI8(ullIn, pFltOut);
3011 /************************************************************************
3012 * VarR4CmpR8 (OLEAUT32.316)
3014 * Compare a VT_R4 to a VT_R8.
3016 * PARAMS
3017 * fltLeft [I] Source
3018 * dblRight [I] Value to compare
3020 * RETURNS
3021 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3022 * equal to or greater than dblRight respectively.
3024 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3026 if (fltLeft < dblRight)
3027 return VARCMP_LT;
3028 else if (fltLeft > dblRight)
3029 return VARCMP_GT;
3030 return VARCMP_EQ;
3033 /* R8
3036 /************************************************************************
3037 * VarR8FromUI1 (OLEAUT32.78)
3039 * Convert a VT_UI1 to a VT_R8.
3041 * PARAMS
3042 * bIn [I] Source
3043 * pDblOut [O] Destination
3045 * RETURNS
3046 * S_OK.
3048 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3050 return _VarR8FromUI1(bIn, pDblOut);
3053 /************************************************************************
3054 * VarR8FromI2 (OLEAUT32.79)
3056 * Convert a VT_I2 to a VT_R8.
3058 * PARAMS
3059 * sIn [I] Source
3060 * pDblOut [O] Destination
3062 * RETURNS
3063 * S_OK.
3065 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3067 return _VarR8FromI2(sIn, pDblOut);
3070 /************************************************************************
3071 * VarR8FromI4 (OLEAUT32.80)
3073 * Convert a VT_I4 to a VT_R8.
3075 * PARAMS
3076 * sIn [I] Source
3077 * pDblOut [O] Destination
3079 * RETURNS
3080 * S_OK.
3082 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3084 return _VarR8FromI4(lIn, pDblOut);
3087 /************************************************************************
3088 * VarR8FromR4 (OLEAUT32.81)
3090 * Convert a VT_R4 to a VT_R8.
3092 * PARAMS
3093 * fltIn [I] Source
3094 * pDblOut [O] Destination
3096 * RETURNS
3097 * S_OK.
3099 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3101 return _VarR8FromR4(fltIn, pDblOut);
3104 /************************************************************************
3105 * VarR8FromCy (OLEAUT32.82)
3107 * Convert a VT_CY to a VT_R8.
3109 * PARAMS
3110 * cyIn [I] Source
3111 * pDblOut [O] Destination
3113 * RETURNS
3114 * S_OK.
3116 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3118 return _VarR8FromCy(cyIn, pDblOut);
3121 /************************************************************************
3122 * VarR8FromDate (OLEAUT32.83)
3124 * Convert a VT_DATE to a VT_R8.
3126 * PARAMS
3127 * dateIn [I] Source
3128 * pDblOut [O] Destination
3130 * RETURNS
3131 * S_OK.
3133 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3135 return _VarR8FromDate(dateIn, pDblOut);
3138 /************************************************************************
3139 * VarR8FromStr (OLEAUT32.84)
3141 * Convert a VT_BSTR to a VT_R8.
3143 * PARAMS
3144 * strIn [I] Source
3145 * lcid [I] LCID for the conversion
3146 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3147 * pDblOut [O] Destination
3149 * RETURNS
3150 * Success: S_OK.
3151 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3152 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3154 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3156 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3159 /************************************************************************
3160 * VarR8FromDisp (OLEAUT32.85)
3162 * Convert a VT_DISPATCH to a VT_R8.
3164 * PARAMS
3165 * pdispIn [I] Source
3166 * lcid [I] LCID for conversion
3167 * pDblOut [O] Destination
3169 * RETURNS
3170 * Success: S_OK.
3171 * Failure: E_INVALIDARG, if the source value is invalid
3172 * DISP_E_OVERFLOW, if the value will not fit in the destination
3173 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3175 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3177 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0);
3180 /************************************************************************
3181 * VarR8FromBool (OLEAUT32.86)
3183 * Convert a VT_BOOL to a VT_R8.
3185 * PARAMS
3186 * boolIn [I] Source
3187 * pDblOut [O] Destination
3189 * RETURNS
3190 * S_OK.
3192 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3194 return VarR8FromI2(boolIn, pDblOut);
3197 /************************************************************************
3198 * VarR8FromI1 (OLEAUT32.217)
3200 * Convert a VT_I1 to a VT_R8.
3202 * PARAMS
3203 * cIn [I] Source
3204 * pDblOut [O] Destination
3206 * RETURNS
3207 * Success: S_OK.
3208 * Failure: E_INVALIDARG, if the source value is invalid
3209 * DISP_E_OVERFLOW, if the value will not fit in the destination
3210 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3212 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3214 return _VarR8FromI1(cIn, pDblOut);
3217 /************************************************************************
3218 * VarR8FromUI2 (OLEAUT32.218)
3220 * Convert a VT_UI2 to a VT_R8.
3222 * PARAMS
3223 * usIn [I] Source
3224 * pDblOut [O] Destination
3226 * RETURNS
3227 * Success: S_OK.
3228 * Failure: E_INVALIDARG, if the source value is invalid
3229 * DISP_E_OVERFLOW, if the value will not fit in the destination
3230 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3232 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3234 return _VarR8FromUI2(usIn, pDblOut);
3237 /************************************************************************
3238 * VarR8FromUI4 (OLEAUT32.219)
3240 * Convert a VT_UI4 to a VT_R8.
3242 * PARAMS
3243 * ulIn [I] Source
3244 * pDblOut [O] Destination
3246 * RETURNS
3247 * Success: S_OK.
3248 * Failure: E_INVALIDARG, if the source value is invalid
3249 * DISP_E_OVERFLOW, if the value will not fit in the destination
3250 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3252 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3254 return _VarR8FromUI4(ulIn, pDblOut);
3257 /************************************************************************
3258 * VarR8FromDec (OLEAUT32.220)
3260 * Convert a VT_DECIMAL to a VT_R8.
3262 * PARAMS
3263 * pDecIn [I] Source
3264 * pDblOut [O] Destination
3266 * RETURNS
3267 * Success: S_OK.
3268 * Failure: E_INVALIDARG, if the source value is invalid.
3270 HRESULT WINAPI VarR8FromDec(DECIMAL* pDecIn, double *pDblOut)
3272 BYTE scale = DEC_SCALE(pDecIn);
3273 double divisor = 1.0, highPart;
3275 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3276 return E_INVALIDARG;
3278 while (scale--)
3279 divisor *= 10;
3281 if (DEC_SIGN(pDecIn))
3282 divisor = -divisor;
3284 if (DEC_HI32(pDecIn))
3286 highPart = (double)DEC_HI32(pDecIn) / divisor;
3287 highPart *= 4294967296.0F;
3288 highPart *= 4294967296.0F;
3290 else
3291 highPart = 0.0;
3293 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3294 return S_OK;
3297 /************************************************************************
3298 * VarR8FromI8 (OLEAUT32.362)
3300 * Convert a VT_I8 to a VT_R8.
3302 * PARAMS
3303 * ullIn [I] Source
3304 * pDblOut [O] Destination
3306 * RETURNS
3307 * S_OK.
3309 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3311 return _VarR8FromI8(llIn, pDblOut);
3314 /************************************************************************
3315 * VarR8FromUI8 (OLEAUT32.363)
3317 * Convert a VT_UI8 to a VT_R8.
3319 * PARAMS
3320 * ullIn [I] Source
3321 * pDblOut [O] Destination
3323 * RETURNS
3324 * S_OK.
3326 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3328 return _VarR8FromUI8(ullIn, pDblOut);
3331 /************************************************************************
3332 * VarR8Pow (OLEAUT32.315)
3334 * Raise a VT_R8 to a power.
3336 * PARAMS
3337 * dblLeft [I] Source
3338 * dblPow [I] Power to raise dblLeft by
3339 * pDblOut [O] Destination
3341 * RETURNS
3342 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3344 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3346 *pDblOut = pow(dblLeft, dblPow);
3347 return S_OK;
3350 /************************************************************************
3351 * VarR8Round (OLEAUT32.317)
3353 * Round a VT_R8 to a given number of decimal points.
3355 * PARAMS
3356 * dblIn [I] Source
3357 * nDig [I] Number of decimal points to round to
3358 * pDblOut [O] Destination for rounded number
3360 * RETURNS
3361 * Success: S_OK. pDblOut is rounded to nDig digits.
3362 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3364 * NOTES
3365 * The native version of this function rounds using the internal
3366 * binary representation of the number. Wine uses the dutch rounding
3367 * convention, so therefore small differences can occur in the value returned.
3368 * MSDN says that you should use your own rounding function if you want
3369 * rounding to be predictable in your application.
3371 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3373 double scale, whole, fract;
3375 if (nDig < 0)
3376 return E_INVALIDARG;
3378 scale = pow(10.0, nDig);
3380 dblIn *= scale;
3381 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3382 fract = dblIn - whole;
3384 if (fract > 0.5)
3385 dblIn = whole + 1.0;
3386 else if (fract == 0.5)
3387 dblIn = whole + fmod(whole, 2.0);
3388 else if (fract >= 0.0)
3389 dblIn = whole;
3390 else if (fract == -0.5)
3391 dblIn = whole - fmod(whole, 2.0);
3392 else if (fract > -0.5)
3393 dblIn = whole;
3394 else
3395 dblIn = whole - 1.0;
3397 *pDblOut = dblIn / scale;
3398 return S_OK;
3401 /* CY
3404 /* Powers of 10 from 0..4 D.P. */
3405 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3406 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3408 /************************************************************************
3409 * VarCyFromUI1 (OLEAUT32.98)
3411 * Convert a VT_UI1 to a VT_CY.
3413 * PARAMS
3414 * bIn [I] Source
3415 * pCyOut [O] Destination
3417 * RETURNS
3418 * Success: S_OK.
3419 * Failure: E_INVALIDARG, if the source value is invalid
3420 * DISP_E_OVERFLOW, if the value will not fit in the destination
3421 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3423 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3425 return VarCyFromR8(bIn, pCyOut);
3428 /************************************************************************
3429 * VarCyFromI2 (OLEAUT32.99)
3431 * Convert a VT_I2 to a VT_CY.
3433 * PARAMS
3434 * sIn [I] Source
3435 * pCyOut [O] Destination
3437 * RETURNS
3438 * Success: S_OK.
3439 * Failure: E_INVALIDARG, if the source value is invalid
3440 * DISP_E_OVERFLOW, if the value will not fit in the destination
3441 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3443 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3445 return VarCyFromR8(sIn, pCyOut);
3448 /************************************************************************
3449 * VarCyFromI4 (OLEAUT32.100)
3451 * Convert a VT_I4 to a VT_CY.
3453 * PARAMS
3454 * sIn [I] Source
3455 * pCyOut [O] Destination
3457 * RETURNS
3458 * Success: S_OK.
3459 * Failure: E_INVALIDARG, if the source value is invalid
3460 * DISP_E_OVERFLOW, if the value will not fit in the destination
3461 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3463 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3465 return VarCyFromR8(lIn, pCyOut);
3468 /************************************************************************
3469 * VarCyFromR4 (OLEAUT32.101)
3471 * Convert a VT_R4 to a VT_CY.
3473 * PARAMS
3474 * fltIn [I] Source
3475 * pCyOut [O] Destination
3477 * RETURNS
3478 * Success: S_OK.
3479 * Failure: E_INVALIDARG, if the source value is invalid
3480 * DISP_E_OVERFLOW, if the value will not fit in the destination
3481 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3483 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3485 return VarCyFromR8(fltIn, pCyOut);
3488 /************************************************************************
3489 * VarCyFromR8 (OLEAUT32.102)
3491 * Convert a VT_R8 to a VT_CY.
3493 * PARAMS
3494 * dblIn [I] Source
3495 * pCyOut [O] Destination
3497 * RETURNS
3498 * Success: S_OK.
3499 * Failure: E_INVALIDARG, if the source value is invalid
3500 * DISP_E_OVERFLOW, if the value will not fit in the destination
3501 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3503 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3505 #if defined(__GNUC__) && defined(__i386__)
3506 /* This code gives identical results to Win32 on Intel.
3507 * Here we use fp exceptions to catch overflows when storing the value.
3509 static const unsigned short r8_fpcontrol = 0x137f;
3510 static const double r8_multiplier = CY_MULTIPLIER_F;
3511 unsigned short old_fpcontrol, result_fpstatus;
3513 /* Clear exceptions, save the old fp state and load the new state */
3514 __asm__ __volatile__( "fnclex" );
3515 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3516 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3517 /* Perform the conversion. */
3518 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3519 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3520 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3521 /* Save the resulting fp state, load the old state and clear exceptions */
3522 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3523 __asm__ __volatile__( "fnclex" );
3524 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3526 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3527 return DISP_E_OVERFLOW;
3528 return S_OK;
3529 #else
3530 /* This version produces slightly different results for boundary cases */
3531 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3532 return DISP_E_OVERFLOW;
3533 dblIn *= CY_MULTIPLIER_F;
3534 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3535 #endif
3536 return S_OK;
3539 /************************************************************************
3540 * VarCyFromDate (OLEAUT32.103)
3542 * Convert a VT_DATE to a VT_CY.
3544 * PARAMS
3545 * dateIn [I] Source
3546 * pCyOut [O] Destination
3548 * RETURNS
3549 * Success: S_OK.
3550 * Failure: E_INVALIDARG, if the source value is invalid
3551 * DISP_E_OVERFLOW, if the value will not fit in the destination
3552 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3554 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3556 return VarCyFromR8(dateIn, pCyOut);
3559 /************************************************************************
3560 * VarCyFromStr (OLEAUT32.104)
3562 * Convert a VT_BSTR to a VT_CY.
3564 * PARAMS
3565 * strIn [I] Source
3566 * lcid [I] LCID for the conversion
3567 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3568 * pCyOut [O] Destination
3570 * RETURNS
3571 * Success: S_OK.
3572 * Failure: E_INVALIDARG, if the source value is invalid
3573 * DISP_E_OVERFLOW, if the value will not fit in the destination
3574 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3576 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3578 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3581 /************************************************************************
3582 * VarCyFromDisp (OLEAUT32.105)
3584 * Convert a VT_DISPATCH to a VT_CY.
3586 * PARAMS
3587 * pdispIn [I] Source
3588 * lcid [I] LCID for conversion
3589 * pCyOut [O] Destination
3591 * RETURNS
3592 * Success: S_OK.
3593 * Failure: E_INVALIDARG, if the source value is invalid
3594 * DISP_E_OVERFLOW, if the value will not fit in the destination
3595 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3597 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3599 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0);
3602 /************************************************************************
3603 * VarCyFromBool (OLEAUT32.106)
3605 * Convert a VT_BOOL to a VT_CY.
3607 * PARAMS
3608 * boolIn [I] Source
3609 * pCyOut [O] Destination
3611 * RETURNS
3612 * Success: S_OK.
3613 * Failure: E_INVALIDARG, if the source value is invalid
3614 * DISP_E_OVERFLOW, if the value will not fit in the destination
3615 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3617 * NOTES
3618 * While the sign of the boolean is stored in the currency, the value is
3619 * converted to either 0 or 1.
3621 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3623 return VarCyFromR8(boolIn, pCyOut);
3626 /************************************************************************
3627 * VarCyFromI1 (OLEAUT32.225)
3629 * Convert a VT_I1 to a VT_CY.
3631 * PARAMS
3632 * cIn [I] Source
3633 * pCyOut [O] Destination
3635 * RETURNS
3636 * Success: S_OK.
3637 * Failure: E_INVALIDARG, if the source value is invalid
3638 * DISP_E_OVERFLOW, if the value will not fit in the destination
3639 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3641 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3643 return VarCyFromR8(cIn, pCyOut);
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 return VarCyFromR8(usIn, pCyOut);
3666 /************************************************************************
3667 * VarCyFromUI4 (OLEAUT32.227)
3669 * Convert a VT_UI4 to a VT_CY.
3671 * PARAMS
3672 * ulIn [I] Source
3673 * pCyOut [O] Destination
3675 * RETURNS
3676 * Success: S_OK.
3677 * Failure: E_INVALIDARG, if the source value is invalid
3678 * DISP_E_OVERFLOW, if the value will not fit in the destination
3679 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3681 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3683 return VarCyFromR8(ulIn, pCyOut);
3686 /************************************************************************
3687 * VarCyFromDec (OLEAUT32.228)
3689 * Convert a VT_DECIMAL to a VT_CY.
3691 * PARAMS
3692 * pdecIn [I] Source
3693 * pCyOut [O] Destination
3695 * RETURNS
3696 * Success: S_OK.
3697 * Failure: E_INVALIDARG, if the source value is invalid
3698 * DISP_E_OVERFLOW, if the value will not fit in the destination
3699 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3701 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
3703 DECIMAL rounded;
3704 HRESULT hRet;
3706 hRet = VarDecRound(pdecIn, 4, &rounded);
3708 if (SUCCEEDED(hRet))
3710 double d;
3712 if (DEC_HI32(&rounded))
3713 return DISP_E_OVERFLOW;
3715 /* Note: Without the casts this promotes to int64 which loses precision */
3716 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3717 if (DEC_SIGN(&rounded))
3718 d = -d;
3719 return VarCyFromR8(d, pCyOut);
3721 return hRet;
3724 /************************************************************************
3725 * VarCyFromI8 (OLEAUT32.366)
3727 * Convert a VT_I8 to a VT_CY.
3729 * PARAMS
3730 * ullIn [I] Source
3731 * pCyOut [O] Destination
3733 * RETURNS
3734 * Success: S_OK.
3735 * Failure: E_INVALIDARG, if the source value is invalid
3736 * DISP_E_OVERFLOW, if the value will not fit in the destination
3737 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3739 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3741 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3742 pCyOut->int64 = llIn * CY_MULTIPLIER;
3743 return S_OK;
3746 /************************************************************************
3747 * VarCyFromUI8 (OLEAUT32.375)
3749 * Convert a VT_UI8 to a VT_CY.
3751 * PARAMS
3752 * ullIn [I] Source
3753 * pCyOut [O] Destination
3755 * RETURNS
3756 * Success: S_OK.
3757 * Failure: E_INVALIDARG, if the source value is invalid
3758 * DISP_E_OVERFLOW, if the value will not fit in the destination
3759 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3761 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3763 return VarCyFromR8(ullIn, pCyOut);
3766 /************************************************************************
3767 * VarCyAdd (OLEAUT32.299)
3769 * Add one CY to another.
3771 * PARAMS
3772 * cyLeft [I] Source
3773 * cyRight [I] Value to add
3774 * pCyOut [O] Destination
3776 * RETURNS
3777 * Success: S_OK.
3778 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3780 HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut)
3782 double l,r;
3783 _VarR8FromCy(cyLeft, &l);
3784 _VarR8FromCy(cyRight, &r);
3785 l = l + r;
3786 return VarCyFromR8(l, pCyOut);
3789 /************************************************************************
3790 * VarCyMul (OLEAUT32.303)
3792 * Multiply one CY by another.
3794 * PARAMS
3795 * cyLeft [I] Source
3796 * cyRight [I] Value to multiply by
3797 * pCyOut [O] Destination
3799 * RETURNS
3800 * Success: S_OK.
3801 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3803 HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut)
3805 double l,r;
3806 _VarR8FromCy(cyLeft, &l);
3807 _VarR8FromCy(cyRight, &r);
3808 l = l * r;
3809 return VarCyFromR8(l, pCyOut);
3812 /************************************************************************
3813 * VarCyMulI4 (OLEAUT32.304)
3815 * Multiply one CY by a VT_I4.
3817 * PARAMS
3818 * cyLeft [I] Source
3819 * lRight [I] Value to multiply by
3820 * pCyOut [O] Destination
3822 * RETURNS
3823 * Success: S_OK.
3824 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3826 HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut)
3828 double d;
3830 _VarR8FromCy(cyLeft, &d);
3831 d = d * lRight;
3832 return VarCyFromR8(d, pCyOut);
3835 /************************************************************************
3836 * VarCySub (OLEAUT32.305)
3838 * Subtract one CY from another.
3840 * PARAMS
3841 * cyLeft [I] Source
3842 * cyRight [I] Value to subtract
3843 * pCyOut [O] Destination
3845 * RETURNS
3846 * Success: S_OK.
3847 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3849 HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut)
3851 double l,r;
3852 _VarR8FromCy(cyLeft, &l);
3853 _VarR8FromCy(cyRight, &r);
3854 l = l - r;
3855 return VarCyFromR8(l, pCyOut);
3858 /************************************************************************
3859 * VarCyAbs (OLEAUT32.306)
3861 * Convert a VT_CY into its absolute value.
3863 * PARAMS
3864 * cyIn [I] Source
3865 * pCyOut [O] Destination
3867 * RETURNS
3868 * Success: S_OK. pCyOut contains the absolute value.
3869 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3871 HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut)
3873 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3874 return DISP_E_OVERFLOW;
3876 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3877 return S_OK;
3880 /************************************************************************
3881 * VarCyFix (OLEAUT32.307)
3883 * Return the integer part of a VT_CY.
3885 * PARAMS
3886 * cyIn [I] Source
3887 * pCyOut [O] Destination
3889 * RETURNS
3890 * Success: S_OK.
3891 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3893 * NOTES
3894 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3895 * negative numbers away from 0, while this function rounds them towards zero.
3897 HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut)
3899 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3900 pCyOut->int64 *= CY_MULTIPLIER;
3901 return S_OK;
3904 /************************************************************************
3905 * VarCyInt (OLEAUT32.308)
3907 * Return the integer part of a VT_CY.
3909 * PARAMS
3910 * cyIn [I] Source
3911 * pCyOut [O] Destination
3913 * RETURNS
3914 * Success: S_OK.
3915 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3917 * NOTES
3918 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3919 * negative numbers towards 0, while this function rounds them away from zero.
3921 HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut)
3923 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3924 pCyOut->int64 *= CY_MULTIPLIER;
3926 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3928 pCyOut->int64 -= CY_MULTIPLIER;
3930 return S_OK;
3933 /************************************************************************
3934 * VarCyNeg (OLEAUT32.309)
3936 * Change the sign of a VT_CY.
3938 * PARAMS
3939 * cyIn [I] Source
3940 * pCyOut [O] Destination
3942 * RETURNS
3943 * Success: S_OK.
3944 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3946 HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut)
3948 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3949 return DISP_E_OVERFLOW;
3951 pCyOut->int64 = -cyIn.int64;
3952 return S_OK;
3955 /************************************************************************
3956 * VarCyRound (OLEAUT32.310)
3958 * Change the precision of a VT_CY.
3960 * PARAMS
3961 * cyIn [I] Source
3962 * cDecimals [I] New number of decimals to keep
3963 * pCyOut [O] Destination
3965 * RETURNS
3966 * Success: S_OK.
3967 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3969 HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
3971 if (cDecimals < 0)
3972 return E_INVALIDARG;
3974 if (cDecimals > 3)
3976 /* Rounding to more precision than we have */
3977 *pCyOut = cyIn;
3978 return S_OK;
3980 else
3982 double d, div = CY_Divisors[cDecimals];
3984 _VarR8FromCy(cyIn, &d);
3985 d = d * div;
3986 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3987 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3988 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3989 return S_OK;
3993 /************************************************************************
3994 * VarCyCmp (OLEAUT32.311)
3996 * Compare two VT_CY values.
3998 * PARAMS
3999 * cyLeft [I] Source
4000 * cyRight [I] Value to compare
4002 * RETURNS
4003 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4004 * compare is less, equal or greater than source respectively.
4005 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4007 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
4009 HRESULT hRet;
4010 CY result;
4012 /* Subtract right from left, and compare the result to 0 */
4013 hRet = VarCySub(cyLeft, cyRight, &result);
4015 if (SUCCEEDED(hRet))
4017 if (result.int64 < 0)
4018 hRet = (HRESULT)VARCMP_LT;
4019 else if (result.int64 > 0)
4020 hRet = (HRESULT)VARCMP_GT;
4021 else
4022 hRet = (HRESULT)VARCMP_EQ;
4024 return hRet;
4027 /************************************************************************
4028 * VarCyCmpR8 (OLEAUT32.312)
4030 * Compare a VT_CY to a double
4032 * PARAMS
4033 * cyLeft [I] Currency Source
4034 * dblRight [I] double to compare to cyLeft
4036 * RETURNS
4037 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4038 * less than, equal to or greater than cyLeft respectively.
4039 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4041 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight)
4043 HRESULT hRet;
4044 CY cyRight;
4046 hRet = VarCyFromR8(dblRight, &cyRight);
4048 if (SUCCEEDED(hRet))
4049 hRet = VarCyCmp(cyLeft, cyRight);
4051 return hRet;
4054 /************************************************************************
4055 * VarCyMulI8 (OLEAUT32.329)
4057 * Multiply a VT_CY by a VT_I8.
4059 * PARAMS
4060 * cyLeft [I] Source
4061 * llRight [I] Value to multiply by
4062 * pCyOut [O] Destination
4064 * RETURNS
4065 * Success: S_OK.
4066 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4068 HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
4070 double d;
4072 _VarR8FromCy(cyLeft, &d);
4073 d = d * (double)llRight;
4074 return VarCyFromR8(d, pCyOut);
4077 /* DECIMAL
4080 /************************************************************************
4081 * VarDecFromUI1 (OLEAUT32.190)
4083 * Convert a VT_UI1 to a DECIMAL.
4085 * PARAMS
4086 * bIn [I] Source
4087 * pDecOut [O] Destination
4089 * RETURNS
4090 * S_OK.
4092 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4094 return VarDecFromUI4(bIn, pDecOut);
4097 /************************************************************************
4098 * VarDecFromI2 (OLEAUT32.191)
4100 * Convert a VT_I2 to a DECIMAL.
4102 * PARAMS
4103 * sIn [I] Source
4104 * pDecOut [O] Destination
4106 * RETURNS
4107 * S_OK.
4109 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4111 return VarDecFromI4(sIn, pDecOut);
4114 /************************************************************************
4115 * VarDecFromI4 (OLEAUT32.192)
4117 * Convert a VT_I4 to a DECIMAL.
4119 * PARAMS
4120 * sIn [I] Source
4121 * pDecOut [O] Destination
4123 * RETURNS
4124 * S_OK.
4126 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4128 DEC_HI32(pDecOut) = 0;
4129 DEC_MID32(pDecOut) = 0;
4131 if (lIn < 0)
4133 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4134 DEC_LO32(pDecOut) = -lIn;
4136 else
4138 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4139 DEC_LO32(pDecOut) = lIn;
4141 return S_OK;
4144 #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT))
4146 /************************************************************************
4147 * VarDecFromR4 (OLEAUT32.193)
4149 * Convert a VT_R4 to a DECIMAL.
4151 * PARAMS
4152 * fltIn [I] Source
4153 * pDecOut [O] Destination
4155 * RETURNS
4156 * S_OK.
4158 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4160 WCHAR buff[256];
4162 sprintfW( buff, szFloatFormatW, fltIn );
4163 return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut);
4166 /************************************************************************
4167 * VarDecFromR8 (OLEAUT32.194)
4169 * Convert a VT_R8 to a DECIMAL.
4171 * PARAMS
4172 * dblIn [I] Source
4173 * pDecOut [O] Destination
4175 * RETURNS
4176 * S_OK.
4178 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4180 WCHAR buff[256];
4182 sprintfW( buff, szDoubleFormatW, dblIn );
4183 return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut);
4186 /************************************************************************
4187 * VarDecFromDate (OLEAUT32.195)
4189 * Convert a VT_DATE to a DECIMAL.
4191 * PARAMS
4192 * dateIn [I] Source
4193 * pDecOut [O] Destination
4195 * RETURNS
4196 * S_OK.
4198 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4200 return VarDecFromR8(dateIn, pDecOut);
4203 /************************************************************************
4204 * VarDecFromCy (OLEAUT32.196)
4206 * Convert a VT_CY to a DECIMAL.
4208 * PARAMS
4209 * cyIn [I] Source
4210 * pDecOut [O] Destination
4212 * RETURNS
4213 * S_OK.
4215 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4217 DEC_HI32(pDecOut) = 0;
4219 /* Note: This assumes 2s complement integer representation */
4220 if (cyIn.s.Hi & 0x80000000)
4222 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4223 DEC_LO64(pDecOut) = -cyIn.int64;
4225 else
4227 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4228 DEC_MID32(pDecOut) = cyIn.s.Hi;
4229 DEC_LO32(pDecOut) = cyIn.s.Lo;
4231 return S_OK;
4234 /************************************************************************
4235 * VarDecFromStr (OLEAUT32.197)
4237 * Convert a VT_BSTR to a DECIMAL.
4239 * PARAMS
4240 * strIn [I] Source
4241 * lcid [I] LCID for the conversion
4242 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4243 * pDecOut [O] Destination
4245 * RETURNS
4246 * Success: S_OK.
4247 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4249 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4251 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4254 /************************************************************************
4255 * VarDecFromDisp (OLEAUT32.198)
4257 * Convert a VT_DISPATCH to a DECIMAL.
4259 * PARAMS
4260 * pdispIn [I] Source
4261 * lcid [I] LCID for conversion
4262 * pDecOut [O] Destination
4264 * RETURNS
4265 * Success: S_OK.
4266 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4268 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4270 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0);
4273 /************************************************************************
4274 * VarDecFromBool (OLEAUT32.199)
4276 * Convert a VT_BOOL to a DECIMAL.
4278 * PARAMS
4279 * bIn [I] Source
4280 * pDecOut [O] Destination
4282 * RETURNS
4283 * S_OK.
4285 * NOTES
4286 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4288 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4290 DEC_HI32(pDecOut) = 0;
4291 DEC_MID32(pDecOut) = 0;
4292 if (bIn)
4294 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4295 DEC_LO32(pDecOut) = 1;
4297 else
4299 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4300 DEC_LO32(pDecOut) = 0;
4302 return S_OK;
4305 /************************************************************************
4306 * VarDecFromI1 (OLEAUT32.241)
4308 * Convert a VT_I1 to a DECIMAL.
4310 * PARAMS
4311 * cIn [I] Source
4312 * pDecOut [O] Destination
4314 * RETURNS
4315 * S_OK.
4317 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4319 return VarDecFromI4(cIn, pDecOut);
4322 /************************************************************************
4323 * VarDecFromUI2 (OLEAUT32.242)
4325 * Convert a VT_UI2 to a DECIMAL.
4327 * PARAMS
4328 * usIn [I] Source
4329 * pDecOut [O] Destination
4331 * RETURNS
4332 * S_OK.
4334 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4336 return VarDecFromUI4(usIn, pDecOut);
4339 /************************************************************************
4340 * VarDecFromUI4 (OLEAUT32.243)
4342 * Convert a VT_UI4 to a DECIMAL.
4344 * PARAMS
4345 * ulIn [I] Source
4346 * pDecOut [O] Destination
4348 * RETURNS
4349 * S_OK.
4351 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4353 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4354 DEC_HI32(pDecOut) = 0;
4355 DEC_MID32(pDecOut) = 0;
4356 DEC_LO32(pDecOut) = ulIn;
4357 return S_OK;
4360 /************************************************************************
4361 * VarDecFromI8 (OLEAUT32.374)
4363 * Convert a VT_I8 to a DECIMAL.
4365 * PARAMS
4366 * llIn [I] Source
4367 * pDecOut [O] Destination
4369 * RETURNS
4370 * S_OK.
4372 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4374 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4376 DEC_HI32(pDecOut) = 0;
4378 /* Note: This assumes 2s complement integer representation */
4379 if (pLi->u.HighPart & 0x80000000)
4381 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4382 DEC_LO64(pDecOut) = -pLi->QuadPart;
4384 else
4386 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4387 DEC_MID32(pDecOut) = pLi->u.HighPart;
4388 DEC_LO32(pDecOut) = pLi->u.LowPart;
4390 return S_OK;
4393 /************************************************************************
4394 * VarDecFromUI8 (OLEAUT32.375)
4396 * Convert a VT_UI8 to a DECIMAL.
4398 * PARAMS
4399 * ullIn [I] Source
4400 * pDecOut [O] Destination
4402 * RETURNS
4403 * S_OK.
4405 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4407 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4408 DEC_HI32(pDecOut) = 0;
4409 DEC_LO64(pDecOut) = ullIn;
4410 return S_OK;
4413 /* Make two DECIMALS the same scale; used by math functions below */
4414 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4415 const DECIMAL** ppDecRight,
4416 DECIMAL* pDecOut)
4418 static DECIMAL scaleFactor;
4419 DECIMAL decTemp;
4420 int scaleAmount, i;
4421 HRESULT hRet = S_OK;
4423 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4424 return E_INVALIDARG;
4426 DEC_LO32(&scaleFactor) = 10;
4428 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4430 if (!scaleAmount)
4431 return S_OK; /* Same scale */
4433 if (scaleAmount > 0)
4435 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4436 *ppDecRight = pDecOut;
4438 else
4440 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4441 *ppDecLeft = pDecOut;
4442 i = scaleAmount = -scaleAmount;
4445 if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE)
4446 return DISP_E_OVERFLOW; /* Can't scale up */
4448 /* Multiply up the value to be scaled by the correct amount */
4449 while (SUCCEEDED(hRet) && i--)
4451 /* Note we are multiplying by a value with a scale of 0, so we don't recurse */
4452 hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut);
4453 decTemp = *pDecOut;
4455 DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */
4456 return hRet;
4459 /* Add two unsigned 32 bit values with overflow */
4460 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4462 ULARGE_INTEGER ul64;
4464 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4465 *pulHigh = ul64.u.HighPart;
4466 return ul64.u.LowPart;
4469 /* Subtract two unsigned 32 bit values with underflow */
4470 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4472 int invert = 0;
4473 ULARGE_INTEGER ul64;
4475 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4476 if (ulLeft < ulRight)
4477 invert = 1;
4479 if (ul64.QuadPart > (ULONG64)*pulHigh)
4480 ul64.QuadPart -= (ULONG64)*pulHigh;
4481 else
4483 ul64.QuadPart -= (ULONG64)*pulHigh;
4484 invert = 1;
4486 if (invert)
4487 ul64.u.HighPart = -ul64.u.HighPart ;
4489 *pulHigh = ul64.u.HighPart;
4490 return ul64.u.LowPart;
4493 /* Multiply two unsigned 32 bit values with overflow */
4494 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4496 ULARGE_INTEGER ul64;
4498 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4499 *pulHigh = ul64.u.HighPart;
4500 return ul64.u.LowPart;
4503 /* Compare two decimals that have the same scale */
4504 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4506 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4507 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4508 return -1;
4509 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4510 return 0;
4511 return 1;
4514 /************************************************************************
4515 * VarDecAdd (OLEAUT32.177)
4517 * Add one DECIMAL to another.
4519 * PARAMS
4520 * pDecLeft [I] Source
4521 * pDecRight [I] Value to add
4522 * pDecOut [O] Destination
4524 * RETURNS
4525 * Success: S_OK.
4526 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4528 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4530 HRESULT hRet;
4531 DECIMAL scaled;
4533 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled);
4535 if (SUCCEEDED(hRet))
4537 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4538 ULONG overflow = 0;
4539 BYTE sign = DECIMAL_POS;
4541 /* Correct for the sign of the result */
4542 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4544 /* -x + -y : Negative */
4545 sign = DECIMAL_NEG;
4546 goto VarDecAdd_AsPositive;
4548 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4550 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4552 /* -x + y : Negative if x > y */
4553 if (cmp > 0)
4555 sign = DECIMAL_NEG;
4556 VarDecAdd_AsNegative:
4557 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4558 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4559 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4561 else
4563 VarDecAdd_AsInvertedNegative:
4564 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4565 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4566 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4569 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4571 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4573 /* x + -y : Negative if x <= y */
4574 if (cmp <= 0)
4576 sign = DECIMAL_NEG;
4577 goto VarDecAdd_AsInvertedNegative;
4579 goto VarDecAdd_AsNegative;
4581 else
4583 /* x + y : Positive */
4584 VarDecAdd_AsPositive:
4585 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4586 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4587 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4590 if (overflow)
4591 return DISP_E_OVERFLOW; /* overflowed */
4593 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4594 DEC_SIGN(pDecOut) = sign;
4596 return hRet;
4599 /* internal representation of the value stored in a DECIMAL. The bytes are
4600 stored from LSB at index 0 to MSB at index 11
4602 typedef struct DECIMAL_internal
4604 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4605 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4606 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4607 } VARIANT_DI;
4609 /* translate from external DECIMAL format into an internal representation */
4610 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4612 to->scale = DEC_SCALE(from);
4613 to->sign = DEC_SIGN(from) ? 1 : 0;
4615 to->bitsnum[0] = DEC_LO32(from);
4616 to->bitsnum[1] = DEC_MID32(from);
4617 to->bitsnum[2] = DEC_HI32(from);
4620 static void VARIANT_DecFromDI(VARIANT_DI * from, DECIMAL * to)
4622 if (from->sign) {
4623 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4624 } else {
4625 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4628 DEC_LO32(to) = from->bitsnum[0];
4629 DEC_MID32(to) = from->bitsnum[1];
4630 DEC_HI32(to) = from->bitsnum[2];
4633 /* clear an internal representation of a DECIMAL */
4634 static void VARIANT_DI_clear(VARIANT_DI * i)
4636 memset(i, 0, sizeof(VARIANT_DI));
4639 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4640 size is supported. The value in p is replaced by the quotient of the division, and
4641 the remainder is returned as a result. This routine is most often used with a divisor
4642 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4644 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4646 if (divisor == 0) {
4647 /* division by 0 */
4648 return 0xFF;
4649 } else if (divisor == 1) {
4650 /* dividend remains unchanged */
4651 return 0;
4652 } else {
4653 unsigned char remainder = 0;
4654 ULONGLONG iTempDividend;
4655 signed int i;
4657 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4658 for (; i >= 0; i--) {
4659 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4660 remainder = iTempDividend % divisor;
4661 p[i] = iTempDividend / divisor;
4664 return remainder;
4668 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4669 static int VARIANT_int_iszero(DWORD * p, unsigned int n)
4671 for (; n > 0; n--) if (*p++ != 0) return 0;
4672 return 1;
4675 /* multiply two DECIMALS, without changing either one, and place result in third
4676 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4677 digits when scale > 0 in order to fit an overflowing result. Final overflow
4678 flag is returned.
4680 static int VARIANT_DI_mul(VARIANT_DI * a, VARIANT_DI * b, VARIANT_DI * result)
4682 int r_overflow = 0;
4683 DWORD running[6];
4684 signed int mulstart;
4686 VARIANT_DI_clear(result);
4687 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4689 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4690 of the result is formed by adding the scales of the operands.
4692 result->scale = a->scale + b->scale;
4693 memset(running, 0, sizeof(running));
4695 /* count number of leading zero-bytes in operand A */
4696 for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4697 if (mulstart < 0) {
4698 /* result is 0, because operand A is 0 */
4699 result->scale = 0;
4700 result->sign = 0;
4701 } else {
4702 unsigned char remainder = 0;
4703 int iA;
4705 /* perform actual multiplication */
4706 for (iA = 0; iA <= mulstart; iA++) {
4707 ULONG iOverflowMul;
4708 int iB;
4710 for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
4711 ULONG iRV;
4712 int iR;
4714 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4715 iR = iA + iB;
4716 do {
4717 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4718 iR++;
4719 } while (iRV);
4723 /* Too bad - native oleaut does not do this, so we should not either */
4724 #if 0
4725 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4726 This operation should not lose significant digits, and gives an
4727 opportunity to reduce the possibility of overflows in future
4728 operations issued by the application.
4730 while (result->scale > 0) {
4731 memcpy(quotient, running, sizeof(quotient));
4732 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4733 if (remainder > 0) break;
4734 memcpy(running, quotient, sizeof(quotient));
4735 result->scale--;
4737 #endif
4738 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4739 This operation *will* lose significant digits of the result because
4740 all the factors of 10 were consumed by the previous operation.
4742 while (result->scale > 0 && !VARIANT_int_iszero(
4743 running + sizeof(result->bitsnum) / sizeof(DWORD),
4744 (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
4746 remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
4747 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4748 result->scale--;
4751 /* round up the result - native oleaut32 does this */
4752 if (remainder >= 5) {
4753 unsigned int i;
4754 for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
4755 ULONGLONG digit = running[i] + 1;
4756 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4757 running[i] = digit & 0xFFFFFFFF;
4761 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4762 and copy result bits into result structure
4764 r_overflow = !VARIANT_int_iszero(
4765 running + sizeof(result->bitsnum)/sizeof(DWORD),
4766 (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
4767 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4769 return r_overflow;
4772 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4773 hardcoded (period for decimal separator, dash as negative sign). Returns 0 for
4774 success, nonzero if insufficient space in output buffer.
4776 static int VARIANT_DI_tostringW(VARIANT_DI * a, WCHAR * s, unsigned int n)
4778 int overflow = 0;
4779 DWORD quotient[3];
4780 unsigned char remainder;
4781 unsigned int i;
4783 /* place negative sign */
4784 if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
4785 if (n > 0) {
4786 *s++ = '-';
4787 n--;
4789 else overflow = 1;
4792 /* prepare initial 0 */
4793 if (!overflow) {
4794 if (n >= 2) {
4795 s[0] = '0';
4796 s[1] = '\0';
4797 } else overflow = 1;
4800 i = 0;
4801 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4802 while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
4803 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4804 if (i + 2 > n) {
4805 overflow = 1;
4806 } else {
4807 s[i++] = '0' + remainder;
4808 s[i] = '\0';
4812 if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
4814 /* reverse order of digits */
4815 WCHAR * x = s; WCHAR * y = s + i - 1;
4816 while (x < y) {
4817 *x ^= *y;
4818 *y ^= *x;
4819 *x++ ^= *y--;
4822 /* check for decimal point. "i" now has string length */
4823 if (i <= a->scale) {
4824 unsigned int numzeroes = a->scale + 1 - i;
4825 if (i + 1 + numzeroes >= n) {
4826 overflow = 1;
4827 } else {
4828 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4829 i += numzeroes;
4830 while (numzeroes > 0) {
4831 s[--numzeroes] = '0';
4836 /* place decimal point */
4837 if (a->scale > 0) {
4838 unsigned int periodpos = i - a->scale;
4839 if (i + 2 >= n) {
4840 overflow = 1;
4841 } else {
4842 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4843 s[periodpos] = '.'; i++;
4845 /* remove extra zeros at the end, if any */
4846 while (s[i - 1] == '0') s[--i] = '\0';
4847 if (s[i - 1] == '.') s[--i] = '\0';
4852 return overflow;
4855 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4856 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4858 DWORD shifted;
4859 unsigned int i;
4861 /* shift whole DWORDs to the left */
4862 while (shift >= 32)
4864 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4865 *p = 0; shift -= 32;
4868 /* shift remainder (1..31 bits) */
4869 shifted = 0;
4870 if (shift > 0) for (i = 0; i < n; i++)
4872 DWORD b;
4873 b = p[i] >> (32 - shift);
4874 p[i] = (p[i] << shift) | shifted;
4875 shifted = b;
4879 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4880 Value at v is incremented by the value at p. Any size is supported, provided
4881 that v is not shorter than p. Any unapplied carry is returned as a result.
4883 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, DWORD * p,
4884 unsigned int np)
4886 unsigned char carry = 0;
4888 if (nv >= np) {
4889 ULONGLONG sum;
4890 unsigned int i;
4892 for (i = 0; i < np; i++) {
4893 sum = (ULONGLONG)v[i]
4894 + (ULONGLONG)p[i]
4895 + (ULONGLONG)carry;
4896 v[i] = sum & 0xffffffff;
4897 carry = sum >> 32;
4899 for (; i < nv && carry; i++) {
4900 sum = (ULONGLONG)v[i]
4901 + (ULONGLONG)carry;
4902 v[i] = sum & 0xffffffff;
4903 carry = sum >> 32;
4906 return carry;
4909 /* perform integral division with operand p as dividend. Parameter n indicates
4910 number of available DWORDs in divisor p, but available space in p must be
4911 actually at least 2 * n DWORDs, because the remainder of the integral
4912 division is built in the next n DWORDs past the start of the quotient. This
4913 routine replaces the dividend in p with the quotient, and appends n
4914 additional DWORDs for the remainder.
4916 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4917 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4918 source code to the VLI (Very Large Integer) division operator. This algorithm
4919 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4920 variably-scaled integers such as the MS DECIMAL representation.
4922 static void VARIANT_int_div(DWORD * p, unsigned int n, DWORD * divisor,
4923 unsigned int dn)
4925 unsigned int i;
4926 DWORD tempsub[8];
4927 DWORD * negdivisor = tempsub + n;
4929 /* build 2s-complement of divisor */
4930 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
4931 p[n] = 1;
4932 VARIANT_int_add(negdivisor, n, p + n, 1);
4933 memset(p + n, 0, n * sizeof(DWORD));
4935 /* skip all leading zero DWORDs in quotient */
4936 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
4937 /* i is now number of DWORDs left to process */
4938 for (i <<= 5; i < (n << 5); i++) {
4939 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
4941 /* trial subtraction */
4942 memcpy(tempsub, p + n, n * sizeof(DWORD));
4943 VARIANT_int_add(tempsub, n, negdivisor, n);
4945 /* check whether result of subtraction was negative */
4946 if ((tempsub[n - 1] & 0x80000000) == 0) {
4947 memcpy(p + n, tempsub, n * sizeof(DWORD));
4948 p[0] |= 1;
4953 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4954 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
4956 unsigned int i;
4957 ULONG iOverflowMul;
4959 for (iOverflowMul = 0, i = 0; i < n; i++)
4960 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
4961 return (unsigned char)iOverflowMul;
4964 /* increment value in A by the value indicated in B, with scale adjusting.
4965 Modifies parameters by adjusting scales. Returns 0 if addition was
4966 successful, nonzero if a parameter underflowed before it could be
4967 successfully used in the addition.
4969 static int VARIANT_int_addlossy(
4970 DWORD * a, int * ascale, unsigned int an,
4971 DWORD * b, int * bscale, unsigned int bn)
4973 int underflow = 0;
4975 if (VARIANT_int_iszero(a, an)) {
4976 /* if A is zero, copy B into A, after removing digits */
4977 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
4978 VARIANT_int_divbychar(b, bn, 10);
4979 (*bscale)--;
4981 memcpy(a, b, an * sizeof(DWORD));
4982 *ascale = *bscale;
4983 } else if (!VARIANT_int_iszero(b, bn)) {
4984 unsigned int tn = an + 1;
4985 DWORD t[5];
4987 if (bn + 1 > tn) tn = bn + 1;
4988 if (*ascale != *bscale) {
4989 /* first (optimistic) try - try to scale down the one with the bigger
4990 scale, while this number is divisible by 10 */
4991 DWORD * digitchosen;
4992 unsigned int nchosen;
4993 int * scalechosen;
4994 int targetscale;
4996 if (*ascale < *bscale) {
4997 targetscale = *ascale;
4998 scalechosen = bscale;
4999 digitchosen = b;
5000 nchosen = bn;
5001 } else {
5002 targetscale = *bscale;
5003 scalechosen = ascale;
5004 digitchosen = a;
5005 nchosen = an;
5007 memset(t, 0, tn * sizeof(DWORD));
5008 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5010 /* divide by 10 until target scale is reached */
5011 while (*scalechosen > targetscale) {
5012 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5013 if (!remainder) {
5014 (*scalechosen)--;
5015 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5016 } else break;
5020 if (*ascale != *bscale) {
5021 DWORD * digitchosen;
5022 unsigned int nchosen;
5023 int * scalechosen;
5024 int targetscale;
5026 /* try to scale up the one with the smaller scale */
5027 if (*ascale > *bscale) {
5028 targetscale = *ascale;
5029 scalechosen = bscale;
5030 digitchosen = b;
5031 nchosen = bn;
5032 } else {
5033 targetscale = *bscale;
5034 scalechosen = ascale;
5035 digitchosen = a;
5036 nchosen = an;
5038 memset(t, 0, tn * sizeof(DWORD));
5039 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5041 /* multiply by 10 until target scale is reached, or
5042 significant bytes overflow the number
5044 while (*scalechosen < targetscale && t[nchosen] == 0) {
5045 VARIANT_int_mulbychar(t, tn, 10);
5046 if (t[nchosen] == 0) {
5047 /* still does not overflow */
5048 (*scalechosen)++;
5049 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5054 if (*ascale != *bscale) {
5055 /* still different? try to scale down the one with the bigger scale
5056 (this *will* lose significant digits) */
5057 DWORD * digitchosen;
5058 unsigned int nchosen;
5059 int * scalechosen;
5060 int targetscale;
5062 if (*ascale < *bscale) {
5063 targetscale = *ascale;
5064 scalechosen = bscale;
5065 digitchosen = b;
5066 nchosen = bn;
5067 } else {
5068 targetscale = *bscale;
5069 scalechosen = ascale;
5070 digitchosen = a;
5071 nchosen = an;
5073 memset(t, 0, tn * sizeof(DWORD));
5074 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5076 /* divide by 10 until target scale is reached */
5077 while (*scalechosen > targetscale) {
5078 VARIANT_int_divbychar(t, tn, 10);
5079 (*scalechosen)--;
5080 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5084 /* check whether any of the operands still has significant digits
5085 (underflow case 1)
5087 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5088 underflow = 1;
5089 } else {
5090 /* at this step, both numbers have the same scale and can be added
5091 as integers. However, the result might not fit in A, so further
5092 scaling down might be necessary.
5094 while (!underflow) {
5095 memset(t, 0, tn * sizeof(DWORD));
5096 memcpy(t, a, an * sizeof(DWORD));
5098 VARIANT_int_add(t, tn, b, bn);
5099 if (VARIANT_int_iszero(t + an, tn - an)) {
5100 /* addition was successful */
5101 memcpy(a, t, an * sizeof(DWORD));
5102 break;
5103 } else {
5104 /* addition overflowed - remove significant digits
5105 from both operands and try again */
5106 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5107 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5108 /* check whether any operand keeps significant digits after
5109 scaledown (underflow case 2)
5111 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5116 return underflow;
5119 /* perform complete DECIMAL division in the internal representation. Returns
5120 0 if the division was completed (even if quotient is set to 0), or nonzero
5121 in case of quotient overflow.
5123 static HRESULT VARIANT_DI_div(VARIANT_DI * dividend, VARIANT_DI * divisor, VARIANT_DI * quotient)
5125 HRESULT r_overflow = S_OK;
5127 if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
5128 /* division by 0 */
5129 r_overflow = DISP_E_DIVBYZERO;
5130 } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
5131 VARIANT_DI_clear(quotient);
5132 } else {
5133 int quotientscale, remainderscale, tempquotientscale;
5134 DWORD remainderplusquotient[8];
5135 int underflow;
5137 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5138 tempquotientscale = quotientscale;
5139 VARIANT_DI_clear(quotient);
5140 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5142 /* The following strategy is used for division
5143 1) if there was a nonzero remainder from previous iteration, use it as
5144 dividend for this iteration, else (for first iteration) use intended
5145 dividend
5146 2) perform integer division in temporary buffer, develop quotient in
5147 low-order part, remainder in high-order part
5148 3) add quotient from step 2 to final result, with possible loss of
5149 significant digits
5150 4) multiply integer part of remainder by 10, while incrementing the
5151 scale of the remainder. This operation preserves the intended value
5152 of the remainder.
5153 5) loop to step 1 until one of the following is true:
5154 a) remainder is zero (exact division achieved)
5155 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5157 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5158 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5159 do {
5160 VARIANT_int_div(
5161 remainderplusquotient, 4,
5162 divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
5163 underflow = VARIANT_int_addlossy(
5164 quotient->bitsnum, &quotientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
5165 remainderplusquotient, &tempquotientscale, 4);
5166 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5167 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5168 tempquotientscale = ++remainderscale;
5169 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5171 /* quotient scale might now be negative (extremely big number). If, so, try
5172 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5173 until scale is 0. If this cannot be done, it is a real overflow.
5175 while (!r_overflow && quotientscale < 0) {
5176 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5177 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5178 VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
5179 if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
5180 (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
5181 quotientscale++;
5182 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5183 } else r_overflow = DISP_E_OVERFLOW;
5185 if (!r_overflow) {
5186 if (quotientscale <= 255) quotient->scale = quotientscale;
5187 else VARIANT_DI_clear(quotient);
5190 return r_overflow;
5193 /************************************************************************
5194 * VarDecDiv (OLEAUT32.178)
5196 * Divide one DECIMAL by another.
5198 * PARAMS
5199 * pDecLeft [I] Source
5200 * pDecRight [I] Value to divide by
5201 * pDecOut [O] Destination
5203 * RETURNS
5204 * Success: S_OK.
5205 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5207 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5209 HRESULT hRet = S_OK;
5210 VARIANT_DI di_left, di_right, di_result;
5211 HRESULT divresult;
5213 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5215 VARIANT_DIFromDec(pDecLeft, &di_left);
5216 VARIANT_DIFromDec(pDecRight, &di_right);
5217 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result);
5218 if (divresult)
5220 /* division actually overflowed */
5221 hRet = divresult;
5223 else
5225 hRet = S_OK;
5227 if (di_result.scale > DEC_MAX_SCALE)
5229 unsigned char remainder = 0;
5231 /* division underflowed. In order to comply with the MSDN
5232 specifications for DECIMAL ranges, some significant digits
5233 must be removed
5235 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5236 di_result.scale);
5237 while (di_result.scale > DEC_MAX_SCALE &&
5238 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
5240 remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
5241 di_result.scale--;
5243 if (di_result.scale > DEC_MAX_SCALE)
5245 WARN("result underflowed, setting to 0\n");
5246 di_result.scale = 0;
5247 di_result.sign = 0;
5249 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5251 unsigned int i;
5252 for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
5253 ULONGLONG digit = di_result.bitsnum[i] + 1;
5254 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5255 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5259 VARIANT_DecFromDI(&di_result, pDecOut);
5261 return hRet;
5264 /************************************************************************
5265 * VarDecMul (OLEAUT32.179)
5267 * Multiply one DECIMAL by another.
5269 * PARAMS
5270 * pDecLeft [I] Source
5271 * pDecRight [I] Value to multiply by
5272 * pDecOut [O] Destination
5274 * RETURNS
5275 * Success: S_OK.
5276 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5278 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5280 HRESULT hRet = S_OK;
5281 VARIANT_DI di_left, di_right, di_result;
5282 int mulresult;
5284 VARIANT_DIFromDec(pDecLeft, &di_left);
5285 VARIANT_DIFromDec(pDecRight, &di_right);
5286 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5287 if (mulresult)
5289 /* multiplication actually overflowed */
5290 hRet = DISP_E_OVERFLOW;
5292 else
5294 if (di_result.scale > DEC_MAX_SCALE)
5296 /* multiplication underflowed. In order to comply with the MSDN
5297 specifications for DECIMAL ranges, some significant digits
5298 must be removed
5300 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5301 di_result.scale);
5302 while (di_result.scale > DEC_MAX_SCALE &&
5303 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
5305 VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
5306 di_result.scale--;
5308 if (di_result.scale > DEC_MAX_SCALE)
5310 WARN("result underflowed, setting to 0\n");
5311 di_result.scale = 0;
5312 di_result.sign = 0;
5315 VARIANT_DecFromDI(&di_result, pDecOut);
5317 return hRet;
5320 /************************************************************************
5321 * VarDecSub (OLEAUT32.181)
5323 * Subtract one DECIMAL from another.
5325 * PARAMS
5326 * pDecLeft [I] Source
5327 * pDecRight [I] DECIMAL to subtract from pDecLeft
5328 * pDecOut [O] Destination
5330 * RETURNS
5331 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5333 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5335 DECIMAL decRight;
5337 /* Implement as addition of the negative */
5338 VarDecNeg(pDecRight, &decRight);
5339 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5342 /************************************************************************
5343 * VarDecAbs (OLEAUT32.182)
5345 * Convert a DECIMAL into its absolute value.
5347 * PARAMS
5348 * pDecIn [I] Source
5349 * pDecOut [O] Destination
5351 * RETURNS
5352 * S_OK. This function does not fail.
5354 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5356 *pDecOut = *pDecIn;
5357 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5358 return S_OK;
5361 /************************************************************************
5362 * VarDecFix (OLEAUT32.187)
5364 * Return the integer portion of a DECIMAL.
5366 * PARAMS
5367 * pDecIn [I] Source
5368 * pDecOut [O] Destination
5370 * RETURNS
5371 * Success: S_OK.
5372 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5374 * NOTES
5375 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5376 * negative numbers away from 0, while this function rounds them towards zero.
5378 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5380 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5381 return E_INVALIDARG;
5383 if (!DEC_SCALE(pDecIn))
5385 *pDecOut = *pDecIn; /* Already an integer */
5386 return S_OK;
5389 FIXME("semi-stub!\n");
5390 return DISP_E_OVERFLOW;
5393 /************************************************************************
5394 * VarDecInt (OLEAUT32.188)
5396 * Return the integer portion of a DECIMAL.
5398 * PARAMS
5399 * pDecIn [I] Source
5400 * pDecOut [O] Destination
5402 * RETURNS
5403 * Success: S_OK.
5404 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5406 * NOTES
5407 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5408 * negative numbers towards 0, while this function rounds them away from zero.
5410 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5412 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5413 return E_INVALIDARG;
5415 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5416 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5418 FIXME("semi-stub!\n");
5419 return DISP_E_OVERFLOW;
5422 /************************************************************************
5423 * VarDecNeg (OLEAUT32.189)
5425 * Change the sign of a DECIMAL.
5427 * PARAMS
5428 * pDecIn [I] Source
5429 * pDecOut [O] Destination
5431 * RETURNS
5432 * S_OK. This function does not fail.
5434 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5436 *pDecOut = *pDecIn;
5437 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5438 return S_OK;
5441 /************************************************************************
5442 * VarDecRound (OLEAUT32.203)
5444 * Change the precision of a DECIMAL.
5446 * PARAMS
5447 * pDecIn [I] Source
5448 * cDecimals [I] New number of decimals to keep
5449 * pDecOut [O] Destination
5451 * RETURNS
5452 * Success: S_OK. pDecOut contains the rounded value.
5453 * Failure: E_INVALIDARG if any argument is invalid.
5455 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5457 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5458 return E_INVALIDARG;
5460 if (cDecimals >= DEC_SCALE(pDecIn))
5462 *pDecOut = *pDecIn; /* More precision than we have */
5463 return S_OK;
5466 FIXME("semi-stub!\n");
5468 return DISP_E_OVERFLOW;
5471 /************************************************************************
5472 * VarDecCmp (OLEAUT32.204)
5474 * Compare two DECIMAL values.
5476 * PARAMS
5477 * pDecLeft [I] Source
5478 * pDecRight [I] Value to compare
5480 * RETURNS
5481 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5482 * is less than, equal to or greater than pDecRight respectively.
5483 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5485 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5487 HRESULT hRet;
5488 DECIMAL result;
5490 /* Subtract right from left, and compare the result to 0 */
5491 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5493 if (SUCCEEDED(hRet))
5495 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5497 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5498 hRet = (HRESULT)VARCMP_LT;
5499 else if (non_zero)
5500 hRet = (HRESULT)VARCMP_GT;
5501 else
5502 hRet = (HRESULT)VARCMP_EQ;
5504 return hRet;
5507 /************************************************************************
5508 * VarDecCmpR8 (OLEAUT32.298)
5510 * Compare a DECIMAL to a double
5512 * PARAMS
5513 * pDecLeft [I] DECIMAL Source
5514 * dblRight [I] double to compare to pDecLeft
5516 * RETURNS
5517 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5518 * is less than, equal to or greater than pDecLeft respectively.
5519 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5521 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5523 HRESULT hRet;
5524 DECIMAL decRight;
5526 hRet = VarDecFromR8(dblRight, &decRight);
5528 if (SUCCEEDED(hRet))
5529 hRet = VarDecCmp(pDecLeft, &decRight);
5531 return hRet;
5534 /* BOOL
5537 /************************************************************************
5538 * VarBoolFromUI1 (OLEAUT32.118)
5540 * Convert a VT_UI1 to a VT_BOOL.
5542 * PARAMS
5543 * bIn [I] Source
5544 * pBoolOut [O] Destination
5546 * RETURNS
5547 * S_OK.
5549 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5551 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5552 return S_OK;
5555 /************************************************************************
5556 * VarBoolFromI2 (OLEAUT32.119)
5558 * Convert a VT_I2 to a VT_BOOL.
5560 * PARAMS
5561 * sIn [I] Source
5562 * pBoolOut [O] Destination
5564 * RETURNS
5565 * S_OK.
5567 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5569 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5570 return S_OK;
5573 /************************************************************************
5574 * VarBoolFromI4 (OLEAUT32.120)
5576 * Convert a VT_I4 to a VT_BOOL.
5578 * PARAMS
5579 * sIn [I] Source
5580 * pBoolOut [O] Destination
5582 * RETURNS
5583 * S_OK.
5585 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
5587 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
5588 return S_OK;
5591 /************************************************************************
5592 * VarBoolFromR4 (OLEAUT32.121)
5594 * Convert a VT_R4 to a VT_BOOL.
5596 * PARAMS
5597 * fltIn [I] Source
5598 * pBoolOut [O] Destination
5600 * RETURNS
5601 * S_OK.
5603 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
5605 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
5606 return S_OK;
5609 /************************************************************************
5610 * VarBoolFromR8 (OLEAUT32.122)
5612 * Convert a VT_R8 to a VT_BOOL.
5614 * PARAMS
5615 * dblIn [I] Source
5616 * pBoolOut [O] Destination
5618 * RETURNS
5619 * S_OK.
5621 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
5623 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
5624 return S_OK;
5627 /************************************************************************
5628 * VarBoolFromDate (OLEAUT32.123)
5630 * Convert a VT_DATE to a VT_BOOL.
5632 * PARAMS
5633 * dateIn [I] Source
5634 * pBoolOut [O] Destination
5636 * RETURNS
5637 * S_OK.
5639 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
5641 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
5642 return S_OK;
5645 /************************************************************************
5646 * VarBoolFromCy (OLEAUT32.124)
5648 * Convert a VT_CY to a VT_BOOL.
5650 * PARAMS
5651 * cyIn [I] Source
5652 * pBoolOut [O] Destination
5654 * RETURNS
5655 * S_OK.
5657 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
5659 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
5660 return S_OK;
5663 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
5665 HRSRC hrsrc;
5667 hrsrc = FindResourceExW( OLEAUT32_hModule, (LPWSTR)RT_STRING,
5668 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
5669 if (hrsrc)
5671 HGLOBAL hmem = LoadResource( OLEAUT32_hModule, hrsrc );
5673 if (hmem)
5675 const WCHAR *p;
5676 unsigned int i;
5678 p = LockResource( hmem );
5679 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
5681 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
5682 lpszDest[*p] = '\0';
5683 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
5684 return TRUE;
5687 return FALSE;
5690 /************************************************************************
5691 * VarBoolFromStr (OLEAUT32.125)
5693 * Convert a VT_BSTR to a VT_BOOL.
5695 * PARAMS
5696 * strIn [I] Source
5697 * lcid [I] LCID for the conversion
5698 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5699 * pBoolOut [O] Destination
5701 * RETURNS
5702 * Success: S_OK.
5703 * Failure: E_INVALIDARG, if pBoolOut is invalid.
5704 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5706 * NOTES
5707 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
5708 * it may contain (in any case mapping) the text "true" or "false".
5709 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
5710 * localised text of "True" or "False" in the language specified by lcid.
5711 * - If none of these matches occur, the string is treated as a numeric string
5712 * and the boolean pBoolOut will be set according to whether the number is zero
5713 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
5714 * - If the text is not numeric and does not match any of the above, then
5715 * DISP_E_TYPEMISMATCH is returned.
5717 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
5719 /* Any VB/VBA programmers out there should recognise these strings... */
5720 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
5721 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
5722 WCHAR szBuff[64];
5723 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5724 HRESULT hRes = S_OK;
5726 if (!strIn || !pBoolOut)
5727 return DISP_E_TYPEMISMATCH;
5729 /* Check if we should be comparing against localised text */
5730 if (dwFlags & VAR_LOCALBOOL)
5732 /* Convert our LCID into a usable value */
5733 lcid = ConvertDefaultLocale(lcid);
5735 langId = LANGIDFROMLCID(lcid);
5737 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
5738 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5740 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
5741 * I don't think this is needed unless any of the localised text strings
5742 * contain characters that can be so mapped. In the event that this is
5743 * true for a given language (possibly some Asian languages), then strIn
5744 * should be mapped here _only_ if langId is an Id for which this can occur.
5748 /* Note that if we are not comparing against localised strings, langId
5749 * will have its default value of LANG_ENGLISH. This allows us to mimic
5750 * the native behaviour of always checking against English strings even
5751 * after we've checked for localised ones.
5753 VarBoolFromStr_CheckLocalised:
5754 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
5756 /* Compare against localised strings, ignoring case */
5757 if (!strcmpiW(strIn, szBuff))
5759 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
5760 return hRes;
5762 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
5763 if (!strcmpiW(strIn, szBuff))
5765 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
5766 return hRes;
5770 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
5772 /* We have checked the localised text, now check English */
5773 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5774 goto VarBoolFromStr_CheckLocalised;
5777 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
5778 if (!strcmpW(strIn, szFalse))
5779 *pBoolOut = VARIANT_FALSE;
5780 else if (!strcmpW(strIn, szTrue))
5781 *pBoolOut = VARIANT_TRUE;
5782 else
5784 double d;
5786 /* If this string is a number, convert it as one */
5787 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
5788 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
5790 return hRes;
5793 /************************************************************************
5794 * VarBoolFromDisp (OLEAUT32.126)
5796 * Convert a VT_DISPATCH to a VT_BOOL.
5798 * PARAMS
5799 * pdispIn [I] Source
5800 * lcid [I] LCID for conversion
5801 * pBoolOut [O] Destination
5803 * RETURNS
5804 * Success: S_OK.
5805 * Failure: E_INVALIDARG, if the source value is invalid
5806 * DISP_E_OVERFLOW, if the value will not fit in the destination
5807 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5809 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
5811 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
5814 /************************************************************************
5815 * VarBoolFromI1 (OLEAUT32.233)
5817 * Convert a VT_I1 to a VT_BOOL.
5819 * PARAMS
5820 * cIn [I] Source
5821 * pBoolOut [O] Destination
5823 * RETURNS
5824 * S_OK.
5826 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
5828 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
5829 return S_OK;
5832 /************************************************************************
5833 * VarBoolFromUI2 (OLEAUT32.234)
5835 * Convert a VT_UI2 to a VT_BOOL.
5837 * PARAMS
5838 * usIn [I] Source
5839 * pBoolOut [O] Destination
5841 * RETURNS
5842 * S_OK.
5844 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
5846 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
5847 return S_OK;
5850 /************************************************************************
5851 * VarBoolFromUI4 (OLEAUT32.235)
5853 * Convert a VT_UI4 to a VT_BOOL.
5855 * PARAMS
5856 * ulIn [I] Source
5857 * pBoolOut [O] Destination
5859 * RETURNS
5860 * S_OK.
5862 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
5864 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
5865 return S_OK;
5868 /************************************************************************
5869 * VarBoolFromDec (OLEAUT32.236)
5871 * Convert a VT_DECIMAL to a VT_BOOL.
5873 * PARAMS
5874 * pDecIn [I] Source
5875 * pBoolOut [O] Destination
5877 * RETURNS
5878 * Success: S_OK.
5879 * Failure: E_INVALIDARG, if pDecIn is invalid.
5881 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
5883 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
5884 return E_INVALIDARG;
5886 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
5887 *pBoolOut = VARIANT_TRUE;
5888 else
5889 *pBoolOut = VARIANT_FALSE;
5890 return S_OK;
5893 /************************************************************************
5894 * VarBoolFromI8 (OLEAUT32.370)
5896 * Convert a VT_I8 to a VT_BOOL.
5898 * PARAMS
5899 * ullIn [I] Source
5900 * pBoolOut [O] Destination
5902 * RETURNS
5903 * S_OK.
5905 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
5907 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
5908 return S_OK;
5911 /************************************************************************
5912 * VarBoolFromUI8 (OLEAUT32.371)
5914 * Convert a VT_UI8 to a VT_BOOL.
5916 * PARAMS
5917 * ullIn [I] Source
5918 * pBoolOut [O] Destination
5920 * RETURNS
5921 * S_OK.
5923 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
5925 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
5926 return S_OK;
5929 /* BSTR
5932 /* Write a number from a UI8 and sign */
5933 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
5937 WCHAR ulNextDigit = ulVal % 10;
5939 *szOut-- = '0' + ulNextDigit;
5940 ulVal = (ulVal - ulNextDigit) / 10;
5941 } while (ulVal);
5943 szOut++;
5944 return szOut;
5947 /* Create a (possibly localised) BSTR from a UI8 and sign */
5948 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
5950 WCHAR szConverted[256];
5952 if (dwFlags & VAR_NEGATIVE)
5953 *--szOut = '-';
5955 if (dwFlags & LOCALE_USE_NLS)
5957 /* Format the number for the locale */
5958 szConverted[0] = '\0';
5959 GetNumberFormatW(lcid,
5960 dwFlags & LOCALE_NOUSEROVERRIDE,
5961 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
5962 szOut = szConverted;
5964 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
5967 /* Create a (possibly localised) BSTR from a UI8 and sign */
5968 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
5970 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
5972 if (!pbstrOut)
5973 return E_INVALIDARG;
5975 /* Create the basic number string */
5976 *szOut-- = '\0';
5977 szOut = VARIANT_WriteNumber(ulVal, szOut);
5979 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
5980 TRACE("returning %s\n", debugstr_w(*pbstrOut));
5981 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
5984 /******************************************************************************
5985 * VarBstrFromUI1 (OLEAUT32.108)
5987 * Convert a VT_UI1 to a VT_BSTR.
5989 * PARAMS
5990 * bIn [I] Source
5991 * lcid [I] LCID for the conversion
5992 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5993 * pbstrOut [O] Destination
5995 * RETURNS
5996 * Success: S_OK.
5997 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5998 * E_OUTOFMEMORY, if memory allocation fails.
6000 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6002 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6005 /******************************************************************************
6006 * VarBstrFromI2 (OLEAUT32.109)
6008 * Convert a VT_I2 to a VT_BSTR.
6010 * PARAMS
6011 * sIn [I] Source
6012 * lcid [I] LCID for the conversion
6013 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6014 * pbstrOut [O] Destination
6016 * RETURNS
6017 * Success: S_OK.
6018 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6019 * E_OUTOFMEMORY, if memory allocation fails.
6021 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6023 ULONG64 ul64 = sIn;
6025 if (sIn < 0)
6027 ul64 = -sIn;
6028 dwFlags |= VAR_NEGATIVE;
6030 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6033 /******************************************************************************
6034 * VarBstrFromI4 (OLEAUT32.110)
6036 * Convert a VT_I4 to a VT_BSTR.
6038 * PARAMS
6039 * lIn [I] Source
6040 * lcid [I] LCID for the conversion
6041 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6042 * pbstrOut [O] Destination
6044 * RETURNS
6045 * Success: S_OK.
6046 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6047 * E_OUTOFMEMORY, if memory allocation fails.
6049 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6051 ULONG64 ul64 = lIn;
6053 if (lIn < 0)
6055 ul64 = (ULONG)-lIn;
6056 dwFlags |= VAR_NEGATIVE;
6058 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6061 static BSTR VARIANT_BstrReplaceDecimal(WCHAR * buff, LCID lcid, ULONG dwFlags)
6063 BSTR bstrOut;
6064 WCHAR lpDecimalSep[16];
6066 /* Native oleaut32 uses the locale-specific decimal separator even in the
6067 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6068 American locales will see "one thousand and one tenth" as "1000,1"
6069 instead of "1000.1" (notice the comma). The following code checks for
6070 the need to replace the decimal separator, and if so, will prepare an
6071 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6073 GetLocaleInfoW(lcid, LOCALE_SDECIMAL, lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
6074 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6076 /* locale is compatible with English - return original string */
6077 bstrOut = SysAllocString(buff);
6079 else
6081 WCHAR *p;
6082 WCHAR numbuff[256];
6083 WCHAR empty[1] = {'\0'};
6084 NUMBERFMTW minFormat;
6086 minFormat.NumDigits = 0;
6087 minFormat.LeadingZero = 0;
6088 minFormat.Grouping = 0;
6089 minFormat.lpDecimalSep = lpDecimalSep;
6090 minFormat.lpThousandSep = empty;
6091 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6093 /* count number of decimal digits in string */
6094 p = strchrW( buff, '.' );
6095 if (p) minFormat.NumDigits = strlenW(p + 1);
6097 numbuff[0] = '\0';
6098 if (!GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6099 buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
6101 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6102 bstrOut = SysAllocString(buff);
6104 else
6106 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6107 bstrOut = SysAllocString(numbuff);
6110 return bstrOut;
6113 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6114 BSTR* pbstrOut, LPCWSTR lpszFormat)
6116 WCHAR buff[256];
6118 if (!pbstrOut)
6119 return E_INVALIDARG;
6121 sprintfW( buff, lpszFormat, dblIn );
6123 /* Negative zeroes are disallowed (some applications depend on this).
6124 If buff starts with a minus, and then nothing follows but zeroes
6125 and/or a period, it is a negative zero and is replaced with a
6126 canonical zero. This duplicates native oleaut32 behavior.
6128 if (buff[0] == '-')
6130 const WCHAR szAccept[] = {'0', '.', '\0'};
6131 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
6132 { buff[0] = '0'; buff[1] = '\0'; }
6135 TRACE("created string %s\n", debugstr_w(buff));
6136 if (dwFlags & LOCALE_USE_NLS)
6138 WCHAR numbuff[256];
6140 /* Format the number for the locale */
6141 numbuff[0] = '\0';
6142 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6143 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6144 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6145 *pbstrOut = SysAllocString(numbuff);
6147 else
6149 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6151 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6154 /******************************************************************************
6155 * VarBstrFromR4 (OLEAUT32.111)
6157 * Convert a VT_R4 to a VT_BSTR.
6159 * PARAMS
6160 * fltIn [I] Source
6161 * lcid [I] LCID for the conversion
6162 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6163 * pbstrOut [O] Destination
6165 * RETURNS
6166 * Success: S_OK.
6167 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6168 * E_OUTOFMEMORY, if memory allocation fails.
6170 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6172 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
6175 /******************************************************************************
6176 * VarBstrFromR8 (OLEAUT32.112)
6178 * Convert a VT_R8 to a VT_BSTR.
6180 * PARAMS
6181 * dblIn [I] Source
6182 * lcid [I] LCID for the conversion
6183 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6184 * pbstrOut [O] Destination
6186 * RETURNS
6187 * Success: S_OK.
6188 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6189 * E_OUTOFMEMORY, if memory allocation fails.
6191 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6193 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
6196 /******************************************************************************
6197 * VarBstrFromCy [OLEAUT32.113]
6199 * Convert a VT_CY to a VT_BSTR.
6201 * PARAMS
6202 * cyIn [I] Source
6203 * lcid [I] LCID for the conversion
6204 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6205 * pbstrOut [O] Destination
6207 * RETURNS
6208 * Success: S_OK.
6209 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6210 * E_OUTOFMEMORY, if memory allocation fails.
6212 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6214 WCHAR buff[256];
6215 double dblVal;
6217 if (!pbstrOut)
6218 return E_INVALIDARG;
6220 VarR8FromCy(cyIn, &dblVal);
6221 sprintfW(buff, szDoubleFormatW, dblVal);
6223 if (dwFlags & LOCALE_USE_NLS)
6225 WCHAR cybuff[256];
6227 /* Format the currency for the locale */
6228 cybuff[0] = '\0';
6229 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6230 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR));
6231 *pbstrOut = SysAllocString(cybuff);
6233 else
6234 *pbstrOut = SysAllocString(buff);
6236 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6239 /******************************************************************************
6240 * VarBstrFromDate [OLEAUT32.114]
6242 * Convert a VT_DATE to a VT_BSTR.
6244 * PARAMS
6245 * dateIn [I] Source
6246 * lcid [I] LCID for the conversion
6247 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6248 * pbstrOut [O] Destination
6250 * RETURNS
6251 * Success: S_OK.
6252 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6253 * E_OUTOFMEMORY, if memory allocation fails.
6255 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6257 SYSTEMTIME st;
6258 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6259 WCHAR date[128], *time;
6261 TRACE("(%g,0x%08lx,0x%08lx,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
6263 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6264 return E_INVALIDARG;
6266 *pbstrOut = NULL;
6268 if (dwFlags & VAR_CALENDAR_THAI)
6269 st.wYear += 553; /* Use the Thai buddhist calendar year */
6270 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6271 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6273 if (dwFlags & LOCALE_USE_NLS)
6274 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6275 else
6277 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6278 double partial = dateIn - whole;
6280 if (whole == 0.0)
6281 dwFlags |= VAR_TIMEVALUEONLY;
6282 else if (partial < 1e-12)
6283 dwFlags |= VAR_DATEVALUEONLY;
6286 if (dwFlags & VAR_TIMEVALUEONLY)
6287 date[0] = '\0';
6288 else
6289 if (!GetDateFormatW(lcid, dwFormatFlags|DATE_SHORTDATE, &st, NULL, date,
6290 sizeof(date)/sizeof(WCHAR)))
6291 return E_INVALIDARG;
6293 if (!(dwFlags & VAR_DATEVALUEONLY))
6295 time = date + strlenW(date);
6296 if (time != date)
6297 *time++ = ' ';
6298 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
6299 sizeof(date)/sizeof(WCHAR)-(time-date)))
6300 return E_INVALIDARG;
6303 *pbstrOut = SysAllocString(date);
6304 if (*pbstrOut)
6305 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6306 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6309 /******************************************************************************
6310 * VarBstrFromBool (OLEAUT32.116)
6312 * Convert a VT_BOOL to a VT_BSTR.
6314 * PARAMS
6315 * boolIn [I] Source
6316 * lcid [I] LCID for the conversion
6317 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6318 * pbstrOut [O] Destination
6320 * RETURNS
6321 * Success: S_OK.
6322 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6323 * E_OUTOFMEMORY, if memory allocation fails.
6325 * NOTES
6326 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6327 * localised text of "True" or "False". To convert a bool into a
6328 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6330 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6332 WCHAR szBuff[64];
6333 DWORD dwResId = IDS_TRUE;
6334 LANGID langId;
6336 TRACE("%d,0x%08lx,0x%08lx,%p\n", boolIn, lcid, dwFlags, pbstrOut);
6338 if (!pbstrOut)
6339 return E_INVALIDARG;
6341 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6342 * for variant formatting */
6343 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6345 case VAR_BOOLONOFF:
6346 dwResId = IDS_ON;
6347 break;
6348 case VAR_BOOLYESNO:
6349 dwResId = IDS_YES;
6350 break;
6351 case VAR_LOCALBOOL:
6352 break;
6353 default:
6354 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6357 lcid = ConvertDefaultLocale(lcid);
6358 langId = LANGIDFROMLCID(lcid);
6359 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6360 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6362 if (boolIn == VARIANT_FALSE)
6363 dwResId++; /* Use negative form */
6365 VarBstrFromBool_GetLocalised:
6366 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6368 *pbstrOut = SysAllocString(szBuff);
6369 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6372 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6374 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6375 goto VarBstrFromBool_GetLocalised;
6378 /* Should never get here */
6379 WARN("Failed to load bool text!\n");
6380 return E_OUTOFMEMORY;
6383 /******************************************************************************
6384 * VarBstrFromI1 (OLEAUT32.229)
6386 * Convert a VT_I1 to a VT_BSTR.
6388 * PARAMS
6389 * cIn [I] Source
6390 * lcid [I] LCID for the conversion
6391 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6392 * pbstrOut [O] Destination
6394 * RETURNS
6395 * Success: S_OK.
6396 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6397 * E_OUTOFMEMORY, if memory allocation fails.
6399 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6401 ULONG64 ul64 = cIn;
6403 if (cIn < 0)
6405 ul64 = -cIn;
6406 dwFlags |= VAR_NEGATIVE;
6408 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6411 /******************************************************************************
6412 * VarBstrFromUI2 (OLEAUT32.230)
6414 * Convert a VT_UI2 to a VT_BSTR.
6416 * PARAMS
6417 * usIn [I] Source
6418 * lcid [I] LCID for the conversion
6419 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6420 * pbstrOut [O] Destination
6422 * RETURNS
6423 * Success: S_OK.
6424 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6425 * E_OUTOFMEMORY, if memory allocation fails.
6427 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6429 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6432 /******************************************************************************
6433 * VarBstrFromUI4 (OLEAUT32.231)
6435 * Convert a VT_UI4 to a VT_BSTR.
6437 * PARAMS
6438 * ulIn [I] Source
6439 * lcid [I] LCID for the conversion
6440 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6441 * pbstrOut [O] Destination
6443 * RETURNS
6444 * Success: S_OK.
6445 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6446 * E_OUTOFMEMORY, if memory allocation fails.
6448 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6450 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
6453 /******************************************************************************
6454 * VarBstrFromDec (OLEAUT32.232)
6456 * Convert a VT_DECIMAL to a VT_BSTR.
6458 * PARAMS
6459 * pDecIn [I] Source
6460 * lcid [I] LCID for the conversion
6461 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6462 * pbstrOut [O] Destination
6464 * RETURNS
6465 * Success: S_OK.
6466 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6467 * E_OUTOFMEMORY, if memory allocation fails.
6469 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6471 WCHAR buff[256];
6472 VARIANT_DI temp;
6474 if (!pbstrOut)
6475 return E_INVALIDARG;
6477 VARIANT_DIFromDec(pDecIn, &temp);
6478 VARIANT_DI_tostringW(&temp, buff, 256);
6480 if (dwFlags & LOCALE_USE_NLS)
6482 WCHAR numbuff[256];
6484 /* Format the number for the locale */
6485 numbuff[0] = '\0';
6486 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6487 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6488 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6489 *pbstrOut = SysAllocString(numbuff);
6491 else
6493 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6496 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6497 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6500 /************************************************************************
6501 * VarBstrFromI8 (OLEAUT32.370)
6503 * Convert a VT_I8 to a VT_BSTR.
6505 * PARAMS
6506 * llIn [I] Source
6507 * lcid [I] LCID for the conversion
6508 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6509 * pbstrOut [O] Destination
6511 * RETURNS
6512 * Success: S_OK.
6513 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6514 * E_OUTOFMEMORY, if memory allocation fails.
6516 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6518 ULONG64 ul64 = llIn;
6520 if (llIn < 0)
6522 ul64 = -llIn;
6523 dwFlags |= VAR_NEGATIVE;
6525 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6528 /************************************************************************
6529 * VarBstrFromUI8 (OLEAUT32.371)
6531 * Convert a VT_UI8 to a VT_BSTR.
6533 * PARAMS
6534 * ullIn [I] Source
6535 * lcid [I] LCID for the conversion
6536 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6537 * pbstrOut [O] Destination
6539 * RETURNS
6540 * Success: S_OK.
6541 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6542 * E_OUTOFMEMORY, if memory allocation fails.
6544 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6546 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
6549 /************************************************************************
6550 * VarBstrFromDisp (OLEAUT32.115)
6552 * Convert a VT_DISPATCH to a BSTR.
6554 * PARAMS
6555 * pdispIn [I] Source
6556 * lcid [I] LCID for 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 the source value is invalid
6563 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6565 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6567 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
6570 /**********************************************************************
6571 * VarBstrCat (OLEAUT32.313)
6573 * Concatenate two BSTR values.
6575 * PARAMS
6576 * pbstrLeft [I] Source
6577 * pbstrRight [I] Value to concatenate
6578 * pbstrOut [O] Destination
6580 * RETURNS
6581 * Success: S_OK.
6582 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6583 * E_OUTOFMEMORY, if memory allocation fails.
6585 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
6587 unsigned int len;
6589 if (!pbstrOut)
6590 return E_INVALIDARG;
6592 len = pbstrLeft ? strlenW(pbstrLeft) : 0;
6593 if (pbstrRight)
6594 len += strlenW(pbstrRight);
6596 *pbstrOut = SysAllocStringLen(NULL, len);
6597 if (!*pbstrOut)
6598 return E_OUTOFMEMORY;
6600 (*pbstrOut)[0] = '\0';
6602 if (pbstrLeft)
6603 strcpyW(*pbstrOut, pbstrLeft);
6605 if (pbstrRight)
6606 strcatW(*pbstrOut, pbstrRight);
6608 return S_OK;
6611 /**********************************************************************
6612 * VarBstrCmp (OLEAUT32.314)
6614 * Compare two BSTR values.
6616 * PARAMS
6617 * pbstrLeft [I] Source
6618 * pbstrRight [I] Value to compare
6619 * lcid [I] LCID for the comparison
6620 * dwFlags [I] Flags to pass directly to CompareStringW().
6622 * RETURNS
6623 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
6624 * than, equal to or greater than pbstrRight respectively.
6626 * NOTES
6627 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
6628 * states. A NULL BSTR pointer is equivalent to an empty string.
6630 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
6632 if (!pbstrLeft || !*pbstrLeft)
6634 if (!pbstrRight || !*pbstrRight)
6635 return VARCMP_EQ;
6636 return VARCMP_LT;
6638 else if (!pbstrRight || !*pbstrRight)
6639 return VARCMP_GT;
6641 return CompareStringW(lcid, dwFlags, pbstrLeft, -1, pbstrRight, -1) - 1;
6645 * DATE
6648 /******************************************************************************
6649 * VarDateFromUI1 (OLEAUT32.88)
6651 * Convert a VT_UI1 to a VT_DATE.
6653 * PARAMS
6654 * bIn [I] Source
6655 * pdateOut [O] Destination
6657 * RETURNS
6658 * S_OK.
6660 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
6662 return VarR8FromUI1(bIn, pdateOut);
6665 /******************************************************************************
6666 * VarDateFromI2 (OLEAUT32.89)
6668 * Convert a VT_I2 to a VT_DATE.
6670 * PARAMS
6671 * sIn [I] Source
6672 * pdateOut [O] Destination
6674 * RETURNS
6675 * S_OK.
6677 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
6679 return VarR8FromI2(sIn, pdateOut);
6682 /******************************************************************************
6683 * VarDateFromI4 (OLEAUT32.90)
6685 * Convert a VT_I4 to a VT_DATE.
6687 * PARAMS
6688 * lIn [I] Source
6689 * pdateOut [O] Destination
6691 * RETURNS
6692 * S_OK.
6694 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
6696 return VarDateFromR8(lIn, pdateOut);
6699 /******************************************************************************
6700 * VarDateFromR4 (OLEAUT32.91)
6702 * Convert a VT_R4 to a VT_DATE.
6704 * PARAMS
6705 * fltIn [I] Source
6706 * pdateOut [O] Destination
6708 * RETURNS
6709 * S_OK.
6711 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
6713 return VarR8FromR4(fltIn, pdateOut);
6716 /******************************************************************************
6717 * VarDateFromR8 (OLEAUT32.92)
6719 * Convert a VT_R8 to a VT_DATE.
6721 * PARAMS
6722 * dblIn [I] Source
6723 * pdateOut [O] Destination
6725 * RETURNS
6726 * S_OK.
6728 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
6730 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
6731 *pdateOut = (DATE)dblIn;
6732 return S_OK;
6735 /**********************************************************************
6736 * VarDateFromDisp (OLEAUT32.95)
6738 * Convert a VT_DISPATCH to a VT_DATE.
6740 * PARAMS
6741 * pdispIn [I] Source
6742 * lcid [I] LCID for conversion
6743 * pdateOut [O] Destination
6745 * RETURNS
6746 * Success: S_OK.
6747 * Failure: E_INVALIDARG, if the source value is invalid
6748 * DISP_E_OVERFLOW, if the value will not fit in the destination
6749 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6751 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
6753 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
6756 /******************************************************************************
6757 * VarDateFromBool (OLEAUT32.96)
6759 * Convert a VT_BOOL to a VT_DATE.
6761 * PARAMS
6762 * boolIn [I] Source
6763 * pdateOut [O] Destination
6765 * RETURNS
6766 * S_OK.
6768 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
6770 return VarR8FromBool(boolIn, pdateOut);
6773 /**********************************************************************
6774 * VarDateFromCy (OLEAUT32.93)
6776 * Convert a VT_CY to a VT_DATE.
6778 * PARAMS
6779 * lIn [I] Source
6780 * pdateOut [O] Destination
6782 * RETURNS
6783 * S_OK.
6785 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
6787 return VarR8FromCy(cyIn, pdateOut);
6790 /* Date string parsing */
6791 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
6792 #define DP_DATESEP 0x02 /* Date separator */
6793 #define DP_MONTH 0x04 /* Month name */
6794 #define DP_AM 0x08 /* AM */
6795 #define DP_PM 0x10 /* PM */
6797 typedef struct tagDATEPARSE
6799 DWORD dwCount; /* Number of fields found so far (maximum 6) */
6800 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
6801 DWORD dwFlags[6]; /* Flags for each field */
6802 DWORD dwValues[6]; /* Value of each field */
6803 } DATEPARSE;
6805 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
6807 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
6809 /* Determine if a day is valid in a given month of a given year */
6810 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
6812 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
6814 if (day && month && month < 13)
6816 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
6817 return TRUE;
6819 return FALSE;
6822 /* Possible orders for 3 numbers making up a date */
6823 #define ORDER_MDY 0x01
6824 #define ORDER_YMD 0x02
6825 #define ORDER_YDM 0x04
6826 #define ORDER_DMY 0x08
6827 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
6829 /* Determine a date for a particular locale, from 3 numbers */
6830 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
6831 DWORD offset, SYSTEMTIME *st)
6833 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
6835 if (!dp->dwCount)
6837 v1 = 30; /* Default to (Variant) 0 date part */
6838 v2 = 12;
6839 v3 = 1899;
6840 goto VARIANT_MakeDate_OK;
6843 v1 = dp->dwValues[offset + 0];
6844 v2 = dp->dwValues[offset + 1];
6845 if (dp->dwCount == 2)
6847 SYSTEMTIME current;
6848 GetSystemTime(&current);
6849 v3 = current.wYear;
6851 else
6852 v3 = dp->dwValues[offset + 2];
6854 TRACE("(%ld,%ld,%ld,%ld,%ld)\n", v1, v2, v3, iDate, offset);
6856 /* If one number must be a month (Because a month name was given), then only
6857 * consider orders with the month in that position.
6858 * If we took the current year as 'v3', then only allow a year in that position.
6860 if (dp->dwFlags[offset + 0] & DP_MONTH)
6862 dwAllOrders = ORDER_MDY;
6864 else if (dp->dwFlags[offset + 1] & DP_MONTH)
6866 dwAllOrders = ORDER_DMY;
6867 if (dp->dwCount > 2)
6868 dwAllOrders |= ORDER_YMD;
6870 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
6872 dwAllOrders = ORDER_YDM;
6874 else
6876 dwAllOrders = ORDER_MDY|ORDER_DMY;
6877 if (dp->dwCount > 2)
6878 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
6881 VARIANT_MakeDate_Start:
6882 TRACE("dwAllOrders is 0x%08lx\n", dwAllOrders);
6884 while (dwAllOrders)
6886 DWORD dwTemp;
6888 if (dwCount == 0)
6890 /* First: Try the order given by iDate */
6891 switch (iDate)
6893 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
6894 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
6895 default: dwTry = dwAllOrders & ORDER_YMD; break;
6898 else if (dwCount == 1)
6900 /* Second: Try all the orders compatible with iDate */
6901 switch (iDate)
6903 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
6904 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break;
6905 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
6908 else
6910 /* Finally: Try any remaining orders */
6911 dwTry = dwAllOrders;
6914 TRACE("Attempt %ld, dwTry is 0x%08lx\n", dwCount, dwTry);
6916 dwCount++;
6917 if (!dwTry)
6918 continue;
6920 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
6922 if (dwTry & ORDER_MDY)
6924 if (VARIANT_IsValidMonthDay(v2,v1,v3))
6926 DATE_SWAP(v1,v2);
6927 goto VARIANT_MakeDate_OK;
6929 dwAllOrders &= ~ORDER_MDY;
6931 if (dwTry & ORDER_YMD)
6933 if (VARIANT_IsValidMonthDay(v3,v2,v1))
6935 DATE_SWAP(v1,v3);
6936 goto VARIANT_MakeDate_OK;
6938 dwAllOrders &= ~ORDER_YMD;
6940 if (dwTry & ORDER_YDM)
6942 if (VARIANT_IsValidMonthDay(v2,v3,v1))
6944 DATE_SWAP(v1,v2);
6945 DATE_SWAP(v2,v3);
6946 goto VARIANT_MakeDate_OK;
6948 dwAllOrders &= ~ORDER_YDM;
6950 if (dwTry & ORDER_DMY)
6952 if (VARIANT_IsValidMonthDay(v1,v2,v3))
6953 goto VARIANT_MakeDate_OK;
6954 dwAllOrders &= ~ORDER_DMY;
6956 if (dwTry & ORDER_MYD)
6958 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
6959 if (VARIANT_IsValidMonthDay(v3,v1,v2))
6961 DATE_SWAP(v1,v3);
6962 DATE_SWAP(v2,v3);
6963 goto VARIANT_MakeDate_OK;
6965 dwAllOrders &= ~ORDER_MYD;
6969 if (dp->dwCount == 2)
6971 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
6972 v3 = 1; /* 1st of the month */
6973 dwAllOrders = ORDER_YMD|ORDER_MYD;
6974 dp->dwCount = 0; /* Don't return to this code path again */
6975 dwCount = 0;
6976 goto VARIANT_MakeDate_Start;
6979 /* No valid dates were able to be constructed */
6980 return DISP_E_TYPEMISMATCH;
6982 VARIANT_MakeDate_OK:
6984 /* Check that the time part is ok */
6985 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
6986 return DISP_E_TYPEMISMATCH;
6988 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
6989 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
6990 st->wHour += 12;
6991 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
6992 st->wHour = 0;
6993 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
6995 st->wDay = v1;
6996 st->wMonth = v2;
6997 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
6998 * be retrieved from:
6999 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7000 * But Wine doesn't have/use that key as at the time of writing.
7002 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
7003 TRACE("Returning date %ld/%ld/%d\n", v1, v2, st->wYear);
7004 return S_OK;
7007 /******************************************************************************
7008 * VarDateFromStr [OLEAUT32.94]
7010 * Convert a VT_BSTR to at VT_DATE.
7012 * PARAMS
7013 * strIn [I] String to convert
7014 * lcid [I] Locale identifier for the conversion
7015 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7016 * pdateOut [O] Destination for the converted value
7018 * RETURNS
7019 * Success: S_OK. pdateOut contains the converted value.
7020 * FAILURE: An HRESULT error code indicating the prolem.
7022 * NOTES
7023 * Any date format that can be created using the date formats from lcid
7024 * (Either from kernel Nls functions, variant conversion or formatting) is a
7025 * valid input to this function. In addition, a few more esoteric formats are
7026 * also supported for compatibility with the native version. The date is
7027 * interpreted according to the date settings in the control panel, unless
7028 * the date is invalid in that format, in which the most compatible format
7029 * that produces a valid date will be used.
7031 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7033 static const USHORT ParseDateTokens[] =
7035 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7036 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7037 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7038 LOCALE_SMONTHNAME13,
7039 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7040 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7041 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7042 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7043 LOCALE_SABBREVMONTHNAME13,
7044 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7045 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7046 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7047 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7048 LOCALE_SABBREVDAYNAME7,
7049 LOCALE_S1159, LOCALE_S2359
7051 static const BYTE ParseDateMonths[] =
7053 1,2,3,4,5,6,7,8,9,10,11,12,13,
7054 1,2,3,4,5,6,7,8,9,10,11,12,13
7056 size_t i;
7057 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
7058 DATEPARSE dp;
7059 DWORD dwDateSeps = 0, iDate = 0;
7060 HRESULT hRet = S_OK;
7062 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7063 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7064 return E_INVALIDARG;
7066 if (!strIn)
7067 return DISP_E_TYPEMISMATCH;
7069 *pdateOut = 0.0;
7071 TRACE("(%s,0x%08lx,0x%08lx,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7073 memset(&dp, 0, sizeof(dp));
7075 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7076 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7077 TRACE("iDate is %ld\n", iDate);
7079 /* Get the month/day/am/pm tokens for this locale */
7080 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7082 WCHAR buff[128];
7083 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7085 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7086 * GetAltMonthNames(). We should really cache these strings too.
7088 buff[0] = '\0';
7089 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
7090 tokens[i] = SysAllocString(buff);
7091 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7094 /* Parse the string into our structure */
7095 while (*strIn)
7097 if (dp.dwCount > 6)
7098 break;
7100 if (isdigitW(*strIn))
7102 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
7103 dp.dwCount++;
7104 strIn--;
7106 else if (isalpha(*strIn))
7108 BOOL bFound = FALSE;
7110 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7112 DWORD dwLen = strlenW(tokens[i]);
7113 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
7115 if (i <= 25)
7117 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7118 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7119 dp.dwCount++;
7121 else if (i > 39)
7123 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7124 hRet = DISP_E_TYPEMISMATCH;
7125 else
7127 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7128 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7131 strIn += (dwLen - 1);
7132 bFound = TRUE;
7133 break;
7137 if (!bFound)
7139 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7140 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7142 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7143 if (*strIn == 'a' || *strIn == 'A')
7145 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7146 dp.dwParseFlags |= DP_AM;
7148 else
7150 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7151 dp.dwParseFlags |= DP_PM;
7153 strIn++;
7155 else
7157 TRACE("No matching token for %s\n", debugstr_w(strIn));
7158 hRet = DISP_E_TYPEMISMATCH;
7159 break;
7163 else if (*strIn == ':' || *strIn == '.')
7165 if (!dp.dwCount || !strIn[1])
7166 hRet = DISP_E_TYPEMISMATCH;
7167 else
7168 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7170 else if (*strIn == '-' || *strIn == '/')
7172 dwDateSeps++;
7173 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7174 hRet = DISP_E_TYPEMISMATCH;
7175 else
7176 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7178 else if (*strIn == ',' || isspaceW(*strIn))
7180 if (*strIn == ',' && !strIn[1])
7181 hRet = DISP_E_TYPEMISMATCH;
7183 else
7185 hRet = DISP_E_TYPEMISMATCH;
7187 strIn++;
7190 if (!dp.dwCount || dp.dwCount > 6 ||
7191 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7192 hRet = DISP_E_TYPEMISMATCH;
7194 if (SUCCEEDED(hRet))
7196 SYSTEMTIME st;
7197 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7199 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7201 /* Figure out which numbers correspond to which fields.
7203 * This switch statement works based on the fact that native interprets any
7204 * fields that are not joined with a time separator ('.' or ':') as date
7205 * fields. Thus we construct a value from 0-32 where each set bit indicates
7206 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7207 * For valid permutations, we set dwOffset to point to the first date field
7208 * and shorten dp.dwCount by the number of time fields found. The real
7209 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7210 * each date number must represent in the context of iDate.
7212 TRACE("0x%08lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7214 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7216 case 0x1: /* TT TTDD TTDDD */
7217 if (dp.dwCount > 3 &&
7218 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7219 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7220 hRet = DISP_E_TYPEMISMATCH;
7221 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7222 hRet = DISP_E_TYPEMISMATCH;
7223 st.wHour = dp.dwValues[0];
7224 st.wMinute = dp.dwValues[1];
7225 dp.dwCount -= 2;
7226 dwOffset = 2;
7227 break;
7229 case 0x3: /* TTT TTTDD TTTDDD */
7230 if (dp.dwCount > 4 &&
7231 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7232 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7233 hRet = DISP_E_TYPEMISMATCH;
7234 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7235 hRet = DISP_E_TYPEMISMATCH;
7236 st.wHour = dp.dwValues[0];
7237 st.wMinute = dp.dwValues[1];
7238 st.wSecond = dp.dwValues[2];
7239 dwOffset = 3;
7240 dp.dwCount -= 3;
7241 break;
7243 case 0x4: /* DDTT */
7244 if (dp.dwCount != 4 ||
7245 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7246 hRet = DISP_E_TYPEMISMATCH;
7248 st.wHour = dp.dwValues[2];
7249 st.wMinute = dp.dwValues[3];
7250 dp.dwCount -= 2;
7251 break;
7253 case 0x0: /* T DD DDD TDDD TDDD */
7254 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7256 st.wHour = dp.dwValues[0]; /* T */
7257 dp.dwCount = 0;
7258 break;
7260 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7262 hRet = DISP_E_TYPEMISMATCH;
7264 else if (dp.dwCount == 3)
7266 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7268 dp.dwCount = 2;
7269 st.wHour = dp.dwValues[0];
7270 dwOffset = 1;
7271 break;
7273 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7275 dp.dwCount = 2;
7276 st.wHour = dp.dwValues[2];
7277 break;
7279 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7280 hRet = DISP_E_TYPEMISMATCH;
7282 else if (dp.dwCount == 4)
7284 dp.dwCount = 3;
7285 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7287 st.wHour = dp.dwValues[0];
7288 dwOffset = 1;
7290 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7292 st.wHour = dp.dwValues[3];
7294 else
7295 hRet = DISP_E_TYPEMISMATCH;
7296 break;
7298 /* .. fall through .. */
7300 case 0x8: /* DDDTT */
7301 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7302 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7303 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7304 dp.dwCount == 4 || dp.dwCount == 6)
7305 hRet = DISP_E_TYPEMISMATCH;
7306 st.wHour = dp.dwValues[3];
7307 st.wMinute = dp.dwValues[4];
7308 if (dp.dwCount == 5)
7309 dp.dwCount -= 2;
7310 break;
7312 case 0xC: /* DDTTT */
7313 if (dp.dwCount != 5 ||
7314 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7315 hRet = DISP_E_TYPEMISMATCH;
7316 st.wHour = dp.dwValues[2];
7317 st.wMinute = dp.dwValues[3];
7318 st.wSecond = dp.dwValues[4];
7319 dp.dwCount -= 3;
7320 break;
7322 case 0x18: /* DDDTTT */
7323 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7324 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7325 hRet = DISP_E_TYPEMISMATCH;
7326 st.wHour = dp.dwValues[3];
7327 st.wMinute = dp.dwValues[4];
7328 st.wSecond = dp.dwValues[5];
7329 dp.dwCount -= 3;
7330 break;
7332 default:
7333 hRet = DISP_E_TYPEMISMATCH;
7334 break;
7337 if (SUCCEEDED(hRet))
7339 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7341 if (dwFlags & VAR_TIMEVALUEONLY)
7343 st.wYear = 1899;
7344 st.wMonth = 12;
7345 st.wDay = 30;
7347 else if (dwFlags & VAR_DATEVALUEONLY)
7348 st.wHour = st.wMinute = st.wSecond = 0;
7350 /* Finally, convert the value to a VT_DATE */
7351 if (SUCCEEDED(hRet))
7352 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7356 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7357 SysFreeString(tokens[i]);
7358 return hRet;
7361 /******************************************************************************
7362 * VarDateFromI1 (OLEAUT32.221)
7364 * Convert a VT_I1 to a VT_DATE.
7366 * PARAMS
7367 * cIn [I] Source
7368 * pdateOut [O] Destination
7370 * RETURNS
7371 * S_OK.
7373 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7375 return VarR8FromI1(cIn, pdateOut);
7378 /******************************************************************************
7379 * VarDateFromUI2 (OLEAUT32.222)
7381 * Convert a VT_UI2 to a VT_DATE.
7383 * PARAMS
7384 * uiIn [I] Source
7385 * pdateOut [O] Destination
7387 * RETURNS
7388 * S_OK.
7390 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7392 return VarR8FromUI2(uiIn, pdateOut);
7395 /******************************************************************************
7396 * VarDateFromUI4 (OLEAUT32.223)
7398 * Convert a VT_UI4 to a VT_DATE.
7400 * PARAMS
7401 * ulIn [I] Source
7402 * pdateOut [O] Destination
7404 * RETURNS
7405 * S_OK.
7407 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7409 return VarDateFromR8(ulIn, pdateOut);
7412 /**********************************************************************
7413 * VarDateFromDec (OLEAUT32.224)
7415 * Convert a VT_DECIMAL to a VT_DATE.
7417 * PARAMS
7418 * pdecIn [I] Source
7419 * pdateOut [O] Destination
7421 * RETURNS
7422 * S_OK.
7424 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
7426 return VarR8FromDec(pdecIn, pdateOut);
7429 /******************************************************************************
7430 * VarDateFromI8 (OLEAUT32.364)
7432 * Convert a VT_I8 to a VT_DATE.
7434 * PARAMS
7435 * llIn [I] Source
7436 * pdateOut [O] Destination
7438 * RETURNS
7439 * Success: S_OK.
7440 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7442 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
7444 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
7445 *pdateOut = (DATE)llIn;
7446 return S_OK;
7449 /******************************************************************************
7450 * VarDateFromUI8 (OLEAUT32.365)
7452 * Convert a VT_UI8 to a VT_DATE.
7454 * PARAMS
7455 * ullIn [I] Source
7456 * pdateOut [O] Destination
7458 * RETURNS
7459 * Success: S_OK.
7460 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7462 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
7464 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
7465 *pdateOut = (DATE)ullIn;
7466 return S_OK;