Changes in crossover-wine-src-6.1.0 except for configure
[wine/hacks.git] / dlls / oleaut32 / vartype.c
bloba6a483d4f1c78d1dbbaa6a611ba5b8d64b098987
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 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 &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 static inline 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, ULONG, VarI8FromUI4);
232 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX);
234 /* UI8 */
235 SIMPLE(ULONG64, BYTE, VarUI8FromUI1);
236 NEGTST(ULONG64, SHORT, VarUI8FromI2);
237 NEGTST(ULONG64, signed char, VarUI8FromI1);
238 SIMPLE(ULONG64, USHORT, VarUI8FromUI2);
239 SIMPLE(ULONG64, ULONG, VarUI8FromUI4);
240 NEGTST(ULONG64, LONG64, VarUI8FromI8);
242 /* R4 (float) */
243 SIMPLE(float, BYTE, VarR4FromUI1);
244 SIMPLE(float, SHORT, VarR4FromI2);
245 SIMPLE(float, signed char, VarR4FromI1);
246 SIMPLE(float, USHORT, VarR4FromUI2);
247 SIMPLE(float, LONG, VarR4FromI4);
248 SIMPLE(float, ULONG, VarR4FromUI4);
249 SIMPLE(float, LONG64, VarR4FromI8);
250 SIMPLE(float, ULONG64, VarR4FromUI8);
252 /* R8 (double) */
253 SIMPLE(double, BYTE, VarR8FromUI1);
254 SIMPLE(double, SHORT, VarR8FromI2);
255 SIMPLE(double, float, VarR8FromR4);
256 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
257 SIMPLE(double, DATE, VarR8FromDate);
258 SIMPLE(double, signed char, VarR8FromI1);
259 SIMPLE(double, USHORT, VarR8FromUI2);
260 SIMPLE(double, LONG, VarR8FromI4);
261 SIMPLE(double, ULONG, VarR8FromUI4);
262 SIMPLE(double, LONG64, VarR8FromI8);
263 SIMPLE(double, ULONG64, VarR8FromUI8);
266 /* I1
269 /************************************************************************
270 * VarI1FromUI1 (OLEAUT32.244)
272 * Convert a VT_UI1 to a VT_I1.
274 * PARAMS
275 * bIn [I] Source
276 * pcOut [O] Destination
278 * RETURNS
279 * Success: S_OK.
280 * Failure: E_INVALIDARG, if the source value is invalid
281 * DISP_E_OVERFLOW, if the value will not fit in the destination
283 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
285 return _VarI1FromUI1(bIn, pcOut);
288 /************************************************************************
289 * VarI1FromI2 (OLEAUT32.245)
291 * Convert a VT_I2 to a VT_I1.
293 * PARAMS
294 * sIn [I] Source
295 * pcOut [O] Destination
297 * RETURNS
298 * Success: S_OK.
299 * Failure: E_INVALIDARG, if the source value is invalid
300 * DISP_E_OVERFLOW, if the value will not fit in the destination
302 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
304 return _VarI1FromI2(sIn, pcOut);
307 /************************************************************************
308 * VarI1FromI4 (OLEAUT32.246)
310 * Convert a VT_I4 to a VT_I1.
312 * PARAMS
313 * iIn [I] Source
314 * pcOut [O] Destination
316 * RETURNS
317 * Success: S_OK.
318 * Failure: E_INVALIDARG, if the source value is invalid
319 * DISP_E_OVERFLOW, if the value will not fit in the destination
321 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
323 return _VarI1FromI4(iIn, pcOut);
326 /************************************************************************
327 * VarI1FromR4 (OLEAUT32.247)
329 * Convert a VT_R4 to a VT_I1.
331 * PARAMS
332 * fltIn [I] Source
333 * pcOut [O] Destination
335 * RETURNS
336 * Success: S_OK.
337 * Failure: E_INVALIDARG, if the source value is invalid
338 * DISP_E_OVERFLOW, if the value will not fit in the destination
340 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
342 return VarI1FromR8(fltIn, pcOut);
345 /************************************************************************
346 * VarI1FromR8 (OLEAUT32.248)
348 * Convert a VT_R8 to a VT_I1.
350 * PARAMS
351 * dblIn [I] Source
352 * pcOut [O] Destination
354 * RETURNS
355 * Success: S_OK.
356 * Failure: E_INVALIDARG, if the source value is invalid
357 * DISP_E_OVERFLOW, if the value will not fit in the destination
359 * NOTES
360 * See VarI8FromR8() for details concerning rounding.
362 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
364 if (dblIn < (double)I1_MIN || dblIn > (double)I1_MAX)
365 return DISP_E_OVERFLOW;
366 VARIANT_DutchRound(CHAR, dblIn, *pcOut);
367 return S_OK;
370 /************************************************************************
371 * VarI1FromDate (OLEAUT32.249)
373 * Convert a VT_DATE to a VT_I1.
375 * PARAMS
376 * dateIn [I] Source
377 * pcOut [O] Destination
379 * RETURNS
380 * Success: S_OK.
381 * Failure: E_INVALIDARG, if the source value is invalid
382 * DISP_E_OVERFLOW, if the value will not fit in the destination
384 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
386 return VarI1FromR8(dateIn, pcOut);
389 /************************************************************************
390 * VarI1FromCy (OLEAUT32.250)
392 * Convert a VT_CY to a VT_I1.
394 * PARAMS
395 * cyIn [I] Source
396 * pcOut [O] Destination
398 * RETURNS
399 * Success: S_OK.
400 * Failure: E_INVALIDARG, if the source value is invalid
401 * DISP_E_OVERFLOW, if the value will not fit in the destination
403 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
405 LONG i = I1_MAX + 1;
407 VarI4FromCy(cyIn, &i);
408 return _VarI1FromI4(i, pcOut);
411 /************************************************************************
412 * VarI1FromStr (OLEAUT32.251)
414 * Convert a VT_BSTR to a VT_I1.
416 * PARAMS
417 * strIn [I] Source
418 * lcid [I] LCID for the conversion
419 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
420 * pcOut [O] Destination
422 * RETURNS
423 * Success: S_OK.
424 * Failure: E_INVALIDARG, if the source value is invalid
425 * DISP_E_OVERFLOW, if the value will not fit in the destination
426 * DISP_E_TYPEMISMATCH, if the type cannot be converted
428 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
430 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
433 /************************************************************************
434 * VarI1FromDisp (OLEAUT32.252)
436 * Convert a VT_DISPATCH to a VT_I1.
438 * PARAMS
439 * pdispIn [I] Source
440 * lcid [I] LCID for conversion
441 * pcOut [O] Destination
443 * RETURNS
444 * Success: S_OK.
445 * Failure: E_INVALIDARG, if the source value is invalid
446 * DISP_E_OVERFLOW, if the value will not fit in the destination
447 * DISP_E_TYPEMISMATCH, if the type cannot be converted
449 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
451 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0);
454 /************************************************************************
455 * VarI1FromBool (OLEAUT32.253)
457 * Convert a VT_BOOL to a VT_I1.
459 * PARAMS
460 * boolIn [I] Source
461 * pcOut [O] Destination
463 * RETURNS
464 * S_OK.
466 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
468 return _VarI1FromBool(boolIn, pcOut);
471 /************************************************************************
472 * VarI1FromUI2 (OLEAUT32.254)
474 * Convert a VT_UI2 to a VT_I1.
476 * PARAMS
477 * usIn [I] Source
478 * pcOut [O] Destination
480 * RETURNS
481 * Success: S_OK.
482 * Failure: E_INVALIDARG, if the source value is invalid
483 * DISP_E_OVERFLOW, if the value will not fit in the destination
485 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
487 return _VarI1FromUI2(usIn, pcOut);
490 /************************************************************************
491 * VarI1FromUI4 (OLEAUT32.255)
493 * Convert a VT_UI4 to a VT_I1.
495 * PARAMS
496 * ulIn [I] Source
497 * pcOut [O] Destination
499 * RETURNS
500 * Success: S_OK.
501 * Failure: E_INVALIDARG, if the source value is invalid
502 * DISP_E_OVERFLOW, if the value will not fit in the destination
503 * DISP_E_TYPEMISMATCH, if the type cannot be converted
505 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
507 return _VarI1FromUI4(ulIn, pcOut);
510 /************************************************************************
511 * VarI1FromDec (OLEAUT32.256)
513 * Convert a VT_DECIMAL to a VT_I1.
515 * PARAMS
516 * pDecIn [I] Source
517 * pcOut [O] Destination
519 * RETURNS
520 * Success: S_OK.
521 * Failure: E_INVALIDARG, if the source value is invalid
522 * DISP_E_OVERFLOW, if the value will not fit in the destination
524 HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut)
526 LONG64 i64;
527 HRESULT hRet;
529 hRet = VarI8FromDec(pdecIn, &i64);
531 if (SUCCEEDED(hRet))
532 hRet = _VarI1FromI8(i64, pcOut);
533 return hRet;
536 /************************************************************************
537 * VarI1FromI8 (OLEAUT32.376)
539 * Convert a VT_I8 to a VT_I1.
541 * PARAMS
542 * llIn [I] Source
543 * pcOut [O] Destination
545 * RETURNS
546 * Success: S_OK.
547 * Failure: E_INVALIDARG, if the source value is invalid
548 * DISP_E_OVERFLOW, if the value will not fit in the destination
550 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
552 return _VarI1FromI8(llIn, pcOut);
555 /************************************************************************
556 * VarI1FromUI8 (OLEAUT32.377)
558 * Convert a VT_UI8 to a VT_I1.
560 * PARAMS
561 * ullIn [I] Source
562 * pcOut [O] Destination
564 * RETURNS
565 * Success: S_OK.
566 * Failure: E_INVALIDARG, if the source value is invalid
567 * DISP_E_OVERFLOW, if the value will not fit in the destination
569 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
571 return _VarI1FromUI8(ullIn, pcOut);
574 /* UI1
577 /************************************************************************
578 * VarUI1FromI2 (OLEAUT32.130)
580 * Convert a VT_I2 to a VT_UI1.
582 * PARAMS
583 * sIn [I] Source
584 * pbOut [O] Destination
586 * RETURNS
587 * Success: S_OK.
588 * Failure: E_INVALIDARG, if the source value is invalid
589 * DISP_E_OVERFLOW, if the value will not fit in the destination
591 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
593 return _VarUI1FromI2(sIn, pbOut);
596 /************************************************************************
597 * VarUI1FromI4 (OLEAUT32.131)
599 * Convert a VT_I4 to a VT_UI1.
601 * PARAMS
602 * iIn [I] Source
603 * pbOut [O] Destination
605 * RETURNS
606 * Success: S_OK.
607 * Failure: E_INVALIDARG, if the source value is invalid
608 * DISP_E_OVERFLOW, if the value will not fit in the destination
610 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
612 return _VarUI1FromI4(iIn, pbOut);
615 /************************************************************************
616 * VarUI1FromR4 (OLEAUT32.132)
618 * Convert a VT_R4 to a VT_UI1.
620 * PARAMS
621 * fltIn [I] Source
622 * pbOut [O] Destination
624 * RETURNS
625 * Success: S_OK.
626 * Failure: E_INVALIDARG, if the source value is invalid
627 * DISP_E_OVERFLOW, if the value will not fit in the destination
628 * DISP_E_TYPEMISMATCH, if the type cannot be converted
630 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
632 return VarUI1FromR8(fltIn, pbOut);
635 /************************************************************************
636 * VarUI1FromR8 (OLEAUT32.133)
638 * Convert a VT_R8 to a VT_UI1.
640 * PARAMS
641 * dblIn [I] Source
642 * pbOut [O] Destination
644 * RETURNS
645 * Success: S_OK.
646 * Failure: E_INVALIDARG, if the source value is invalid
647 * DISP_E_OVERFLOW, if the value will not fit in the destination
649 * NOTES
650 * See VarI8FromR8() for details concerning rounding.
652 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
654 if (dblIn < -0.5 || dblIn > (double)UI1_MAX)
655 return DISP_E_OVERFLOW;
656 VARIANT_DutchRound(BYTE, dblIn, *pbOut);
657 return S_OK;
660 /************************************************************************
661 * VarUI1FromCy (OLEAUT32.134)
663 * Convert a VT_CY to a VT_UI1.
665 * PARAMS
666 * cyIn [I] Source
667 * pbOut [O] Destination
669 * RETURNS
670 * Success: S_OK.
671 * Failure: E_INVALIDARG, if the source value is invalid
672 * DISP_E_OVERFLOW, if the value will not fit in the destination
674 * NOTES
675 * Negative values >= -5000 will be converted to 0.
677 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
679 ULONG i = UI1_MAX + 1;
681 VarUI4FromCy(cyIn, &i);
682 return _VarUI1FromUI4(i, pbOut);
685 /************************************************************************
686 * VarUI1FromDate (OLEAUT32.135)
688 * Convert a VT_DATE to a VT_UI1.
690 * PARAMS
691 * dateIn [I] Source
692 * pbOut [O] Destination
694 * RETURNS
695 * Success: S_OK.
696 * Failure: E_INVALIDARG, if the source value is invalid
697 * DISP_E_OVERFLOW, if the value will not fit in the destination
699 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
701 return VarUI1FromR8(dateIn, pbOut);
704 /************************************************************************
705 * VarUI1FromStr (OLEAUT32.136)
707 * Convert a VT_BSTR to a VT_UI1.
709 * PARAMS
710 * strIn [I] Source
711 * lcid [I] LCID for the conversion
712 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
713 * pbOut [O] Destination
715 * RETURNS
716 * Success: S_OK.
717 * Failure: E_INVALIDARG, if the source value is invalid
718 * DISP_E_OVERFLOW, if the value will not fit in the destination
719 * DISP_E_TYPEMISMATCH, if the type cannot be converted
721 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
723 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
726 /************************************************************************
727 * VarUI1FromDisp (OLEAUT32.137)
729 * Convert a VT_DISPATCH to a VT_UI1.
731 * PARAMS
732 * pdispIn [I] Source
733 * lcid [I] LCID for conversion
734 * pbOut [O] Destination
736 * RETURNS
737 * Success: S_OK.
738 * Failure: E_INVALIDARG, if the source value is invalid
739 * DISP_E_OVERFLOW, if the value will not fit in the destination
740 * DISP_E_TYPEMISMATCH, if the type cannot be converted
742 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
744 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0);
747 /************************************************************************
748 * VarUI1FromBool (OLEAUT32.138)
750 * Convert a VT_BOOL to a VT_UI1.
752 * PARAMS
753 * boolIn [I] Source
754 * pbOut [O] Destination
756 * RETURNS
757 * S_OK.
759 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
761 return _VarUI1FromBool(boolIn, pbOut);
764 /************************************************************************
765 * VarUI1FromI1 (OLEAUT32.237)
767 * Convert a VT_I1 to a VT_UI1.
769 * PARAMS
770 * cIn [I] Source
771 * pbOut [O] Destination
773 * RETURNS
774 * Success: S_OK.
775 * Failure: E_INVALIDARG, if the source value is invalid
776 * DISP_E_OVERFLOW, if the value will not fit in the destination
778 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
780 return _VarUI1FromI1(cIn, pbOut);
783 /************************************************************************
784 * VarUI1FromUI2 (OLEAUT32.238)
786 * Convert a VT_UI2 to a VT_UI1.
788 * PARAMS
789 * usIn [I] Source
790 * pbOut [O] Destination
792 * RETURNS
793 * Success: S_OK.
794 * Failure: E_INVALIDARG, if the source value is invalid
795 * DISP_E_OVERFLOW, if the value will not fit in the destination
797 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
799 return _VarUI1FromUI2(usIn, pbOut);
802 /************************************************************************
803 * VarUI1FromUI4 (OLEAUT32.239)
805 * Convert a VT_UI4 to a VT_UI1.
807 * PARAMS
808 * ulIn [I] Source
809 * pbOut [O] Destination
811 * RETURNS
812 * Success: S_OK.
813 * Failure: E_INVALIDARG, if the source value is invalid
814 * DISP_E_OVERFLOW, if the value will not fit in the destination
816 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
818 return _VarUI1FromUI4(ulIn, pbOut);
821 /************************************************************************
822 * VarUI1FromDec (OLEAUT32.240)
824 * Convert a VT_DECIMAL to a VT_UI1.
826 * PARAMS
827 * pDecIn [I] Source
828 * pbOut [O] Destination
830 * RETURNS
831 * Success: S_OK.
832 * Failure: E_INVALIDARG, if the source value is invalid
833 * DISP_E_OVERFLOW, if the value will not fit in the destination
835 HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut)
837 LONG64 i64;
838 HRESULT hRet;
840 hRet = VarI8FromDec(pdecIn, &i64);
842 if (SUCCEEDED(hRet))
843 hRet = _VarUI1FromI8(i64, pbOut);
844 return hRet;
847 /************************************************************************
848 * VarUI1FromI8 (OLEAUT32.372)
850 * Convert a VT_I8 to a VT_UI1.
852 * PARAMS
853 * llIn [I] Source
854 * pbOut [O] Destination
856 * RETURNS
857 * Success: S_OK.
858 * Failure: E_INVALIDARG, if the source value is invalid
859 * DISP_E_OVERFLOW, if the value will not fit in the destination
861 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
863 return _VarUI1FromI8(llIn, pbOut);
866 /************************************************************************
867 * VarUI1FromUI8 (OLEAUT32.373)
869 * Convert a VT_UI8 to a VT_UI1.
871 * PARAMS
872 * ullIn [I] Source
873 * pbOut [O] Destination
875 * RETURNS
876 * Success: S_OK.
877 * Failure: E_INVALIDARG, if the source value is invalid
878 * DISP_E_OVERFLOW, if the value will not fit in the destination
880 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
882 return _VarUI1FromUI8(ullIn, pbOut);
886 /* I2
889 /************************************************************************
890 * VarI2FromUI1 (OLEAUT32.48)
892 * Convert a VT_UI2 to a VT_I2.
894 * PARAMS
895 * bIn [I] Source
896 * psOut [O] Destination
898 * RETURNS
899 * S_OK.
901 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
903 return _VarI2FromUI1(bIn, psOut);
906 /************************************************************************
907 * VarI2FromI4 (OLEAUT32.49)
909 * Convert a VT_I4 to a VT_I2.
911 * PARAMS
912 * iIn [I] Source
913 * psOut [O] Destination
915 * RETURNS
916 * Success: S_OK.
917 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
919 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
921 return _VarI2FromI4(iIn, psOut);
924 /************************************************************************
925 * VarI2FromR4 (OLEAUT32.50)
927 * Convert a VT_R4 to a VT_I2.
929 * PARAMS
930 * fltIn [I] Source
931 * psOut [O] Destination
933 * RETURNS
934 * Success: S_OK.
935 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
937 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
939 return VarI2FromR8(fltIn, psOut);
942 /************************************************************************
943 * VarI2FromR8 (OLEAUT32.51)
945 * Convert a VT_R8 to a VT_I2.
947 * PARAMS
948 * dblIn [I] Source
949 * psOut [O] Destination
951 * RETURNS
952 * Success: S_OK.
953 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
955 * NOTES
956 * See VarI8FromR8() for details concerning rounding.
958 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
960 if (dblIn < (double)I2_MIN || dblIn > (double)I2_MAX)
961 return DISP_E_OVERFLOW;
962 VARIANT_DutchRound(SHORT, dblIn, *psOut);
963 return S_OK;
966 /************************************************************************
967 * VarI2FromCy (OLEAUT32.52)
969 * Convert a VT_CY to a VT_I2.
971 * PARAMS
972 * cyIn [I] Source
973 * psOut [O] Destination
975 * RETURNS
976 * Success: S_OK.
977 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
979 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
981 LONG i = I2_MAX + 1;
983 VarI4FromCy(cyIn, &i);
984 return _VarI2FromI4(i, psOut);
987 /************************************************************************
988 * VarI2FromDate (OLEAUT32.53)
990 * Convert a VT_DATE to a VT_I2.
992 * PARAMS
993 * dateIn [I] Source
994 * psOut [O] Destination
996 * RETURNS
997 * Success: S_OK.
998 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1000 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
1002 return VarI2FromR8(dateIn, psOut);
1005 /************************************************************************
1006 * VarI2FromStr (OLEAUT32.54)
1008 * Convert a VT_BSTR to a VT_I2.
1010 * PARAMS
1011 * strIn [I] Source
1012 * lcid [I] LCID for the conversion
1013 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1014 * psOut [O] Destination
1016 * RETURNS
1017 * Success: S_OK.
1018 * Failure: E_INVALIDARG, if any parameter is invalid
1019 * DISP_E_OVERFLOW, if the value will not fit in the destination
1020 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1022 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
1024 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
1027 /************************************************************************
1028 * VarI2FromDisp (OLEAUT32.55)
1030 * Convert a VT_DISPATCH to a VT_I2.
1032 * PARAMS
1033 * pdispIn [I] Source
1034 * lcid [I] LCID for conversion
1035 * psOut [O] Destination
1037 * RETURNS
1038 * Success: S_OK.
1039 * Failure: E_INVALIDARG, if pdispIn is invalid,
1040 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1041 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1043 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
1045 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0);
1048 /************************************************************************
1049 * VarI2FromBool (OLEAUT32.56)
1051 * Convert a VT_BOOL to a VT_I2.
1053 * PARAMS
1054 * boolIn [I] Source
1055 * psOut [O] Destination
1057 * RETURNS
1058 * S_OK.
1060 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
1062 return _VarI2FromBool(boolIn, psOut);
1065 /************************************************************************
1066 * VarI2FromI1 (OLEAUT32.205)
1068 * Convert a VT_I1 to a VT_I2.
1070 * PARAMS
1071 * cIn [I] Source
1072 * psOut [O] Destination
1074 * RETURNS
1075 * S_OK.
1077 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
1079 return _VarI2FromI1(cIn, psOut);
1082 /************************************************************************
1083 * VarI2FromUI2 (OLEAUT32.206)
1085 * Convert a VT_UI2 to a VT_I2.
1087 * PARAMS
1088 * usIn [I] Source
1089 * psOut [O] Destination
1091 * RETURNS
1092 * Success: S_OK.
1093 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1095 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
1097 return _VarI2FromUI2(usIn, psOut);
1100 /************************************************************************
1101 * VarI2FromUI4 (OLEAUT32.207)
1103 * Convert a VT_UI4 to a VT_I2.
1105 * PARAMS
1106 * ulIn [I] Source
1107 * psOut [O] Destination
1109 * RETURNS
1110 * Success: S_OK.
1111 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1113 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
1115 return _VarI2FromUI4(ulIn, psOut);
1118 /************************************************************************
1119 * VarI2FromDec (OLEAUT32.208)
1121 * Convert a VT_DECIMAL to a VT_I2.
1123 * PARAMS
1124 * pDecIn [I] Source
1125 * psOut [O] Destination
1127 * RETURNS
1128 * Success: S_OK.
1129 * Failure: E_INVALIDARG, if the source value is invalid
1130 * DISP_E_OVERFLOW, if the value will not fit in the destination
1132 HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut)
1134 LONG64 i64;
1135 HRESULT hRet;
1137 hRet = VarI8FromDec(pdecIn, &i64);
1139 if (SUCCEEDED(hRet))
1140 hRet = _VarI2FromI8(i64, psOut);
1141 return hRet;
1144 /************************************************************************
1145 * VarI2FromI8 (OLEAUT32.346)
1147 * Convert a VT_I8 to a VT_I2.
1149 * PARAMS
1150 * llIn [I] Source
1151 * psOut [O] Destination
1153 * RETURNS
1154 * Success: S_OK.
1155 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1157 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
1159 return _VarI2FromI8(llIn, psOut);
1162 /************************************************************************
1163 * VarI2FromUI8 (OLEAUT32.347)
1165 * Convert a VT_UI8 to a VT_I2.
1167 * PARAMS
1168 * ullIn [I] Source
1169 * psOut [O] Destination
1171 * RETURNS
1172 * Success: S_OK.
1173 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1175 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
1177 return _VarI2FromUI8(ullIn, psOut);
1180 /* UI2
1183 /************************************************************************
1184 * VarUI2FromUI1 (OLEAUT32.257)
1186 * Convert a VT_UI1 to a VT_UI2.
1188 * PARAMS
1189 * bIn [I] Source
1190 * pusOut [O] Destination
1192 * RETURNS
1193 * S_OK.
1195 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
1197 return _VarUI2FromUI1(bIn, pusOut);
1200 /************************************************************************
1201 * VarUI2FromI2 (OLEAUT32.258)
1203 * Convert a VT_I2 to a VT_UI2.
1205 * PARAMS
1206 * sIn [I] Source
1207 * pusOut [O] Destination
1209 * RETURNS
1210 * Success: S_OK.
1211 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1213 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
1215 return _VarUI2FromI2(sIn, pusOut);
1218 /************************************************************************
1219 * VarUI2FromI4 (OLEAUT32.259)
1221 * Convert a VT_I4 to a VT_UI2.
1223 * PARAMS
1224 * iIn [I] Source
1225 * pusOut [O] Destination
1227 * RETURNS
1228 * Success: S_OK.
1229 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1231 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
1233 return _VarUI2FromI4(iIn, pusOut);
1236 /************************************************************************
1237 * VarUI2FromR4 (OLEAUT32.260)
1239 * Convert a VT_R4 to a VT_UI2.
1241 * PARAMS
1242 * fltIn [I] Source
1243 * pusOut [O] Destination
1245 * RETURNS
1246 * Success: S_OK.
1247 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1249 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
1251 return VarUI2FromR8(fltIn, pusOut);
1254 /************************************************************************
1255 * VarUI2FromR8 (OLEAUT32.261)
1257 * Convert a VT_R8 to a VT_UI2.
1259 * PARAMS
1260 * dblIn [I] Source
1261 * pusOut [O] Destination
1263 * RETURNS
1264 * Success: S_OK.
1265 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1267 * NOTES
1268 * See VarI8FromR8() for details concerning rounding.
1270 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
1272 if (dblIn < -0.5 || dblIn > (double)UI2_MAX)
1273 return DISP_E_OVERFLOW;
1274 VARIANT_DutchRound(USHORT, dblIn, *pusOut);
1275 return S_OK;
1278 /************************************************************************
1279 * VarUI2FromDate (OLEAUT32.262)
1281 * Convert a VT_DATE to a VT_UI2.
1283 * PARAMS
1284 * dateIn [I] Source
1285 * pusOut [O] Destination
1287 * RETURNS
1288 * Success: S_OK.
1289 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1291 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
1293 return VarUI2FromR8(dateIn, pusOut);
1296 /************************************************************************
1297 * VarUI2FromCy (OLEAUT32.263)
1299 * Convert a VT_CY to a VT_UI2.
1301 * PARAMS
1302 * cyIn [I] Source
1303 * pusOut [O] Destination
1305 * RETURNS
1306 * Success: S_OK.
1307 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1309 * NOTES
1310 * Negative values >= -5000 will be converted to 0.
1312 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
1314 ULONG i = UI2_MAX + 1;
1316 VarUI4FromCy(cyIn, &i);
1317 return _VarUI2FromUI4(i, pusOut);
1320 /************************************************************************
1321 * VarUI2FromStr (OLEAUT32.264)
1323 * Convert a VT_BSTR to a VT_UI2.
1325 * PARAMS
1326 * strIn [I] Source
1327 * lcid [I] LCID for the conversion
1328 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1329 * pusOut [O] Destination
1331 * RETURNS
1332 * Success: S_OK.
1333 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1334 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1336 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
1338 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
1341 /************************************************************************
1342 * VarUI2FromDisp (OLEAUT32.265)
1344 * Convert a VT_DISPATCH to a VT_UI2.
1346 * PARAMS
1347 * pdispIn [I] Source
1348 * lcid [I] LCID for conversion
1349 * pusOut [O] Destination
1351 * RETURNS
1352 * Success: S_OK.
1353 * Failure: E_INVALIDARG, if the source value is invalid
1354 * DISP_E_OVERFLOW, if the value will not fit in the destination
1355 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1357 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
1359 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0);
1362 /************************************************************************
1363 * VarUI2FromBool (OLEAUT32.266)
1365 * Convert a VT_BOOL to a VT_UI2.
1367 * PARAMS
1368 * boolIn [I] Source
1369 * pusOut [O] Destination
1371 * RETURNS
1372 * S_OK.
1374 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
1376 return _VarUI2FromBool(boolIn, pusOut);
1379 /************************************************************************
1380 * VarUI2FromI1 (OLEAUT32.267)
1382 * Convert a VT_I1 to a VT_UI2.
1384 * PARAMS
1385 * cIn [I] Source
1386 * pusOut [O] Destination
1388 * RETURNS
1389 * Success: S_OK.
1390 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1392 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
1394 return _VarUI2FromI1(cIn, pusOut);
1397 /************************************************************************
1398 * VarUI2FromUI4 (OLEAUT32.268)
1400 * Convert a VT_UI4 to a VT_UI2.
1402 * PARAMS
1403 * ulIn [I] Source
1404 * pusOut [O] Destination
1406 * RETURNS
1407 * Success: S_OK.
1408 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1410 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
1412 return _VarUI2FromUI4(ulIn, pusOut);
1415 /************************************************************************
1416 * VarUI2FromDec (OLEAUT32.269)
1418 * Convert a VT_DECIMAL to a VT_UI2.
1420 * PARAMS
1421 * pDecIn [I] Source
1422 * pusOut [O] Destination
1424 * RETURNS
1425 * Success: S_OK.
1426 * Failure: E_INVALIDARG, if the source value is invalid
1427 * DISP_E_OVERFLOW, if the value will not fit in the destination
1429 HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut)
1431 LONG64 i64;
1432 HRESULT hRet;
1434 hRet = VarI8FromDec(pdecIn, &i64);
1436 if (SUCCEEDED(hRet))
1437 hRet = _VarUI2FromI8(i64, pusOut);
1438 return hRet;
1441 /************************************************************************
1442 * VarUI2FromI8 (OLEAUT32.378)
1444 * Convert a VT_I8 to a VT_UI2.
1446 * PARAMS
1447 * llIn [I] Source
1448 * pusOut [O] Destination
1450 * RETURNS
1451 * Success: S_OK.
1452 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1454 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
1456 return _VarUI2FromI8(llIn, pusOut);
1459 /************************************************************************
1460 * VarUI2FromUI8 (OLEAUT32.379)
1462 * Convert a VT_UI8 to a VT_UI2.
1464 * PARAMS
1465 * ullIn [I] Source
1466 * pusOut [O] Destination
1468 * RETURNS
1469 * Success: S_OK.
1470 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1472 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
1474 return _VarUI2FromUI8(ullIn, pusOut);
1477 /* I4
1480 /************************************************************************
1481 * VarI4FromUI1 (OLEAUT32.58)
1483 * Convert a VT_UI1 to a VT_I4.
1485 * PARAMS
1486 * bIn [I] Source
1487 * piOut [O] Destination
1489 * RETURNS
1490 * S_OK.
1492 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
1494 return _VarI4FromUI1(bIn, piOut);
1497 /************************************************************************
1498 * VarI4FromI2 (OLEAUT32.59)
1500 * Convert a VT_I2 to a VT_I4.
1502 * PARAMS
1503 * sIn [I] Source
1504 * piOut [O] Destination
1506 * RETURNS
1507 * Success: S_OK.
1508 * Failure: E_INVALIDARG, if the source value is invalid
1509 * DISP_E_OVERFLOW, if the value will not fit in the destination
1511 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
1513 return _VarI4FromI2(sIn, piOut);
1516 /************************************************************************
1517 * VarI4FromR4 (OLEAUT32.60)
1519 * Convert a VT_R4 to a VT_I4.
1521 * PARAMS
1522 * fltIn [I] Source
1523 * piOut [O] Destination
1525 * RETURNS
1526 * Success: S_OK.
1527 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1529 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
1531 return VarI4FromR8(fltIn, piOut);
1534 /************************************************************************
1535 * VarI4FromR8 (OLEAUT32.61)
1537 * Convert a VT_R8 to a VT_I4.
1539 * PARAMS
1540 * dblIn [I] Source
1541 * piOut [O] Destination
1543 * RETURNS
1544 * Success: S_OK.
1545 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1547 * NOTES
1548 * See VarI8FromR8() for details concerning rounding.
1550 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
1552 if (dblIn < (double)I4_MIN || dblIn > (double)I4_MAX)
1553 return DISP_E_OVERFLOW;
1554 VARIANT_DutchRound(LONG, dblIn, *piOut);
1555 return S_OK;
1558 /************************************************************************
1559 * VarI4FromCy (OLEAUT32.62)
1561 * Convert a VT_CY to a VT_I4.
1563 * PARAMS
1564 * cyIn [I] Source
1565 * piOut [O] Destination
1567 * RETURNS
1568 * Success: S_OK.
1569 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1571 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
1573 double d = cyIn.int64 / CY_MULTIPLIER_F;
1574 return VarI4FromR8(d, piOut);
1577 /************************************************************************
1578 * VarI4FromDate (OLEAUT32.63)
1580 * Convert a VT_DATE to a VT_I4.
1582 * PARAMS
1583 * dateIn [I] Source
1584 * piOut [O] Destination
1586 * RETURNS
1587 * Success: S_OK.
1588 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1590 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
1592 return VarI4FromR8(dateIn, piOut);
1595 /************************************************************************
1596 * VarI4FromStr (OLEAUT32.64)
1598 * Convert a VT_BSTR to a VT_I4.
1600 * PARAMS
1601 * strIn [I] Source
1602 * lcid [I] LCID for the conversion
1603 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1604 * piOut [O] Destination
1606 * RETURNS
1607 * Success: S_OK.
1608 * Failure: E_INVALIDARG, if any parameter is invalid
1609 * DISP_E_OVERFLOW, if the value will not fit in the destination
1610 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1612 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
1614 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
1617 /************************************************************************
1618 * VarI4FromDisp (OLEAUT32.65)
1620 * Convert a VT_DISPATCH to a VT_I4.
1622 * PARAMS
1623 * pdispIn [I] Source
1624 * lcid [I] LCID for conversion
1625 * piOut [O] Destination
1627 * RETURNS
1628 * Success: S_OK.
1629 * Failure: E_INVALIDARG, if the source value is invalid
1630 * DISP_E_OVERFLOW, if the value will not fit in the destination
1631 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1633 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
1635 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0);
1638 /************************************************************************
1639 * VarI4FromBool (OLEAUT32.66)
1641 * Convert a VT_BOOL to a VT_I4.
1643 * PARAMS
1644 * boolIn [I] Source
1645 * piOut [O] Destination
1647 * RETURNS
1648 * S_OK.
1650 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
1652 return _VarI4FromBool(boolIn, piOut);
1655 /************************************************************************
1656 * VarI4FromI1 (OLEAUT32.209)
1658 * Convert a VT_I4 to a VT_I4.
1660 * PARAMS
1661 * cIn [I] Source
1662 * piOut [O] Destination
1664 * RETURNS
1665 * S_OK.
1667 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
1669 return _VarI4FromI1(cIn, piOut);
1672 /************************************************************************
1673 * VarI4FromUI2 (OLEAUT32.210)
1675 * Convert a VT_UI2 to a VT_I4.
1677 * PARAMS
1678 * usIn [I] Source
1679 * piOut [O] Destination
1681 * RETURNS
1682 * S_OK.
1684 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
1686 return _VarI4FromUI2(usIn, piOut);
1689 /************************************************************************
1690 * VarI4FromUI4 (OLEAUT32.211)
1692 * Convert a VT_UI4 to a VT_I4.
1694 * PARAMS
1695 * ulIn [I] Source
1696 * piOut [O] Destination
1698 * RETURNS
1699 * Success: S_OK.
1700 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1702 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
1704 return _VarI4FromUI4(ulIn, piOut);
1707 /************************************************************************
1708 * VarI4FromDec (OLEAUT32.212)
1710 * Convert a VT_DECIMAL to a VT_I4.
1712 * PARAMS
1713 * pDecIn [I] Source
1714 * piOut [O] Destination
1716 * RETURNS
1717 * Success: S_OK.
1718 * Failure: E_INVALIDARG, if pdecIn is invalid
1719 * DISP_E_OVERFLOW, if the value will not fit in the destination
1721 HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut)
1723 LONG64 i64;
1724 HRESULT hRet;
1726 hRet = VarI8FromDec(pdecIn, &i64);
1728 if (SUCCEEDED(hRet))
1729 hRet = _VarI4FromI8(i64, piOut);
1730 return hRet;
1733 /************************************************************************
1734 * VarI4FromI8 (OLEAUT32.348)
1736 * Convert a VT_I8 to a VT_I4.
1738 * PARAMS
1739 * llIn [I] Source
1740 * piOut [O] Destination
1742 * RETURNS
1743 * Success: S_OK.
1744 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1746 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
1748 return _VarI4FromI8(llIn, piOut);
1751 /************************************************************************
1752 * VarI4FromUI8 (OLEAUT32.349)
1754 * Convert a VT_UI8 to a VT_I4.
1756 * PARAMS
1757 * ullIn [I] Source
1758 * piOut [O] Destination
1760 * RETURNS
1761 * Success: S_OK.
1762 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1764 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
1766 return _VarI4FromUI8(ullIn, piOut);
1769 /* UI4
1772 /************************************************************************
1773 * VarUI4FromUI1 (OLEAUT32.270)
1775 * Convert a VT_UI1 to a VT_UI4.
1777 * PARAMS
1778 * bIn [I] Source
1779 * pulOut [O] Destination
1781 * RETURNS
1782 * S_OK.
1784 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
1786 return _VarUI4FromUI1(bIn, pulOut);
1789 /************************************************************************
1790 * VarUI4FromI2 (OLEAUT32.271)
1792 * Convert a VT_I2 to a VT_UI4.
1794 * PARAMS
1795 * sIn [I] Source
1796 * pulOut [O] Destination
1798 * RETURNS
1799 * Success: S_OK.
1800 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1802 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
1804 return _VarUI4FromI2(sIn, pulOut);
1807 /************************************************************************
1808 * VarUI4FromI4 (OLEAUT32.272)
1810 * Convert a VT_I4 to a VT_UI4.
1812 * PARAMS
1813 * iIn [I] Source
1814 * pulOut [O] Destination
1816 * RETURNS
1817 * Success: S_OK.
1818 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1820 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
1822 return _VarUI4FromI4(iIn, pulOut);
1825 /************************************************************************
1826 * VarUI4FromR4 (OLEAUT32.273)
1828 * Convert a VT_R4 to a VT_UI4.
1830 * PARAMS
1831 * fltIn [I] Source
1832 * pulOut [O] Destination
1834 * RETURNS
1835 * Success: S_OK.
1836 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1838 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
1840 return VarUI4FromR8(fltIn, pulOut);
1843 /************************************************************************
1844 * VarUI4FromR8 (OLEAUT32.274)
1846 * Convert a VT_R8 to a VT_UI4.
1848 * PARAMS
1849 * dblIn [I] Source
1850 * pulOut [O] Destination
1852 * RETURNS
1853 * Success: S_OK.
1854 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1856 * NOTES
1857 * See VarI8FromR8() for details concerning rounding.
1859 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
1861 if (dblIn < -0.5 || dblIn > (double)UI4_MAX)
1862 return DISP_E_OVERFLOW;
1863 VARIANT_DutchRound(ULONG, dblIn, *pulOut);
1864 return S_OK;
1867 /************************************************************************
1868 * VarUI4FromDate (OLEAUT32.275)
1870 * Convert a VT_DATE to a VT_UI4.
1872 * PARAMS
1873 * dateIn [I] Source
1874 * pulOut [O] Destination
1876 * RETURNS
1877 * Success: S_OK.
1878 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1880 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
1882 return VarUI4FromR8(dateIn, pulOut);
1885 /************************************************************************
1886 * VarUI4FromCy (OLEAUT32.276)
1888 * Convert a VT_CY to a VT_UI4.
1890 * PARAMS
1891 * cyIn [I] Source
1892 * pulOut [O] Destination
1894 * RETURNS
1895 * Success: S_OK.
1896 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1898 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
1900 double d = cyIn.int64 / CY_MULTIPLIER_F;
1901 return VarUI4FromR8(d, pulOut);
1904 /************************************************************************
1905 * VarUI4FromStr (OLEAUT32.277)
1907 * Convert a VT_BSTR to a VT_UI4.
1909 * PARAMS
1910 * strIn [I] Source
1911 * lcid [I] LCID for the conversion
1912 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1913 * pulOut [O] Destination
1915 * RETURNS
1916 * Success: S_OK.
1917 * Failure: E_INVALIDARG, if any parameter is invalid
1918 * DISP_E_OVERFLOW, if the value will not fit in the destination
1919 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1921 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
1923 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
1926 /************************************************************************
1927 * VarUI4FromDisp (OLEAUT32.278)
1929 * Convert a VT_DISPATCH to a VT_UI4.
1931 * PARAMS
1932 * pdispIn [I] Source
1933 * lcid [I] LCID for conversion
1934 * pulOut [O] Destination
1936 * RETURNS
1937 * Success: S_OK.
1938 * Failure: E_INVALIDARG, if the source value is invalid
1939 * DISP_E_OVERFLOW, if the value will not fit in the destination
1940 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1942 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
1944 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0);
1947 /************************************************************************
1948 * VarUI4FromBool (OLEAUT32.279)
1950 * Convert a VT_BOOL to a VT_UI4.
1952 * PARAMS
1953 * boolIn [I] Source
1954 * pulOut [O] Destination
1956 * RETURNS
1957 * S_OK.
1959 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
1961 return _VarUI4FromBool(boolIn, pulOut);
1964 /************************************************************************
1965 * VarUI4FromI1 (OLEAUT32.280)
1967 * Convert a VT_I1 to a VT_UI4.
1969 * PARAMS
1970 * cIn [I] Source
1971 * pulOut [O] Destination
1973 * RETURNS
1974 * Success: S_OK.
1975 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1977 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
1979 return _VarUI4FromI1(cIn, pulOut);
1982 /************************************************************************
1983 * VarUI4FromUI2 (OLEAUT32.281)
1985 * Convert a VT_UI2 to a VT_UI4.
1987 * PARAMS
1988 * usIn [I] Source
1989 * pulOut [O] Destination
1991 * RETURNS
1992 * S_OK.
1994 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
1996 return _VarUI4FromUI2(usIn, pulOut);
1999 /************************************************************************
2000 * VarUI4FromDec (OLEAUT32.282)
2002 * Convert a VT_DECIMAL to a VT_UI4.
2004 * PARAMS
2005 * pDecIn [I] Source
2006 * pulOut [O] Destination
2008 * RETURNS
2009 * Success: S_OK.
2010 * Failure: E_INVALIDARG, if pdecIn is invalid
2011 * DISP_E_OVERFLOW, if the value will not fit in the destination
2013 HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut)
2015 LONG64 i64;
2016 HRESULT hRet;
2018 hRet = VarI8FromDec(pdecIn, &i64);
2020 if (SUCCEEDED(hRet))
2021 hRet = _VarUI4FromI8(i64, pulOut);
2022 return hRet;
2025 /************************************************************************
2026 * VarUI4FromI8 (OLEAUT32.425)
2028 * Convert a VT_I8 to a VT_UI4.
2030 * PARAMS
2031 * llIn [I] Source
2032 * pulOut [O] Destination
2034 * RETURNS
2035 * Success: S_OK.
2036 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2038 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
2040 return _VarUI4FromI8(llIn, pulOut);
2043 /************************************************************************
2044 * VarUI4FromUI8 (OLEAUT32.426)
2046 * Convert a VT_UI8 to a VT_UI4.
2048 * PARAMS
2049 * ullIn [I] Source
2050 * pulOut [O] Destination
2052 * RETURNS
2053 * Success: S_OK.
2054 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2056 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
2058 return _VarUI4FromUI8(ullIn, pulOut);
2061 /* I8
2064 /************************************************************************
2065 * VarI8FromUI1 (OLEAUT32.333)
2067 * Convert a VT_UI1 to a VT_I8.
2069 * PARAMS
2070 * bIn [I] Source
2071 * pi64Out [O] Destination
2073 * RETURNS
2074 * S_OK.
2076 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
2078 return _VarI8FromUI1(bIn, pi64Out);
2082 /************************************************************************
2083 * VarI8FromI2 (OLEAUT32.334)
2085 * Convert a VT_I2 to a VT_I8.
2087 * PARAMS
2088 * sIn [I] Source
2089 * pi64Out [O] Destination
2091 * RETURNS
2092 * S_OK.
2094 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
2096 return _VarI8FromI2(sIn, pi64Out);
2099 /************************************************************************
2100 * VarI8FromR4 (OLEAUT32.335)
2102 * Convert a VT_R4 to a VT_I8.
2104 * PARAMS
2105 * fltIn [I] Source
2106 * pi64Out [O] Destination
2108 * RETURNS
2109 * Success: S_OK.
2110 * Failure: E_INVALIDARG, if the source value is invalid
2111 * DISP_E_OVERFLOW, if the value will not fit in the destination
2113 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
2115 return VarI8FromR8(fltIn, pi64Out);
2118 /************************************************************************
2119 * VarI8FromR8 (OLEAUT32.336)
2121 * Convert a VT_R8 to a VT_I8.
2123 * PARAMS
2124 * dblIn [I] Source
2125 * pi64Out [O] Destination
2127 * RETURNS
2128 * Success: S_OK.
2129 * Failure: E_INVALIDARG, if the source value is invalid
2130 * DISP_E_OVERFLOW, if the value will not fit in the destination
2132 * NOTES
2133 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2134 * very high or low values will not be accurately converted.
2136 * Numbers are rounded using Dutch rounding, as follows:
2138 *| Fractional Part Sign Direction Example
2139 *| --------------- ---- --------- -------
2140 *| < 0.5 + Down 0.4 -> 0.0
2141 *| < 0.5 - Up -0.4 -> 0.0
2142 *| > 0.5 + Up 0.6 -> 1.0
2143 *| < 0.5 - Up -0.6 -> -1.0
2144 *| = 0.5 + Up/Down Down if even, Up if odd
2145 *| = 0.5 - Up/Down Up if even, Down if odd
2147 * This system is often used in supermarkets.
2149 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
2151 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
2152 return DISP_E_OVERFLOW;
2153 VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
2154 return S_OK;
2157 /************************************************************************
2158 * VarI8FromCy (OLEAUT32.337)
2160 * Convert a VT_CY to a VT_I8.
2162 * PARAMS
2163 * cyIn [I] Source
2164 * pi64Out [O] Destination
2166 * RETURNS
2167 * S_OK.
2169 * NOTES
2170 * All negative numbers are rounded down by 1, including those that are
2171 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2172 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2173 * for details.
2175 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
2177 *pi64Out = cyIn.int64 / CY_MULTIPLIER;
2179 if (cyIn.int64 < 0)
2180 (*pi64Out)--; /* Mimic Win32 bug */
2181 else
2183 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2185 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1)))
2186 (*pi64Out)++;
2188 return S_OK;
2191 /************************************************************************
2192 * VarI8FromDate (OLEAUT32.338)
2194 * Convert a VT_DATE to a VT_I8.
2196 * PARAMS
2197 * dateIn [I] Source
2198 * pi64Out [O] Destination
2200 * RETURNS
2201 * Success: S_OK.
2202 * Failure: E_INVALIDARG, if the source value is invalid
2203 * DISP_E_OVERFLOW, if the value will not fit in the destination
2204 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2206 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
2208 return VarI8FromR8(dateIn, pi64Out);
2211 /************************************************************************
2212 * VarI8FromStr (OLEAUT32.339)
2214 * Convert a VT_BSTR to a VT_I8.
2216 * PARAMS
2217 * strIn [I] Source
2218 * lcid [I] LCID for the conversion
2219 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2220 * pi64Out [O] Destination
2222 * RETURNS
2223 * Success: S_OK.
2224 * Failure: E_INVALIDARG, if the source value is invalid
2225 * DISP_E_OVERFLOW, if the value will not fit in the destination
2226 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2228 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
2230 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
2233 /************************************************************************
2234 * VarI8FromDisp (OLEAUT32.340)
2236 * Convert a VT_DISPATCH to a VT_I8.
2238 * PARAMS
2239 * pdispIn [I] Source
2240 * lcid [I] LCID for conversion
2241 * pi64Out [O] Destination
2243 * RETURNS
2244 * Success: S_OK.
2245 * Failure: E_INVALIDARG, if the source value is invalid
2246 * DISP_E_OVERFLOW, if the value will not fit in the destination
2247 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2249 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
2251 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0);
2254 /************************************************************************
2255 * VarI8FromBool (OLEAUT32.341)
2257 * Convert a VT_BOOL to a VT_I8.
2259 * PARAMS
2260 * boolIn [I] Source
2261 * pi64Out [O] Destination
2263 * RETURNS
2264 * S_OK.
2266 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
2268 return VarI8FromI2(boolIn, pi64Out);
2271 /************************************************************************
2272 * VarI8FromI1 (OLEAUT32.342)
2274 * Convert a VT_I1 to a VT_I8.
2276 * PARAMS
2277 * cIn [I] Source
2278 * pi64Out [O] Destination
2280 * RETURNS
2281 * S_OK.
2283 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
2285 return _VarI8FromI1(cIn, pi64Out);
2288 /************************************************************************
2289 * VarI8FromUI2 (OLEAUT32.343)
2291 * Convert a VT_UI2 to a VT_I8.
2293 * PARAMS
2294 * usIn [I] Source
2295 * pi64Out [O] Destination
2297 * RETURNS
2298 * S_OK.
2300 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
2302 return _VarI8FromUI2(usIn, pi64Out);
2305 /************************************************************************
2306 * VarI8FromUI4 (OLEAUT32.344)
2308 * Convert a VT_UI4 to a VT_I8.
2310 * PARAMS
2311 * ulIn [I] Source
2312 * pi64Out [O] Destination
2314 * RETURNS
2315 * S_OK.
2317 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
2319 return _VarI8FromUI4(ulIn, pi64Out);
2322 /************************************************************************
2323 * VarI8FromDec (OLEAUT32.345)
2325 * Convert a VT_DECIMAL to a VT_I8.
2327 * PARAMS
2328 * pDecIn [I] Source
2329 * pi64Out [O] Destination
2331 * RETURNS
2332 * Success: S_OK.
2333 * Failure: E_INVALIDARG, if the source value is invalid
2334 * DISP_E_OVERFLOW, if the value will not fit in the destination
2336 HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out)
2338 if (!DEC_SCALE(pdecIn))
2340 /* This decimal is just a 96 bit integer */
2341 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2342 return E_INVALIDARG;
2344 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000)
2345 return DISP_E_OVERFLOW;
2347 if (DEC_SIGN(pdecIn))
2348 *pi64Out = -DEC_LO64(pdecIn);
2349 else
2350 *pi64Out = DEC_LO64(pdecIn);
2351 return S_OK;
2353 else
2355 /* Decimal contains a floating point number */
2356 HRESULT hRet;
2357 double dbl;
2359 hRet = VarR8FromDec(pdecIn, &dbl);
2360 if (SUCCEEDED(hRet))
2361 hRet = VarI8FromR8(dbl, pi64Out);
2362 return hRet;
2366 /************************************************************************
2367 * VarI8FromUI8 (OLEAUT32.427)
2369 * Convert a VT_UI8 to a VT_I8.
2371 * PARAMS
2372 * ullIn [I] Source
2373 * pi64Out [O] Destination
2375 * RETURNS
2376 * Success: S_OK.
2377 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2379 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
2381 return _VarI8FromUI8(ullIn, pi64Out);
2384 /* UI8
2387 /************************************************************************
2388 * VarUI8FromI8 (OLEAUT32.428)
2390 * Convert a VT_I8 to a VT_UI8.
2392 * PARAMS
2393 * ulIn [I] Source
2394 * pui64Out [O] Destination
2396 * RETURNS
2397 * Success: S_OK.
2398 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2400 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
2402 return _VarUI8FromI8(llIn, pui64Out);
2405 /************************************************************************
2406 * VarUI8FromUI1 (OLEAUT32.429)
2408 * Convert a VT_UI1 to a VT_UI8.
2410 * PARAMS
2411 * bIn [I] Source
2412 * pui64Out [O] Destination
2414 * RETURNS
2415 * S_OK.
2417 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
2419 return _VarUI8FromUI1(bIn, pui64Out);
2422 /************************************************************************
2423 * VarUI8FromI2 (OLEAUT32.430)
2425 * Convert a VT_I2 to a VT_UI8.
2427 * PARAMS
2428 * sIn [I] Source
2429 * pui64Out [O] Destination
2431 * RETURNS
2432 * S_OK.
2434 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
2436 return _VarUI8FromI2(sIn, pui64Out);
2439 /************************************************************************
2440 * VarUI8FromR4 (OLEAUT32.431)
2442 * Convert a VT_R4 to a VT_UI8.
2444 * PARAMS
2445 * fltIn [I] Source
2446 * pui64Out [O] Destination
2448 * RETURNS
2449 * Success: S_OK.
2450 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2452 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
2454 return VarUI8FromR8(fltIn, pui64Out);
2457 /************************************************************************
2458 * VarUI8FromR8 (OLEAUT32.432)
2460 * Convert a VT_R8 to a VT_UI8.
2462 * PARAMS
2463 * dblIn [I] Source
2464 * pui64Out [O] Destination
2466 * RETURNS
2467 * Success: S_OK.
2468 * Failure: E_INVALIDARG, if the source value is invalid
2469 * DISP_E_OVERFLOW, if the value will not fit in the destination
2471 * NOTES
2472 * See VarI8FromR8() for details concerning rounding.
2474 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
2476 if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
2477 return DISP_E_OVERFLOW;
2478 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
2479 return S_OK;
2482 /************************************************************************
2483 * VarUI8FromCy (OLEAUT32.433)
2485 * Convert a VT_CY to a VT_UI8.
2487 * PARAMS
2488 * cyIn [I] Source
2489 * pui64Out [O] Destination
2491 * RETURNS
2492 * Success: S_OK.
2493 * Failure: E_INVALIDARG, if the source value is invalid
2494 * DISP_E_OVERFLOW, if the value will not fit in the destination
2496 * NOTES
2497 * Negative values >= -5000 will be converted to 0.
2499 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
2501 if (cyIn.int64 < 0)
2503 if (cyIn.int64 < -CY_HALF)
2504 return DISP_E_OVERFLOW;
2505 *pui64Out = 0;
2507 else
2509 *pui64Out = cyIn.int64 / CY_MULTIPLIER;
2511 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2513 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1)))
2514 (*pui64Out)++;
2516 return S_OK;
2519 /************************************************************************
2520 * VarUI8FromDate (OLEAUT32.434)
2522 * Convert a VT_DATE to a VT_UI8.
2524 * PARAMS
2525 * dateIn [I] Source
2526 * pui64Out [O] Destination
2528 * RETURNS
2529 * Success: S_OK.
2530 * Failure: E_INVALIDARG, if the source value is invalid
2531 * DISP_E_OVERFLOW, if the value will not fit in the destination
2532 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2534 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
2536 return VarUI8FromR8(dateIn, pui64Out);
2539 /************************************************************************
2540 * VarUI8FromStr (OLEAUT32.435)
2542 * Convert a VT_BSTR to a VT_UI8.
2544 * PARAMS
2545 * strIn [I] Source
2546 * lcid [I] LCID for the conversion
2547 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2548 * pui64Out [O] Destination
2550 * RETURNS
2551 * Success: S_OK.
2552 * Failure: E_INVALIDARG, if the source value is invalid
2553 * DISP_E_OVERFLOW, if the value will not fit in the destination
2554 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2556 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
2558 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
2561 /************************************************************************
2562 * VarUI8FromDisp (OLEAUT32.436)
2564 * Convert a VT_DISPATCH to a VT_UI8.
2566 * PARAMS
2567 * pdispIn [I] Source
2568 * lcid [I] LCID for conversion
2569 * pui64Out [O] Destination
2571 * RETURNS
2572 * Success: S_OK.
2573 * Failure: E_INVALIDARG, if the source value is invalid
2574 * DISP_E_OVERFLOW, if the value will not fit in the destination
2575 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2577 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
2579 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0);
2582 /************************************************************************
2583 * VarUI8FromBool (OLEAUT32.437)
2585 * Convert a VT_BOOL to a VT_UI8.
2587 * PARAMS
2588 * boolIn [I] Source
2589 * pui64Out [O] Destination
2591 * RETURNS
2592 * Success: S_OK.
2593 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2595 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
2597 return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
2599 /************************************************************************
2600 * VarUI8FromI1 (OLEAUT32.438)
2602 * Convert a VT_I1 to a VT_UI8.
2604 * PARAMS
2605 * cIn [I] Source
2606 * pui64Out [O] Destination
2608 * RETURNS
2609 * Success: S_OK.
2610 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2612 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
2614 return _VarUI8FromI1(cIn, pui64Out);
2617 /************************************************************************
2618 * VarUI8FromUI2 (OLEAUT32.439)
2620 * Convert a VT_UI2 to a VT_UI8.
2622 * PARAMS
2623 * usIn [I] Source
2624 * pui64Out [O] Destination
2626 * RETURNS
2627 * S_OK.
2629 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
2631 return _VarUI8FromUI2(usIn, pui64Out);
2634 /************************************************************************
2635 * VarUI8FromUI4 (OLEAUT32.440)
2637 * Convert a VT_UI4 to a VT_UI8.
2639 * PARAMS
2640 * ulIn [I] Source
2641 * pui64Out [O] Destination
2643 * RETURNS
2644 * S_OK.
2646 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
2648 return _VarUI8FromUI4(ulIn, pui64Out);
2651 /************************************************************************
2652 * VarUI8FromDec (OLEAUT32.441)
2654 * Convert a VT_DECIMAL to a VT_UI8.
2656 * PARAMS
2657 * pDecIn [I] Source
2658 * pui64Out [O] Destination
2660 * RETURNS
2661 * Success: S_OK.
2662 * Failure: E_INVALIDARG, if the source value is invalid
2663 * DISP_E_OVERFLOW, if the value will not fit in the destination
2665 * NOTES
2666 * Under native Win32, if the source value has a scale of 0, its sign is
2667 * ignored, i.e. this function takes the absolute value rather than fail
2668 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2669 * (use VarAbs() on pDecIn first if you really want this behaviour).
2671 HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out)
2673 if (!DEC_SCALE(pdecIn))
2675 /* This decimal is just a 96 bit integer */
2676 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2677 return E_INVALIDARG;
2679 if (DEC_HI32(pdecIn))
2680 return DISP_E_OVERFLOW;
2682 if (DEC_SIGN(pdecIn))
2684 WARN("Sign would be ignored under Win32!\n");
2685 return DISP_E_OVERFLOW;
2688 *pui64Out = DEC_LO64(pdecIn);
2689 return S_OK;
2691 else
2693 /* Decimal contains a floating point number */
2694 HRESULT hRet;
2695 double dbl;
2697 hRet = VarR8FromDec(pdecIn, &dbl);
2698 if (SUCCEEDED(hRet))
2699 hRet = VarUI8FromR8(dbl, pui64Out);
2700 return hRet;
2704 /* R4
2707 /************************************************************************
2708 * VarR4FromUI1 (OLEAUT32.68)
2710 * Convert a VT_UI1 to a VT_R4.
2712 * PARAMS
2713 * bIn [I] Source
2714 * pFltOut [O] Destination
2716 * RETURNS
2717 * S_OK.
2719 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
2721 return _VarR4FromUI1(bIn, pFltOut);
2724 /************************************************************************
2725 * VarR4FromI2 (OLEAUT32.69)
2727 * Convert a VT_I2 to a VT_R4.
2729 * PARAMS
2730 * sIn [I] Source
2731 * pFltOut [O] Destination
2733 * RETURNS
2734 * S_OK.
2736 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
2738 return _VarR4FromI2(sIn, pFltOut);
2741 /************************************************************************
2742 * VarR4FromI4 (OLEAUT32.70)
2744 * Convert a VT_I4 to a VT_R4.
2746 * PARAMS
2747 * sIn [I] Source
2748 * pFltOut [O] Destination
2750 * RETURNS
2751 * S_OK.
2753 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
2755 return _VarR4FromI4(lIn, pFltOut);
2758 /************************************************************************
2759 * VarR4FromR8 (OLEAUT32.71)
2761 * Convert a VT_R8 to a VT_R4.
2763 * PARAMS
2764 * dblIn [I] Source
2765 * pFltOut [O] Destination
2767 * RETURNS
2768 * Success: S_OK.
2769 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2771 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
2773 double d = dblIn < 0.0 ? -dblIn : dblIn;
2774 if (d > R4_MAX) return DISP_E_OVERFLOW;
2775 *pFltOut = dblIn;
2776 return S_OK;
2779 /************************************************************************
2780 * VarR4FromCy (OLEAUT32.72)
2782 * Convert a VT_CY to a VT_R4.
2784 * PARAMS
2785 * cyIn [I] Source
2786 * pFltOut [O] Destination
2788 * RETURNS
2789 * S_OK.
2791 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
2793 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
2794 return S_OK;
2797 /************************************************************************
2798 * VarR4FromDate (OLEAUT32.73)
2800 * Convert a VT_DATE to a VT_R4.
2802 * PARAMS
2803 * dateIn [I] Source
2804 * pFltOut [O] Destination
2806 * RETURNS
2807 * Success: S_OK.
2808 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2810 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
2812 return VarR4FromR8(dateIn, pFltOut);
2815 /************************************************************************
2816 * VarR4FromStr (OLEAUT32.74)
2818 * Convert a VT_BSTR to a VT_R4.
2820 * PARAMS
2821 * strIn [I] Source
2822 * lcid [I] LCID for the conversion
2823 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2824 * pFltOut [O] Destination
2826 * RETURNS
2827 * Success: S_OK.
2828 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2829 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2831 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
2833 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
2836 /************************************************************************
2837 * VarR4FromDisp (OLEAUT32.75)
2839 * Convert a VT_DISPATCH to a VT_R4.
2841 * PARAMS
2842 * pdispIn [I] Source
2843 * lcid [I] LCID for conversion
2844 * pFltOut [O] Destination
2846 * RETURNS
2847 * Success: S_OK.
2848 * Failure: E_INVALIDARG, if the source value is invalid
2849 * DISP_E_OVERFLOW, if the value will not fit in the destination
2850 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2852 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
2854 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0);
2857 /************************************************************************
2858 * VarR4FromBool (OLEAUT32.76)
2860 * Convert a VT_BOOL to a VT_R4.
2862 * PARAMS
2863 * boolIn [I] Source
2864 * pFltOut [O] Destination
2866 * RETURNS
2867 * S_OK.
2869 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2871 return VarR4FromI2(boolIn, pFltOut);
2874 /************************************************************************
2875 * VarR4FromI1 (OLEAUT32.213)
2877 * Convert a VT_I1 to a VT_R4.
2879 * PARAMS
2880 * cIn [I] Source
2881 * pFltOut [O] Destination
2883 * RETURNS
2884 * Success: S_OK.
2885 * Failure: E_INVALIDARG, if the source value is invalid
2886 * DISP_E_OVERFLOW, if the value will not fit in the destination
2887 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2889 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2891 return _VarR4FromI1(cIn, pFltOut);
2894 /************************************************************************
2895 * VarR4FromUI2 (OLEAUT32.214)
2897 * Convert a VT_UI2 to a VT_R4.
2899 * PARAMS
2900 * usIn [I] Source
2901 * pFltOut [O] Destination
2903 * RETURNS
2904 * Success: S_OK.
2905 * Failure: E_INVALIDARG, if the source value is invalid
2906 * DISP_E_OVERFLOW, if the value will not fit in the destination
2907 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2909 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2911 return _VarR4FromUI2(usIn, pFltOut);
2914 /************************************************************************
2915 * VarR4FromUI4 (OLEAUT32.215)
2917 * Convert a VT_UI4 to a VT_R4.
2919 * PARAMS
2920 * ulIn [I] Source
2921 * pFltOut [O] Destination
2923 * RETURNS
2924 * Success: S_OK.
2925 * Failure: E_INVALIDARG, if the source value is invalid
2926 * DISP_E_OVERFLOW, if the value will not fit in the destination
2927 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2929 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2931 return _VarR4FromUI4(ulIn, pFltOut);
2934 /************************************************************************
2935 * VarR4FromDec (OLEAUT32.216)
2937 * Convert a VT_DECIMAL to a VT_R4.
2939 * PARAMS
2940 * pDecIn [I] Source
2941 * pFltOut [O] Destination
2943 * RETURNS
2944 * Success: S_OK.
2945 * Failure: E_INVALIDARG, if the source value is invalid.
2947 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
2949 BYTE scale = DEC_SCALE(pDecIn);
2950 int divisor = 1;
2951 double highPart;
2953 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2954 return E_INVALIDARG;
2956 while (scale--)
2957 divisor *= 10;
2959 if (DEC_SIGN(pDecIn))
2960 divisor = -divisor;
2962 if (DEC_HI32(pDecIn))
2964 highPart = (double)DEC_HI32(pDecIn) / (double)divisor;
2965 highPart *= 4294967296.0F;
2966 highPart *= 4294967296.0F;
2968 else
2969 highPart = 0.0;
2971 *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart;
2972 return S_OK;
2975 /************************************************************************
2976 * VarR4FromI8 (OLEAUT32.360)
2978 * Convert a VT_I8 to a VT_R4.
2980 * PARAMS
2981 * ullIn [I] Source
2982 * pFltOut [O] Destination
2984 * RETURNS
2985 * S_OK.
2987 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2989 return _VarR4FromI8(llIn, pFltOut);
2992 /************************************************************************
2993 * VarR4FromUI8 (OLEAUT32.361)
2995 * Convert a VT_UI8 to a VT_R4.
2997 * PARAMS
2998 * ullIn [I] Source
2999 * pFltOut [O] Destination
3001 * RETURNS
3002 * S_OK.
3004 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
3006 return _VarR4FromUI8(ullIn, pFltOut);
3009 /************************************************************************
3010 * VarR4CmpR8 (OLEAUT32.316)
3012 * Compare a VT_R4 to a VT_R8.
3014 * PARAMS
3015 * fltLeft [I] Source
3016 * dblRight [I] Value to compare
3018 * RETURNS
3019 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3020 * equal to or greater than dblRight respectively.
3022 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3024 if (fltLeft < dblRight)
3025 return VARCMP_LT;
3026 else if (fltLeft > dblRight)
3027 return VARCMP_GT;
3028 return VARCMP_EQ;
3031 /* R8
3034 /************************************************************************
3035 * VarR8FromUI1 (OLEAUT32.78)
3037 * Convert a VT_UI1 to a VT_R8.
3039 * PARAMS
3040 * bIn [I] Source
3041 * pDblOut [O] Destination
3043 * RETURNS
3044 * S_OK.
3046 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3048 return _VarR8FromUI1(bIn, pDblOut);
3051 /************************************************************************
3052 * VarR8FromI2 (OLEAUT32.79)
3054 * Convert a VT_I2 to a VT_R8.
3056 * PARAMS
3057 * sIn [I] Source
3058 * pDblOut [O] Destination
3060 * RETURNS
3061 * S_OK.
3063 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3065 return _VarR8FromI2(sIn, pDblOut);
3068 /************************************************************************
3069 * VarR8FromI4 (OLEAUT32.80)
3071 * Convert a VT_I4 to a VT_R8.
3073 * PARAMS
3074 * sIn [I] Source
3075 * pDblOut [O] Destination
3077 * RETURNS
3078 * S_OK.
3080 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3082 return _VarR8FromI4(lIn, pDblOut);
3085 /************************************************************************
3086 * VarR8FromR4 (OLEAUT32.81)
3088 * Convert a VT_R4 to a VT_R8.
3090 * PARAMS
3091 * fltIn [I] Source
3092 * pDblOut [O] Destination
3094 * RETURNS
3095 * S_OK.
3097 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3099 return _VarR8FromR4(fltIn, pDblOut);
3102 /************************************************************************
3103 * VarR8FromCy (OLEAUT32.82)
3105 * Convert a VT_CY to a VT_R8.
3107 * PARAMS
3108 * cyIn [I] Source
3109 * pDblOut [O] Destination
3111 * RETURNS
3112 * S_OK.
3114 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3116 return _VarR8FromCy(cyIn, pDblOut);
3119 /************************************************************************
3120 * VarR8FromDate (OLEAUT32.83)
3122 * Convert a VT_DATE to a VT_R8.
3124 * PARAMS
3125 * dateIn [I] Source
3126 * pDblOut [O] Destination
3128 * RETURNS
3129 * S_OK.
3131 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3133 return _VarR8FromDate(dateIn, pDblOut);
3136 /************************************************************************
3137 * VarR8FromStr (OLEAUT32.84)
3139 * Convert a VT_BSTR to a VT_R8.
3141 * PARAMS
3142 * strIn [I] Source
3143 * lcid [I] LCID for the conversion
3144 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3145 * pDblOut [O] Destination
3147 * RETURNS
3148 * Success: S_OK.
3149 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3150 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3152 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3154 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3157 /************************************************************************
3158 * VarR8FromDisp (OLEAUT32.85)
3160 * Convert a VT_DISPATCH to a VT_R8.
3162 * PARAMS
3163 * pdispIn [I] Source
3164 * lcid [I] LCID for conversion
3165 * pDblOut [O] Destination
3167 * RETURNS
3168 * Success: S_OK.
3169 * Failure: E_INVALIDARG, if the source value is invalid
3170 * DISP_E_OVERFLOW, if the value will not fit in the destination
3171 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3173 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3175 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0);
3178 /************************************************************************
3179 * VarR8FromBool (OLEAUT32.86)
3181 * Convert a VT_BOOL to a VT_R8.
3183 * PARAMS
3184 * boolIn [I] Source
3185 * pDblOut [O] Destination
3187 * RETURNS
3188 * S_OK.
3190 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3192 return VarR8FromI2(boolIn, pDblOut);
3195 /************************************************************************
3196 * VarR8FromI1 (OLEAUT32.217)
3198 * Convert a VT_I1 to a VT_R8.
3200 * PARAMS
3201 * cIn [I] Source
3202 * pDblOut [O] Destination
3204 * RETURNS
3205 * Success: S_OK.
3206 * Failure: E_INVALIDARG, if the source value is invalid
3207 * DISP_E_OVERFLOW, if the value will not fit in the destination
3208 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3210 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3212 return _VarR8FromI1(cIn, pDblOut);
3215 /************************************************************************
3216 * VarR8FromUI2 (OLEAUT32.218)
3218 * Convert a VT_UI2 to a VT_R8.
3220 * PARAMS
3221 * usIn [I] Source
3222 * pDblOut [O] Destination
3224 * RETURNS
3225 * Success: S_OK.
3226 * Failure: E_INVALIDARG, if the source value is invalid
3227 * DISP_E_OVERFLOW, if the value will not fit in the destination
3228 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3230 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3232 return _VarR8FromUI2(usIn, pDblOut);
3235 /************************************************************************
3236 * VarR8FromUI4 (OLEAUT32.219)
3238 * Convert a VT_UI4 to a VT_R8.
3240 * PARAMS
3241 * ulIn [I] Source
3242 * pDblOut [O] Destination
3244 * RETURNS
3245 * Success: S_OK.
3246 * Failure: E_INVALIDARG, if the source value is invalid
3247 * DISP_E_OVERFLOW, if the value will not fit in the destination
3248 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3250 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3252 return _VarR8FromUI4(ulIn, pDblOut);
3255 /************************************************************************
3256 * VarR8FromDec (OLEAUT32.220)
3258 * Convert a VT_DECIMAL to a VT_R8.
3260 * PARAMS
3261 * pDecIn [I] Source
3262 * pDblOut [O] Destination
3264 * RETURNS
3265 * Success: S_OK.
3266 * Failure: E_INVALIDARG, if the source value is invalid.
3268 HRESULT WINAPI VarR8FromDec(DECIMAL* pDecIn, double *pDblOut)
3270 BYTE scale = DEC_SCALE(pDecIn);
3271 double divisor = 1.0, highPart;
3273 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3274 return E_INVALIDARG;
3276 while (scale--)
3277 divisor *= 10;
3279 if (DEC_SIGN(pDecIn))
3280 divisor = -divisor;
3282 if (DEC_HI32(pDecIn))
3284 highPart = (double)DEC_HI32(pDecIn) / divisor;
3285 highPart *= 4294967296.0F;
3286 highPart *= 4294967296.0F;
3288 else
3289 highPart = 0.0;
3291 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3292 return S_OK;
3295 /************************************************************************
3296 * VarR8FromI8 (OLEAUT32.362)
3298 * Convert a VT_I8 to a VT_R8.
3300 * PARAMS
3301 * ullIn [I] Source
3302 * pDblOut [O] Destination
3304 * RETURNS
3305 * S_OK.
3307 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3309 return _VarR8FromI8(llIn, pDblOut);
3312 /************************************************************************
3313 * VarR8FromUI8 (OLEAUT32.363)
3315 * Convert a VT_UI8 to a VT_R8.
3317 * PARAMS
3318 * ullIn [I] Source
3319 * pDblOut [O] Destination
3321 * RETURNS
3322 * S_OK.
3324 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3326 return _VarR8FromUI8(ullIn, pDblOut);
3329 /************************************************************************
3330 * VarR8Pow (OLEAUT32.315)
3332 * Raise a VT_R8 to a power.
3334 * PARAMS
3335 * dblLeft [I] Source
3336 * dblPow [I] Power to raise dblLeft by
3337 * pDblOut [O] Destination
3339 * RETURNS
3340 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3342 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3344 *pDblOut = pow(dblLeft, dblPow);
3345 return S_OK;
3348 /************************************************************************
3349 * VarR8Round (OLEAUT32.317)
3351 * Round a VT_R8 to a given number of decimal points.
3353 * PARAMS
3354 * dblIn [I] Source
3355 * nDig [I] Number of decimal points to round to
3356 * pDblOut [O] Destination for rounded number
3358 * RETURNS
3359 * Success: S_OK. pDblOut is rounded to nDig digits.
3360 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3362 * NOTES
3363 * The native version of this function rounds using the internal
3364 * binary representation of the number. Wine uses the dutch rounding
3365 * convention, so therefore small differences can occur in the value returned.
3366 * MSDN says that you should use your own rounding function if you want
3367 * rounding to be predictable in your application.
3369 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3371 double scale, whole, fract;
3373 if (nDig < 0)
3374 return E_INVALIDARG;
3376 scale = pow(10.0, nDig);
3378 dblIn *= scale;
3379 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3380 fract = dblIn - whole;
3382 if (fract > 0.5)
3383 dblIn = whole + 1.0;
3384 else if (fract == 0.5)
3385 dblIn = whole + fmod(whole, 2.0);
3386 else if (fract >= 0.0)
3387 dblIn = whole;
3388 else if (fract == -0.5)
3389 dblIn = whole - fmod(whole, 2.0);
3390 else if (fract > -0.5)
3391 dblIn = whole;
3392 else
3393 dblIn = whole - 1.0;
3395 *pDblOut = dblIn / scale;
3396 return S_OK;
3399 /* CY
3402 /* Powers of 10 from 0..4 D.P. */
3403 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3404 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3406 /************************************************************************
3407 * VarCyFromUI1 (OLEAUT32.98)
3409 * Convert a VT_UI1 to a VT_CY.
3411 * PARAMS
3412 * bIn [I] Source
3413 * pCyOut [O] Destination
3415 * RETURNS
3416 * Success: S_OK.
3417 * Failure: E_INVALIDARG, if the source value is invalid
3418 * DISP_E_OVERFLOW, if the value will not fit in the destination
3419 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3421 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3423 return VarCyFromR8(bIn, pCyOut);
3426 /************************************************************************
3427 * VarCyFromI2 (OLEAUT32.99)
3429 * Convert a VT_I2 to a VT_CY.
3431 * PARAMS
3432 * sIn [I] Source
3433 * pCyOut [O] Destination
3435 * RETURNS
3436 * Success: S_OK.
3437 * Failure: E_INVALIDARG, if the source value is invalid
3438 * DISP_E_OVERFLOW, if the value will not fit in the destination
3439 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3441 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3443 return VarCyFromR8(sIn, pCyOut);
3446 /************************************************************************
3447 * VarCyFromI4 (OLEAUT32.100)
3449 * Convert a VT_I4 to a VT_CY.
3451 * PARAMS
3452 * sIn [I] Source
3453 * pCyOut [O] Destination
3455 * RETURNS
3456 * Success: S_OK.
3457 * Failure: E_INVALIDARG, if the source value is invalid
3458 * DISP_E_OVERFLOW, if the value will not fit in the destination
3459 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3461 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3463 return VarCyFromR8(lIn, pCyOut);
3466 /************************************************************************
3467 * VarCyFromR4 (OLEAUT32.101)
3469 * Convert a VT_R4 to a VT_CY.
3471 * PARAMS
3472 * fltIn [I] Source
3473 * pCyOut [O] Destination
3475 * RETURNS
3476 * Success: S_OK.
3477 * Failure: E_INVALIDARG, if the source value is invalid
3478 * DISP_E_OVERFLOW, if the value will not fit in the destination
3479 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3481 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3483 return VarCyFromR8(fltIn, pCyOut);
3486 /************************************************************************
3487 * VarCyFromR8 (OLEAUT32.102)
3489 * Convert a VT_R8 to a VT_CY.
3491 * PARAMS
3492 * dblIn [I] Source
3493 * pCyOut [O] Destination
3495 * RETURNS
3496 * Success: S_OK.
3497 * Failure: E_INVALIDARG, if the source value is invalid
3498 * DISP_E_OVERFLOW, if the value will not fit in the destination
3499 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3501 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3503 #if defined(__GNUC__) && defined(__i386__)
3504 /* This code gives identical results to Win32 on Intel.
3505 * Here we use fp exceptions to catch overflows when storing the value.
3507 static const unsigned short r8_fpcontrol = 0x137f;
3508 static const double r8_multiplier = CY_MULTIPLIER_F;
3509 unsigned short old_fpcontrol, result_fpstatus;
3511 /* Clear exceptions, save the old fp state and load the new state */
3512 __asm__ __volatile__( "fnclex" );
3513 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3514 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3515 /* Perform the conversion. */
3516 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3517 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3518 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3519 /* Save the resulting fp state, load the old state and clear exceptions */
3520 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3521 __asm__ __volatile__( "fnclex" );
3522 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3524 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3525 return DISP_E_OVERFLOW;
3526 return S_OK;
3527 #else
3528 /* This version produces slightly different results for boundary cases */
3529 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3530 return DISP_E_OVERFLOW;
3531 dblIn *= CY_MULTIPLIER_F;
3532 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3533 #endif
3534 return S_OK;
3537 /************************************************************************
3538 * VarCyFromDate (OLEAUT32.103)
3540 * Convert a VT_DATE to a VT_CY.
3542 * PARAMS
3543 * dateIn [I] Source
3544 * pCyOut [O] Destination
3546 * RETURNS
3547 * Success: S_OK.
3548 * Failure: E_INVALIDARG, if the source value is invalid
3549 * DISP_E_OVERFLOW, if the value will not fit in the destination
3550 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3552 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3554 return VarCyFromR8(dateIn, pCyOut);
3557 /************************************************************************
3558 * VarCyFromStr (OLEAUT32.104)
3560 * Convert a VT_BSTR to a VT_CY.
3562 * PARAMS
3563 * strIn [I] Source
3564 * lcid [I] LCID for the conversion
3565 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3566 * pCyOut [O] Destination
3568 * RETURNS
3569 * Success: S_OK.
3570 * Failure: E_INVALIDARG, if the source value is invalid
3571 * DISP_E_OVERFLOW, if the value will not fit in the destination
3572 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3574 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3576 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3579 /************************************************************************
3580 * VarCyFromDisp (OLEAUT32.105)
3582 * Convert a VT_DISPATCH to a VT_CY.
3584 * PARAMS
3585 * pdispIn [I] Source
3586 * lcid [I] LCID for conversion
3587 * pCyOut [O] Destination
3589 * RETURNS
3590 * Success: S_OK.
3591 * Failure: E_INVALIDARG, if the source value is invalid
3592 * DISP_E_OVERFLOW, if the value will not fit in the destination
3593 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3595 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3597 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0);
3600 /************************************************************************
3601 * VarCyFromBool (OLEAUT32.106)
3603 * Convert a VT_BOOL to a VT_CY.
3605 * PARAMS
3606 * boolIn [I] Source
3607 * pCyOut [O] Destination
3609 * RETURNS
3610 * Success: S_OK.
3611 * Failure: E_INVALIDARG, if the source value is invalid
3612 * DISP_E_OVERFLOW, if the value will not fit in the destination
3613 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3615 * NOTES
3616 * While the sign of the boolean is stored in the currency, the value is
3617 * converted to either 0 or 1.
3619 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3621 return VarCyFromR8(boolIn, pCyOut);
3624 /************************************************************************
3625 * VarCyFromI1 (OLEAUT32.225)
3627 * Convert a VT_I1 to a VT_CY.
3629 * PARAMS
3630 * cIn [I] Source
3631 * pCyOut [O] Destination
3633 * RETURNS
3634 * Success: S_OK.
3635 * Failure: E_INVALIDARG, if the source value is invalid
3636 * DISP_E_OVERFLOW, if the value will not fit in the destination
3637 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3639 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3641 return VarCyFromR8(cIn, pCyOut);
3644 /************************************************************************
3645 * VarCyFromUI2 (OLEAUT32.226)
3647 * Convert a VT_UI2 to a VT_CY.
3649 * PARAMS
3650 * usIn [I] Source
3651 * pCyOut [O] Destination
3653 * RETURNS
3654 * Success: S_OK.
3655 * Failure: E_INVALIDARG, if the source value is invalid
3656 * DISP_E_OVERFLOW, if the value will not fit in the destination
3657 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3659 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3661 return VarCyFromR8(usIn, pCyOut);
3664 /************************************************************************
3665 * VarCyFromUI4 (OLEAUT32.227)
3667 * Convert a VT_UI4 to a VT_CY.
3669 * PARAMS
3670 * ulIn [I] Source
3671 * pCyOut [O] Destination
3673 * RETURNS
3674 * Success: S_OK.
3675 * Failure: E_INVALIDARG, if the source value is invalid
3676 * DISP_E_OVERFLOW, if the value will not fit in the destination
3677 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3679 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3681 return VarCyFromR8(ulIn, pCyOut);
3684 /************************************************************************
3685 * VarCyFromDec (OLEAUT32.228)
3687 * Convert a VT_DECIMAL to a VT_CY.
3689 * PARAMS
3690 * pdecIn [I] Source
3691 * pCyOut [O] Destination
3693 * RETURNS
3694 * Success: S_OK.
3695 * Failure: E_INVALIDARG, if the source value is invalid
3696 * DISP_E_OVERFLOW, if the value will not fit in the destination
3697 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3699 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
3701 DECIMAL rounded;
3702 HRESULT hRet;
3704 hRet = VarDecRound(pdecIn, 4, &rounded);
3706 if (SUCCEEDED(hRet))
3708 double d;
3710 if (DEC_HI32(&rounded))
3711 return DISP_E_OVERFLOW;
3713 /* Note: Without the casts this promotes to int64 which loses precision */
3714 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3715 if (DEC_SIGN(&rounded))
3716 d = -d;
3717 return VarCyFromR8(d, pCyOut);
3719 return hRet;
3722 /************************************************************************
3723 * VarCyFromI8 (OLEAUT32.366)
3725 * Convert a VT_I8 to a VT_CY.
3727 * PARAMS
3728 * ullIn [I] Source
3729 * pCyOut [O] Destination
3731 * RETURNS
3732 * Success: S_OK.
3733 * Failure: E_INVALIDARG, if the source value is invalid
3734 * DISP_E_OVERFLOW, if the value will not fit in the destination
3735 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3737 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3739 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3740 pCyOut->int64 = llIn * CY_MULTIPLIER;
3741 return S_OK;
3744 /************************************************************************
3745 * VarCyFromUI8 (OLEAUT32.375)
3747 * Convert a VT_UI8 to a VT_CY.
3749 * PARAMS
3750 * ullIn [I] Source
3751 * pCyOut [O] Destination
3753 * RETURNS
3754 * Success: S_OK.
3755 * Failure: E_INVALIDARG, if the source value is invalid
3756 * DISP_E_OVERFLOW, if the value will not fit in the destination
3757 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3759 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3761 return VarCyFromR8(ullIn, pCyOut);
3764 /************************************************************************
3765 * VarCyAdd (OLEAUT32.299)
3767 * Add one CY to another.
3769 * PARAMS
3770 * cyLeft [I] Source
3771 * cyRight [I] Value to add
3772 * pCyOut [O] Destination
3774 * RETURNS
3775 * Success: S_OK.
3776 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3778 HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut)
3780 double l,r;
3781 _VarR8FromCy(cyLeft, &l);
3782 _VarR8FromCy(cyRight, &r);
3783 l = l + r;
3784 return VarCyFromR8(l, pCyOut);
3787 /************************************************************************
3788 * VarCyMul (OLEAUT32.303)
3790 * Multiply one CY by another.
3792 * PARAMS
3793 * cyLeft [I] Source
3794 * cyRight [I] Value to multiply by
3795 * pCyOut [O] Destination
3797 * RETURNS
3798 * Success: S_OK.
3799 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3801 HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut)
3803 double l,r;
3804 _VarR8FromCy(cyLeft, &l);
3805 _VarR8FromCy(cyRight, &r);
3806 l = l * r;
3807 return VarCyFromR8(l, pCyOut);
3810 /************************************************************************
3811 * VarCyMulI4 (OLEAUT32.304)
3813 * Multiply one CY by a VT_I4.
3815 * PARAMS
3816 * cyLeft [I] Source
3817 * lRight [I] Value to multiply by
3818 * pCyOut [O] Destination
3820 * RETURNS
3821 * Success: S_OK.
3822 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3824 HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut)
3826 double d;
3828 _VarR8FromCy(cyLeft, &d);
3829 d = d * lRight;
3830 return VarCyFromR8(d, pCyOut);
3833 /************************************************************************
3834 * VarCySub (OLEAUT32.305)
3836 * Subtract one CY from another.
3838 * PARAMS
3839 * cyLeft [I] Source
3840 * cyRight [I] Value to subtract
3841 * pCyOut [O] Destination
3843 * RETURNS
3844 * Success: S_OK.
3845 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3847 HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut)
3849 double l,r;
3850 _VarR8FromCy(cyLeft, &l);
3851 _VarR8FromCy(cyRight, &r);
3852 l = l - r;
3853 return VarCyFromR8(l, pCyOut);
3856 /************************************************************************
3857 * VarCyAbs (OLEAUT32.306)
3859 * Convert a VT_CY into its absolute value.
3861 * PARAMS
3862 * cyIn [I] Source
3863 * pCyOut [O] Destination
3865 * RETURNS
3866 * Success: S_OK. pCyOut contains the absolute value.
3867 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3869 HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut)
3871 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3872 return DISP_E_OVERFLOW;
3874 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3875 return S_OK;
3878 /************************************************************************
3879 * VarCyFix (OLEAUT32.307)
3881 * Return the integer part of a VT_CY.
3883 * PARAMS
3884 * cyIn [I] Source
3885 * pCyOut [O] Destination
3887 * RETURNS
3888 * Success: S_OK.
3889 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3891 * NOTES
3892 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3893 * negative numbers away from 0, while this function rounds them towards zero.
3895 HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut)
3897 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3898 pCyOut->int64 *= CY_MULTIPLIER;
3899 return S_OK;
3902 /************************************************************************
3903 * VarCyInt (OLEAUT32.308)
3905 * Return the integer part of a VT_CY.
3907 * PARAMS
3908 * cyIn [I] Source
3909 * pCyOut [O] Destination
3911 * RETURNS
3912 * Success: S_OK.
3913 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3915 * NOTES
3916 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3917 * negative numbers towards 0, while this function rounds them away from zero.
3919 HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut)
3921 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3922 pCyOut->int64 *= CY_MULTIPLIER;
3924 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3926 pCyOut->int64 -= CY_MULTIPLIER;
3928 return S_OK;
3931 /************************************************************************
3932 * VarCyNeg (OLEAUT32.309)
3934 * Change the sign of a VT_CY.
3936 * PARAMS
3937 * cyIn [I] Source
3938 * pCyOut [O] Destination
3940 * RETURNS
3941 * Success: S_OK.
3942 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3944 HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut)
3946 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3947 return DISP_E_OVERFLOW;
3949 pCyOut->int64 = -cyIn.int64;
3950 return S_OK;
3953 /************************************************************************
3954 * VarCyRound (OLEAUT32.310)
3956 * Change the precision of a VT_CY.
3958 * PARAMS
3959 * cyIn [I] Source
3960 * cDecimals [I] New number of decimals to keep
3961 * pCyOut [O] Destination
3963 * RETURNS
3964 * Success: S_OK.
3965 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3967 HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
3969 if (cDecimals < 0)
3970 return E_INVALIDARG;
3972 if (cDecimals > 3)
3974 /* Rounding to more precision than we have */
3975 *pCyOut = cyIn;
3976 return S_OK;
3978 else
3980 double d, div = CY_Divisors[cDecimals];
3982 _VarR8FromCy(cyIn, &d);
3983 d = d * div;
3984 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3985 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3986 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3987 return S_OK;
3991 /************************************************************************
3992 * VarCyCmp (OLEAUT32.311)
3994 * Compare two VT_CY values.
3996 * PARAMS
3997 * cyLeft [I] Source
3998 * cyRight [I] Value to compare
4000 * RETURNS
4001 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4002 * compare is less, equal or greater than source respectively.
4003 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4005 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
4007 HRESULT hRet;
4008 CY result;
4010 /* Subtract right from left, and compare the result to 0 */
4011 hRet = VarCySub(cyLeft, cyRight, &result);
4013 if (SUCCEEDED(hRet))
4015 if (result.int64 < 0)
4016 hRet = (HRESULT)VARCMP_LT;
4017 else if (result.int64 > 0)
4018 hRet = (HRESULT)VARCMP_GT;
4019 else
4020 hRet = (HRESULT)VARCMP_EQ;
4022 return hRet;
4025 /************************************************************************
4026 * VarCyCmpR8 (OLEAUT32.312)
4028 * Compare a VT_CY to a double
4030 * PARAMS
4031 * cyLeft [I] Currency Source
4032 * dblRight [I] double to compare to cyLeft
4034 * RETURNS
4035 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4036 * less than, equal to or greater than cyLeft respectively.
4037 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4039 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight)
4041 HRESULT hRet;
4042 CY cyRight;
4044 hRet = VarCyFromR8(dblRight, &cyRight);
4046 if (SUCCEEDED(hRet))
4047 hRet = VarCyCmp(cyLeft, cyRight);
4049 return hRet;
4052 /************************************************************************
4053 * VarCyMulI8 (OLEAUT32.329)
4055 * Multiply a VT_CY by a VT_I8.
4057 * PARAMS
4058 * cyLeft [I] Source
4059 * llRight [I] Value to multiply by
4060 * pCyOut [O] Destination
4062 * RETURNS
4063 * Success: S_OK.
4064 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4066 HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
4068 double d;
4070 _VarR8FromCy(cyLeft, &d);
4071 d = d * (double)llRight;
4072 return VarCyFromR8(d, pCyOut);
4075 /* DECIMAL
4078 /************************************************************************
4079 * VarDecFromUI1 (OLEAUT32.190)
4081 * Convert a VT_UI1 to a DECIMAL.
4083 * PARAMS
4084 * bIn [I] Source
4085 * pDecOut [O] Destination
4087 * RETURNS
4088 * S_OK.
4090 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4092 return VarDecFromUI4(bIn, pDecOut);
4095 /************************************************************************
4096 * VarDecFromI2 (OLEAUT32.191)
4098 * Convert a VT_I2 to a DECIMAL.
4100 * PARAMS
4101 * sIn [I] Source
4102 * pDecOut [O] Destination
4104 * RETURNS
4105 * S_OK.
4107 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4109 return VarDecFromI4(sIn, pDecOut);
4112 /************************************************************************
4113 * VarDecFromI4 (OLEAUT32.192)
4115 * Convert a VT_I4 to a DECIMAL.
4117 * PARAMS
4118 * sIn [I] Source
4119 * pDecOut [O] Destination
4121 * RETURNS
4122 * S_OK.
4124 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4126 DEC_HI32(pDecOut) = 0;
4127 DEC_MID32(pDecOut) = 0;
4129 if (lIn < 0)
4131 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4132 DEC_LO32(pDecOut) = -lIn;
4134 else
4136 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4137 DEC_LO32(pDecOut) = lIn;
4139 return S_OK;
4142 #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT))
4144 /* internal representation of the value stored in a DECIMAL. The bytes are
4145 stored from LSB at index 0 to MSB at index 11
4147 typedef struct DECIMAL_internal
4149 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4150 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4151 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4152 } VARIANT_DI;
4154 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest);
4155 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest);
4156 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to);
4157 static void VARIANT_DecFromDI(VARIANT_DI * from, DECIMAL * to);
4159 /************************************************************************
4160 * VarDecFromR4 (OLEAUT32.193)
4162 * Convert a VT_R4 to a DECIMAL.
4164 * PARAMS
4165 * fltIn [I] Source
4166 * pDecOut [O] Destination
4168 * RETURNS
4169 * S_OK.
4171 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4173 VARIANT_DI di;
4174 HRESULT hres;
4176 hres = VARIANT_DI_FromR4(fltIn, &di);
4177 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4178 return hres;
4181 /************************************************************************
4182 * VarDecFromR8 (OLEAUT32.194)
4184 * Convert a VT_R8 to a DECIMAL.
4186 * PARAMS
4187 * dblIn [I] Source
4188 * pDecOut [O] Destination
4190 * RETURNS
4191 * S_OK.
4193 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4195 VARIANT_DI di;
4196 HRESULT hres;
4198 hres = VARIANT_DI_FromR8(dblIn, &di);
4199 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4200 return hres;
4203 /************************************************************************
4204 * VarDecFromDate (OLEAUT32.195)
4206 * Convert a VT_DATE to a DECIMAL.
4208 * PARAMS
4209 * dateIn [I] Source
4210 * pDecOut [O] Destination
4212 * RETURNS
4213 * S_OK.
4215 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4217 return VarDecFromR8(dateIn, pDecOut);
4220 /************************************************************************
4221 * VarDecFromCy (OLEAUT32.196)
4223 * Convert a VT_CY to a DECIMAL.
4225 * PARAMS
4226 * cyIn [I] Source
4227 * pDecOut [O] Destination
4229 * RETURNS
4230 * S_OK.
4232 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4234 DEC_HI32(pDecOut) = 0;
4236 /* Note: This assumes 2s complement integer representation */
4237 if (cyIn.s.Hi & 0x80000000)
4239 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4240 DEC_LO64(pDecOut) = -cyIn.int64;
4242 else
4244 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4245 DEC_MID32(pDecOut) = cyIn.s.Hi;
4246 DEC_LO32(pDecOut) = cyIn.s.Lo;
4248 return S_OK;
4251 /************************************************************************
4252 * VarDecFromStr (OLEAUT32.197)
4254 * Convert a VT_BSTR to a DECIMAL.
4256 * PARAMS
4257 * strIn [I] Source
4258 * lcid [I] LCID for the conversion
4259 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4260 * pDecOut [O] Destination
4262 * RETURNS
4263 * Success: S_OK.
4264 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4266 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4268 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4271 /************************************************************************
4272 * VarDecFromDisp (OLEAUT32.198)
4274 * Convert a VT_DISPATCH to a DECIMAL.
4276 * PARAMS
4277 * pdispIn [I] Source
4278 * lcid [I] LCID for conversion
4279 * pDecOut [O] Destination
4281 * RETURNS
4282 * Success: S_OK.
4283 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4285 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4287 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0);
4290 /************************************************************************
4291 * VarDecFromBool (OLEAUT32.199)
4293 * Convert a VT_BOOL to a DECIMAL.
4295 * PARAMS
4296 * bIn [I] Source
4297 * pDecOut [O] Destination
4299 * RETURNS
4300 * S_OK.
4302 * NOTES
4303 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4305 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4307 DEC_HI32(pDecOut) = 0;
4308 DEC_MID32(pDecOut) = 0;
4309 if (bIn)
4311 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4312 DEC_LO32(pDecOut) = 1;
4314 else
4316 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4317 DEC_LO32(pDecOut) = 0;
4319 return S_OK;
4322 /************************************************************************
4323 * VarDecFromI1 (OLEAUT32.241)
4325 * Convert a VT_I1 to a DECIMAL.
4327 * PARAMS
4328 * cIn [I] Source
4329 * pDecOut [O] Destination
4331 * RETURNS
4332 * S_OK.
4334 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4336 return VarDecFromI4(cIn, pDecOut);
4339 /************************************************************************
4340 * VarDecFromUI2 (OLEAUT32.242)
4342 * Convert a VT_UI2 to a DECIMAL.
4344 * PARAMS
4345 * usIn [I] Source
4346 * pDecOut [O] Destination
4348 * RETURNS
4349 * S_OK.
4351 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4353 return VarDecFromUI4(usIn, pDecOut);
4356 /************************************************************************
4357 * VarDecFromUI4 (OLEAUT32.243)
4359 * Convert a VT_UI4 to a DECIMAL.
4361 * PARAMS
4362 * ulIn [I] Source
4363 * pDecOut [O] Destination
4365 * RETURNS
4366 * S_OK.
4368 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4370 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4371 DEC_HI32(pDecOut) = 0;
4372 DEC_MID32(pDecOut) = 0;
4373 DEC_LO32(pDecOut) = ulIn;
4374 return S_OK;
4377 /************************************************************************
4378 * VarDecFromI8 (OLEAUT32.374)
4380 * Convert a VT_I8 to a DECIMAL.
4382 * PARAMS
4383 * llIn [I] Source
4384 * pDecOut [O] Destination
4386 * RETURNS
4387 * S_OK.
4389 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4391 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4393 DEC_HI32(pDecOut) = 0;
4395 /* Note: This assumes 2s complement integer representation */
4396 if (pLi->u.HighPart & 0x80000000)
4398 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4399 DEC_LO64(pDecOut) = -pLi->QuadPart;
4401 else
4403 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4404 DEC_MID32(pDecOut) = pLi->u.HighPart;
4405 DEC_LO32(pDecOut) = pLi->u.LowPart;
4407 return S_OK;
4410 /************************************************************************
4411 * VarDecFromUI8 (OLEAUT32.375)
4413 * Convert a VT_UI8 to a DECIMAL.
4415 * PARAMS
4416 * ullIn [I] Source
4417 * pDecOut [O] Destination
4419 * RETURNS
4420 * S_OK.
4422 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4424 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4425 DEC_HI32(pDecOut) = 0;
4426 DEC_LO64(pDecOut) = ullIn;
4427 return S_OK;
4430 /* Make two DECIMALS the same scale; used by math functions below */
4431 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4432 const DECIMAL** ppDecRight,
4433 DECIMAL* pDecOut)
4435 static DECIMAL scaleFactor;
4436 DECIMAL decTemp;
4437 int scaleAmount, i;
4438 HRESULT hRet = S_OK;
4440 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4441 return E_INVALIDARG;
4443 DEC_LO32(&scaleFactor) = 10;
4445 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4447 if (!scaleAmount)
4448 return S_OK; /* Same scale */
4450 if (scaleAmount > 0)
4452 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4453 *ppDecRight = pDecOut;
4455 else
4457 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4458 *ppDecLeft = pDecOut;
4459 i = scaleAmount = -scaleAmount;
4462 if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE)
4463 return DISP_E_OVERFLOW; /* Can't scale up */
4465 /* Multiply up the value to be scaled by the correct amount */
4466 while (SUCCEEDED(hRet) && i--)
4468 /* Note we are multiplying by a value with a scale of 0, so we don't recurse */
4469 hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut);
4470 decTemp = *pDecOut;
4472 DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */
4473 return hRet;
4476 /* Add two unsigned 32 bit values with overflow */
4477 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4479 ULARGE_INTEGER ul64;
4481 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4482 *pulHigh = ul64.u.HighPart;
4483 return ul64.u.LowPart;
4486 /* Subtract two unsigned 32 bit values with underflow */
4487 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4489 int invert = 0;
4490 ULARGE_INTEGER ul64;
4492 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4493 if (ulLeft < ulRight)
4494 invert = 1;
4496 if (ul64.QuadPart > (ULONG64)*pulHigh)
4497 ul64.QuadPart -= (ULONG64)*pulHigh;
4498 else
4500 ul64.QuadPart -= (ULONG64)*pulHigh;
4501 invert = 1;
4503 if (invert)
4504 ul64.u.HighPart = -ul64.u.HighPart ;
4506 *pulHigh = ul64.u.HighPart;
4507 return ul64.u.LowPart;
4510 /* Multiply two unsigned 32 bit values with overflow */
4511 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4513 ULARGE_INTEGER ul64;
4515 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4516 *pulHigh = ul64.u.HighPart;
4517 return ul64.u.LowPart;
4520 /* Compare two decimals that have the same scale */
4521 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4523 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4524 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4525 return -1;
4526 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4527 return 0;
4528 return 1;
4531 /************************************************************************
4532 * VarDecAdd (OLEAUT32.177)
4534 * Add one DECIMAL to another.
4536 * PARAMS
4537 * pDecLeft [I] Source
4538 * pDecRight [I] Value to add
4539 * pDecOut [O] Destination
4541 * RETURNS
4542 * Success: S_OK.
4543 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4545 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4547 HRESULT hRet;
4548 DECIMAL scaled;
4550 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled);
4552 if (SUCCEEDED(hRet))
4554 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4555 ULONG overflow = 0;
4556 BYTE sign = DECIMAL_POS;
4558 /* Correct for the sign of the result */
4559 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4561 /* -x + -y : Negative */
4562 sign = DECIMAL_NEG;
4563 goto VarDecAdd_AsPositive;
4565 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4567 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4569 /* -x + y : Negative if x > y */
4570 if (cmp > 0)
4572 sign = DECIMAL_NEG;
4573 VarDecAdd_AsNegative:
4574 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4575 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4576 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4578 else
4580 VarDecAdd_AsInvertedNegative:
4581 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4582 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4583 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4586 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4588 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4590 /* x + -y : Negative if x <= y */
4591 if (cmp <= 0)
4593 sign = DECIMAL_NEG;
4594 goto VarDecAdd_AsInvertedNegative;
4596 goto VarDecAdd_AsNegative;
4598 else
4600 /* x + y : Positive */
4601 VarDecAdd_AsPositive:
4602 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4603 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4604 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4607 if (overflow)
4608 return DISP_E_OVERFLOW; /* overflowed */
4610 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4611 DEC_SIGN(pDecOut) = sign;
4613 return hRet;
4616 /* translate from external DECIMAL format into an internal representation */
4617 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4619 to->scale = DEC_SCALE(from);
4620 to->sign = DEC_SIGN(from) ? 1 : 0;
4622 to->bitsnum[0] = DEC_LO32(from);
4623 to->bitsnum[1] = DEC_MID32(from);
4624 to->bitsnum[2] = DEC_HI32(from);
4627 static void VARIANT_DecFromDI(VARIANT_DI * from, DECIMAL * to)
4629 if (from->sign) {
4630 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4631 } else {
4632 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4635 DEC_LO32(to) = from->bitsnum[0];
4636 DEC_MID32(to) = from->bitsnum[1];
4637 DEC_HI32(to) = from->bitsnum[2];
4640 /* clear an internal representation of a DECIMAL */
4641 static void VARIANT_DI_clear(VARIANT_DI * i)
4643 memset(i, 0, sizeof(VARIANT_DI));
4646 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4647 size is supported. The value in p is replaced by the quotient of the division, and
4648 the remainder is returned as a result. This routine is most often used with a divisor
4649 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4651 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4653 if (divisor == 0) {
4654 /* division by 0 */
4655 return 0xFF;
4656 } else if (divisor == 1) {
4657 /* dividend remains unchanged */
4658 return 0;
4659 } else {
4660 unsigned char remainder = 0;
4661 ULONGLONG iTempDividend;
4662 signed int i;
4664 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4665 for (; i >= 0; i--) {
4666 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4667 remainder = iTempDividend % divisor;
4668 p[i] = iTempDividend / divisor;
4671 return remainder;
4675 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4676 static int VARIANT_int_iszero(DWORD * p, unsigned int n)
4678 for (; n > 0; n--) if (*p++ != 0) return 0;
4679 return 1;
4682 /* multiply two DECIMALS, without changing either one, and place result in third
4683 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4684 digits when scale > 0 in order to fit an overflowing result. Final overflow
4685 flag is returned.
4687 static int VARIANT_DI_mul(VARIANT_DI * a, VARIANT_DI * b, VARIANT_DI * result)
4689 int r_overflow = 0;
4690 DWORD running[6];
4691 signed int mulstart;
4693 VARIANT_DI_clear(result);
4694 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4696 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4697 of the result is formed by adding the scales of the operands.
4699 result->scale = a->scale + b->scale;
4700 memset(running, 0, sizeof(running));
4702 /* count number of leading zero-bytes in operand A */
4703 for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4704 if (mulstart < 0) {
4705 /* result is 0, because operand A is 0 */
4706 result->scale = 0;
4707 result->sign = 0;
4708 } else {
4709 unsigned char remainder = 0;
4710 int iA;
4712 /* perform actual multiplication */
4713 for (iA = 0; iA <= mulstart; iA++) {
4714 ULONG iOverflowMul;
4715 int iB;
4717 for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
4718 ULONG iRV;
4719 int iR;
4721 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4722 iR = iA + iB;
4723 do {
4724 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4725 iR++;
4726 } while (iRV);
4730 /* Too bad - native oleaut does not do this, so we should not either */
4731 #if 0
4732 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4733 This operation should not lose significant digits, and gives an
4734 opportunity to reduce the possibility of overflows in future
4735 operations issued by the application.
4737 while (result->scale > 0) {
4738 memcpy(quotient, running, sizeof(quotient));
4739 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4740 if (remainder > 0) break;
4741 memcpy(running, quotient, sizeof(quotient));
4742 result->scale--;
4744 #endif
4745 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4746 This operation *will* lose significant digits of the result because
4747 all the factors of 10 were consumed by the previous operation.
4749 while (result->scale > 0 && !VARIANT_int_iszero(
4750 running + sizeof(result->bitsnum) / sizeof(DWORD),
4751 (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
4753 remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
4754 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4755 result->scale--;
4758 /* round up the result - native oleaut32 does this */
4759 if (remainder >= 5) {
4760 unsigned int i;
4761 for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
4762 ULONGLONG digit = running[i] + 1;
4763 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4764 running[i] = digit & 0xFFFFFFFF;
4768 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4769 and copy result bits into result structure
4771 r_overflow = !VARIANT_int_iszero(
4772 running + sizeof(result->bitsnum)/sizeof(DWORD),
4773 (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
4774 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4776 return r_overflow;
4779 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4780 hardcoded (period for decimal separator, dash as negative sign). Returns 0 for
4781 success, nonzero if insufficient space in output buffer.
4783 static int VARIANT_DI_tostringW(VARIANT_DI * a, WCHAR * s, unsigned int n)
4785 int overflow = 0;
4786 DWORD quotient[3];
4787 unsigned char remainder;
4788 unsigned int i;
4790 /* place negative sign */
4791 if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
4792 if (n > 0) {
4793 *s++ = '-';
4794 n--;
4796 else overflow = 1;
4799 /* prepare initial 0 */
4800 if (!overflow) {
4801 if (n >= 2) {
4802 s[0] = '0';
4803 s[1] = '\0';
4804 } else overflow = 1;
4807 i = 0;
4808 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4809 while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
4810 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4811 if (i + 2 > n) {
4812 overflow = 1;
4813 } else {
4814 s[i++] = '0' + remainder;
4815 s[i] = '\0';
4819 if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
4821 /* reverse order of digits */
4822 WCHAR * x = s; WCHAR * y = s + i - 1;
4823 while (x < y) {
4824 *x ^= *y;
4825 *y ^= *x;
4826 *x++ ^= *y--;
4829 /* check for decimal point. "i" now has string length */
4830 if (i <= a->scale) {
4831 unsigned int numzeroes = a->scale + 1 - i;
4832 if (i + 1 + numzeroes >= n) {
4833 overflow = 1;
4834 } else {
4835 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4836 i += numzeroes;
4837 while (numzeroes > 0) {
4838 s[--numzeroes] = '0';
4843 /* place decimal point */
4844 if (a->scale > 0) {
4845 unsigned int periodpos = i - a->scale;
4846 if (i + 2 >= n) {
4847 overflow = 1;
4848 } else {
4849 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4850 s[periodpos] = '.'; i++;
4852 /* remove extra zeros at the end, if any */
4853 while (s[i - 1] == '0') s[--i] = '\0';
4854 if (s[i - 1] == '.') s[--i] = '\0';
4859 return overflow;
4862 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4863 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4865 DWORD shifted;
4866 unsigned int i;
4868 /* shift whole DWORDs to the left */
4869 while (shift >= 32)
4871 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4872 *p = 0; shift -= 32;
4875 /* shift remainder (1..31 bits) */
4876 shifted = 0;
4877 if (shift > 0) for (i = 0; i < n; i++)
4879 DWORD b;
4880 b = p[i] >> (32 - shift);
4881 p[i] = (p[i] << shift) | shifted;
4882 shifted = b;
4886 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4887 Value at v is incremented by the value at p. Any size is supported, provided
4888 that v is not shorter than p. Any unapplied carry is returned as a result.
4890 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, DWORD * p,
4891 unsigned int np)
4893 unsigned char carry = 0;
4895 if (nv >= np) {
4896 ULONGLONG sum;
4897 unsigned int i;
4899 for (i = 0; i < np; i++) {
4900 sum = (ULONGLONG)v[i]
4901 + (ULONGLONG)p[i]
4902 + (ULONGLONG)carry;
4903 v[i] = sum & 0xffffffff;
4904 carry = sum >> 32;
4906 for (; i < nv && carry; i++) {
4907 sum = (ULONGLONG)v[i]
4908 + (ULONGLONG)carry;
4909 v[i] = sum & 0xffffffff;
4910 carry = sum >> 32;
4913 return carry;
4916 /* perform integral division with operand p as dividend. Parameter n indicates
4917 number of available DWORDs in divisor p, but available space in p must be
4918 actually at least 2 * n DWORDs, because the remainder of the integral
4919 division is built in the next n DWORDs past the start of the quotient. This
4920 routine replaces the dividend in p with the quotient, and appends n
4921 additional DWORDs for the remainder.
4923 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4924 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4925 source code to the VLI (Very Large Integer) division operator. This algorithm
4926 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4927 variably-scaled integers such as the MS DECIMAL representation.
4929 static void VARIANT_int_div(DWORD * p, unsigned int n, DWORD * divisor,
4930 unsigned int dn)
4932 unsigned int i;
4933 DWORD tempsub[8];
4934 DWORD * negdivisor = tempsub + n;
4936 /* build 2s-complement of divisor */
4937 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
4938 p[n] = 1;
4939 VARIANT_int_add(negdivisor, n, p + n, 1);
4940 memset(p + n, 0, n * sizeof(DWORD));
4942 /* skip all leading zero DWORDs in quotient */
4943 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
4944 /* i is now number of DWORDs left to process */
4945 for (i <<= 5; i < (n << 5); i++) {
4946 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
4948 /* trial subtraction */
4949 memcpy(tempsub, p + n, n * sizeof(DWORD));
4950 VARIANT_int_add(tempsub, n, negdivisor, n);
4952 /* check whether result of subtraction was negative */
4953 if ((tempsub[n - 1] & 0x80000000) == 0) {
4954 memcpy(p + n, tempsub, n * sizeof(DWORD));
4955 p[0] |= 1;
4960 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4961 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
4963 unsigned int i;
4964 ULONG iOverflowMul;
4966 for (iOverflowMul = 0, i = 0; i < n; i++)
4967 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
4968 return (unsigned char)iOverflowMul;
4971 /* increment value in A by the value indicated in B, with scale adjusting.
4972 Modifies parameters by adjusting scales. Returns 0 if addition was
4973 successful, nonzero if a parameter underflowed before it could be
4974 successfully used in the addition.
4976 static int VARIANT_int_addlossy(
4977 DWORD * a, int * ascale, unsigned int an,
4978 DWORD * b, int * bscale, unsigned int bn)
4980 int underflow = 0;
4982 if (VARIANT_int_iszero(a, an)) {
4983 /* if A is zero, copy B into A, after removing digits */
4984 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
4985 VARIANT_int_divbychar(b, bn, 10);
4986 (*bscale)--;
4988 memcpy(a, b, an * sizeof(DWORD));
4989 *ascale = *bscale;
4990 } else if (!VARIANT_int_iszero(b, bn)) {
4991 unsigned int tn = an + 1;
4992 DWORD t[5];
4994 if (bn + 1 > tn) tn = bn + 1;
4995 if (*ascale != *bscale) {
4996 /* first (optimistic) try - try to scale down the one with the bigger
4997 scale, while this number is divisible by 10 */
4998 DWORD * digitchosen;
4999 unsigned int nchosen;
5000 int * scalechosen;
5001 int targetscale;
5003 if (*ascale < *bscale) {
5004 targetscale = *ascale;
5005 scalechosen = bscale;
5006 digitchosen = b;
5007 nchosen = bn;
5008 } else {
5009 targetscale = *bscale;
5010 scalechosen = ascale;
5011 digitchosen = a;
5012 nchosen = an;
5014 memset(t, 0, tn * sizeof(DWORD));
5015 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5017 /* divide by 10 until target scale is reached */
5018 while (*scalechosen > targetscale) {
5019 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5020 if (!remainder) {
5021 (*scalechosen)--;
5022 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5023 } else break;
5027 if (*ascale != *bscale) {
5028 DWORD * digitchosen;
5029 unsigned int nchosen;
5030 int * scalechosen;
5031 int targetscale;
5033 /* try to scale up the one with the smaller scale */
5034 if (*ascale > *bscale) {
5035 targetscale = *ascale;
5036 scalechosen = bscale;
5037 digitchosen = b;
5038 nchosen = bn;
5039 } else {
5040 targetscale = *bscale;
5041 scalechosen = ascale;
5042 digitchosen = a;
5043 nchosen = an;
5045 memset(t, 0, tn * sizeof(DWORD));
5046 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5048 /* multiply by 10 until target scale is reached, or
5049 significant bytes overflow the number
5051 while (*scalechosen < targetscale && t[nchosen] == 0) {
5052 VARIANT_int_mulbychar(t, tn, 10);
5053 if (t[nchosen] == 0) {
5054 /* still does not overflow */
5055 (*scalechosen)++;
5056 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5061 if (*ascale != *bscale) {
5062 /* still different? try to scale down the one with the bigger scale
5063 (this *will* lose significant digits) */
5064 DWORD * digitchosen;
5065 unsigned int nchosen;
5066 int * scalechosen;
5067 int targetscale;
5069 if (*ascale < *bscale) {
5070 targetscale = *ascale;
5071 scalechosen = bscale;
5072 digitchosen = b;
5073 nchosen = bn;
5074 } else {
5075 targetscale = *bscale;
5076 scalechosen = ascale;
5077 digitchosen = a;
5078 nchosen = an;
5080 memset(t, 0, tn * sizeof(DWORD));
5081 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5083 /* divide by 10 until target scale is reached */
5084 while (*scalechosen > targetscale) {
5085 VARIANT_int_divbychar(t, tn, 10);
5086 (*scalechosen)--;
5087 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5091 /* check whether any of the operands still has significant digits
5092 (underflow case 1)
5094 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5095 underflow = 1;
5096 } else {
5097 /* at this step, both numbers have the same scale and can be added
5098 as integers. However, the result might not fit in A, so further
5099 scaling down might be necessary.
5101 while (!underflow) {
5102 memset(t, 0, tn * sizeof(DWORD));
5103 memcpy(t, a, an * sizeof(DWORD));
5105 VARIANT_int_add(t, tn, b, bn);
5106 if (VARIANT_int_iszero(t + an, tn - an)) {
5107 /* addition was successful */
5108 memcpy(a, t, an * sizeof(DWORD));
5109 break;
5110 } else {
5111 /* addition overflowed - remove significant digits
5112 from both operands and try again */
5113 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5114 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5115 /* check whether any operand keeps significant digits after
5116 scaledown (underflow case 2)
5118 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5123 return underflow;
5126 /* perform complete DECIMAL division in the internal representation. Returns
5127 0 if the division was completed (even if quotient is set to 0), or nonzero
5128 in case of quotient overflow.
5130 static HRESULT VARIANT_DI_div(VARIANT_DI * dividend, VARIANT_DI * divisor, VARIANT_DI * quotient)
5132 HRESULT r_overflow = S_OK;
5134 if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
5135 /* division by 0 */
5136 r_overflow = DISP_E_DIVBYZERO;
5137 } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
5138 VARIANT_DI_clear(quotient);
5139 } else {
5140 int quotientscale, remainderscale, tempquotientscale;
5141 DWORD remainderplusquotient[8];
5142 int underflow;
5144 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5145 tempquotientscale = quotientscale;
5146 VARIANT_DI_clear(quotient);
5147 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5149 /* The following strategy is used for division
5150 1) if there was a nonzero remainder from previous iteration, use it as
5151 dividend for this iteration, else (for first iteration) use intended
5152 dividend
5153 2) perform integer division in temporary buffer, develop quotient in
5154 low-order part, remainder in high-order part
5155 3) add quotient from step 2 to final result, with possible loss of
5156 significant digits
5157 4) multiply integer part of remainder by 10, while incrementing the
5158 scale of the remainder. This operation preserves the intended value
5159 of the remainder.
5160 5) loop to step 1 until one of the following is true:
5161 a) remainder is zero (exact division achieved)
5162 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5164 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5165 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5166 do {
5167 VARIANT_int_div(
5168 remainderplusquotient, 4,
5169 divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
5170 underflow = VARIANT_int_addlossy(
5171 quotient->bitsnum, &quotientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
5172 remainderplusquotient, &tempquotientscale, 4);
5173 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5174 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5175 tempquotientscale = ++remainderscale;
5176 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5178 /* quotient scale might now be negative (extremely big number). If, so, try
5179 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5180 until scale is 0. If this cannot be done, it is a real overflow.
5182 while (!r_overflow && quotientscale < 0) {
5183 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5184 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5185 VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
5186 if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
5187 (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
5188 quotientscale++;
5189 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5190 } else r_overflow = DISP_E_OVERFLOW;
5192 if (!r_overflow) {
5193 if (quotientscale <= 255) quotient->scale = quotientscale;
5194 else VARIANT_DI_clear(quotient);
5197 return r_overflow;
5200 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5201 with an undefined scale, which will be assigned to (if possible). It also
5202 receives an exponent of 2. This procedure will then manipulate the mantissa
5203 and calculate a corresponding scale, so that the exponent2 value is assimilated
5204 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5205 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5206 a DECIMAL. */
5207 static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, int isDouble)
5209 HRESULT hres = S_OK;
5210 int exponent5, exponent10;
5212 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5213 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5214 exponent10 might be used to set the VARIANT_DI scale directly. However,
5215 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5216 exponent5 = -exponent2;
5217 exponent10 = exponent2;
5219 /* Handle exponent5 > 0 */
5220 while (exponent5 > 0) {
5221 char bPrevCarryBit;
5222 char bCurrCarryBit;
5224 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5225 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5226 somehow the mantissa should be divided by 2. */
5227 if ((val->bitsnum[0] & 1) == 0) {
5228 /* The mantissa is divisible by 2. Therefore the division can be done
5229 without losing significant digits. */
5230 exponent10++; exponent5--;
5232 /* Shift right */
5233 bPrevCarryBit = val->bitsnum[2] & 1;
5234 val->bitsnum[2] >>= 1;
5235 bCurrCarryBit = val->bitsnum[1] & 1;
5236 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5237 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5238 } else {
5239 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5240 be multiplied by 5, unless the multiplication overflows. */
5241 DWORD temp_bitsnum[3];
5243 exponent5--;
5245 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5246 if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) {
5247 /* Multiplication succeeded without overflow, so copy result back
5248 into VARIANT_DI */
5249 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5251 /* Mask out 3 extraneous bits introduced by the multiply */
5252 } else {
5253 /* Multiplication by 5 overflows. The mantissa should be divided
5254 by 2, and therefore will lose significant digits. */
5255 exponent10++;
5257 /* Shift right */
5258 bPrevCarryBit = val->bitsnum[2] & 1;
5259 val->bitsnum[2] >>= 1;
5260 bCurrCarryBit = val->bitsnum[1] & 1;
5261 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5262 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5267 /* Handle exponent5 < 0 */
5268 while (exponent5 < 0) {
5269 /* In order to divide the value represented by the VARIANT_DI by 5, it
5270 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5271 and the mantissa should be multiplied by 2 */
5272 if ((val->bitsnum[2] & 0x80000000) == 0) {
5273 /* The mantissa can withstand a shift-left without overflowing */
5274 exponent10--; exponent5++;
5275 VARIANT_int_shiftleft(val->bitsnum, 3, 1);
5276 } else {
5277 /* The mantissa would overflow if shifted. Therefore it should be
5278 directly divided by 5. This will lose significant digits, unless
5279 by chance the mantissa happens to be divisible by 5 */
5280 exponent5++;
5281 VARIANT_int_divbychar(val->bitsnum, 3, 5);
5285 /* At this point, the mantissa has assimilated the exponent5, but the
5286 exponent10 might not be suitable for assignment. The exponent10 must be
5287 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5288 down appropriately. */
5289 while (hres == S_OK && exponent10 > 0) {
5290 /* In order to bring exponent10 down to 0, the mantissa should be
5291 multiplied by 10 to compensate. If the exponent10 is too big, this
5292 will cause the mantissa to overflow. */
5293 if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) {
5294 exponent10--;
5295 } else {
5296 hres = DISP_E_OVERFLOW;
5299 while (exponent10 < -DEC_MAX_SCALE) {
5300 int rem10;
5301 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5302 be divided by 10 to compensate. If the exponent10 is too small, this
5303 will cause the mantissa to underflow and become 0 */
5304 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5305 exponent10++;
5306 if (VARIANT_int_iszero(val->bitsnum, 3)) {
5307 /* Underflow, unable to keep dividing */
5308 exponent10 = 0;
5309 } else if (rem10 >= 5) {
5310 DWORD x = 1;
5311 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5314 /* This step is requierd in order to remove excess bits of precision from the
5315 end of the bit representation, down to the precision guaranteed by the
5316 floating point number. */
5317 if (isDouble) {
5318 while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[2] == 0 && (val->bitsnum[1] & 0xFFE00000) != 0))) {
5319 int rem10;
5321 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5322 exponent10++;
5323 if (rem10 >= 5) {
5324 DWORD x = 1;
5325 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5328 } else {
5329 while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 ||
5330 (val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) {
5331 int rem10;
5333 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5334 exponent10++;
5335 if (rem10 >= 5) {
5336 DWORD x = 1;
5337 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5341 /* Remove multiples of 10 from the representation */
5342 while (exponent10 < 0) {
5343 DWORD temp_bitsnum[3];
5345 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5346 if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) {
5347 exponent10++;
5348 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5349 } else break;
5352 /* Scale assignment */
5353 if (hres == S_OK) val->scale = -exponent10;
5355 return hres;
5358 typedef union
5360 struct
5362 unsigned long m : 23;
5363 unsigned int exp_bias : 8;
5364 unsigned int sign : 1;
5365 } i;
5366 float f;
5367 } R4_FIELDS;
5369 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5370 intermediate string step. */
5371 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest)
5373 HRESULT hres = S_OK;
5374 R4_FIELDS fx;
5376 fx.f = source;
5378 /* Detect special cases */
5379 if (fx.i.m == 0 && fx.i.exp_bias == 0) {
5380 /* Floating-point zero */
5381 VARIANT_DI_clear(dest);
5382 } else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) {
5383 /* Floating-point infinity */
5384 hres = DISP_E_OVERFLOW;
5385 } else if (fx.i.exp_bias == 0xFF) {
5386 /* Floating-point NaN */
5387 hres = DISP_E_BADVARTYPE;
5388 } else {
5389 int exponent2;
5390 VARIANT_DI_clear(dest);
5392 exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */
5393 dest->sign = fx.i.sign; /* Sign is simply copied */
5395 /* Copy significant bits to VARIANT_DI mantissa */
5396 dest->bitsnum[0] = fx.i.m;
5397 dest->bitsnum[0] &= 0x007FFFFF;
5398 if (fx.i.exp_bias == 0) {
5399 /* Denormalized number - correct exponent */
5400 exponent2++;
5401 } else {
5402 /* Add hidden bit to mantissa */
5403 dest->bitsnum[0] |= 0x00800000;
5406 /* The act of copying a FP mantissa as integer bits is equivalent to
5407 shifting left the mantissa 23 bits. The exponent2 is reduced to
5408 compensate. */
5409 exponent2 -= 23;
5411 hres = VARIANT_DI_normalize(dest, exponent2, 0);
5414 return hres;
5417 typedef union
5419 struct
5421 unsigned long m_lo : 32; /* 52 bits of precision */
5422 unsigned int m_hi : 20;
5423 unsigned int exp_bias : 11; /* bias == 1023 */
5424 unsigned int sign : 1;
5425 } i;
5426 double d;
5427 } R8_FIELDS;
5429 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5430 intermediate string step. */
5431 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest)
5433 HRESULT hres = S_OK;
5434 R8_FIELDS fx;
5436 fx.d = source;
5438 /* Detect special cases */
5439 if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) {
5440 /* Floating-point zero */
5441 VARIANT_DI_clear(dest);
5442 } else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) {
5443 /* Floating-point infinity */
5444 hres = DISP_E_OVERFLOW;
5445 } else if (fx.i.exp_bias == 0x7FF) {
5446 /* Floating-point NaN */
5447 hres = DISP_E_BADVARTYPE;
5448 } else {
5449 int exponent2;
5450 VARIANT_DI_clear(dest);
5452 exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */
5453 dest->sign = fx.i.sign; /* Sign is simply copied */
5455 /* Copy significant bits to VARIANT_DI mantissa */
5456 dest->bitsnum[0] = fx.i.m_lo;
5457 dest->bitsnum[1] = fx.i.m_hi;
5458 dest->bitsnum[1] &= 0x000FFFFF;
5459 if (fx.i.exp_bias == 0) {
5460 /* Denormalized number - correct exponent */
5461 exponent2++;
5462 } else {
5463 /* Add hidden bit to mantissa */
5464 dest->bitsnum[1] |= 0x00100000;
5467 /* The act of copying a FP mantissa as integer bits is equivalent to
5468 shifting left the mantissa 52 bits. The exponent2 is reduced to
5469 compensate. */
5470 exponent2 -= 52;
5472 hres = VARIANT_DI_normalize(dest, exponent2, 1);
5475 return hres;
5478 /************************************************************************
5479 * VarDecDiv (OLEAUT32.178)
5481 * Divide one DECIMAL by another.
5483 * PARAMS
5484 * pDecLeft [I] Source
5485 * pDecRight [I] Value to divide by
5486 * pDecOut [O] Destination
5488 * RETURNS
5489 * Success: S_OK.
5490 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5492 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5494 HRESULT hRet = S_OK;
5495 VARIANT_DI di_left, di_right, di_result;
5496 HRESULT divresult;
5498 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5500 VARIANT_DIFromDec(pDecLeft, &di_left);
5501 VARIANT_DIFromDec(pDecRight, &di_right);
5502 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result);
5503 if (divresult)
5505 /* division actually overflowed */
5506 hRet = divresult;
5508 else
5510 hRet = S_OK;
5512 if (di_result.scale > DEC_MAX_SCALE)
5514 unsigned char remainder = 0;
5516 /* division underflowed. In order to comply with the MSDN
5517 specifications for DECIMAL ranges, some significant digits
5518 must be removed
5520 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5521 di_result.scale);
5522 while (di_result.scale > DEC_MAX_SCALE &&
5523 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
5525 remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
5526 di_result.scale--;
5528 if (di_result.scale > DEC_MAX_SCALE)
5530 WARN("result underflowed, setting to 0\n");
5531 di_result.scale = 0;
5532 di_result.sign = 0;
5534 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5536 unsigned int i;
5537 for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
5538 ULONGLONG digit = di_result.bitsnum[i] + 1;
5539 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5540 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5544 VARIANT_DecFromDI(&di_result, pDecOut);
5546 return hRet;
5549 /************************************************************************
5550 * VarDecMul (OLEAUT32.179)
5552 * Multiply one DECIMAL by another.
5554 * PARAMS
5555 * pDecLeft [I] Source
5556 * pDecRight [I] Value to multiply by
5557 * pDecOut [O] Destination
5559 * RETURNS
5560 * Success: S_OK.
5561 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5563 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5565 HRESULT hRet = S_OK;
5566 VARIANT_DI di_left, di_right, di_result;
5567 int mulresult;
5569 VARIANT_DIFromDec(pDecLeft, &di_left);
5570 VARIANT_DIFromDec(pDecRight, &di_right);
5571 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5572 if (mulresult)
5574 /* multiplication actually overflowed */
5575 hRet = DISP_E_OVERFLOW;
5577 else
5579 if (di_result.scale > DEC_MAX_SCALE)
5581 /* multiplication underflowed. In order to comply with the MSDN
5582 specifications for DECIMAL ranges, some significant digits
5583 must be removed
5585 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5586 di_result.scale);
5587 while (di_result.scale > DEC_MAX_SCALE &&
5588 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
5590 VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
5591 di_result.scale--;
5593 if (di_result.scale > DEC_MAX_SCALE)
5595 WARN("result underflowed, setting to 0\n");
5596 di_result.scale = 0;
5597 di_result.sign = 0;
5600 VARIANT_DecFromDI(&di_result, pDecOut);
5602 return hRet;
5605 /************************************************************************
5606 * VarDecSub (OLEAUT32.181)
5608 * Subtract one DECIMAL from another.
5610 * PARAMS
5611 * pDecLeft [I] Source
5612 * pDecRight [I] DECIMAL to subtract from pDecLeft
5613 * pDecOut [O] Destination
5615 * RETURNS
5616 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5618 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5620 DECIMAL decRight;
5622 /* Implement as addition of the negative */
5623 VarDecNeg(pDecRight, &decRight);
5624 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5627 /************************************************************************
5628 * VarDecAbs (OLEAUT32.182)
5630 * Convert a DECIMAL into its absolute value.
5632 * PARAMS
5633 * pDecIn [I] Source
5634 * pDecOut [O] Destination
5636 * RETURNS
5637 * S_OK. This function does not fail.
5639 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5641 *pDecOut = *pDecIn;
5642 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5643 return S_OK;
5646 /************************************************************************
5647 * VarDecFix (OLEAUT32.187)
5649 * Return the integer portion of a DECIMAL.
5651 * PARAMS
5652 * pDecIn [I] Source
5653 * pDecOut [O] Destination
5655 * RETURNS
5656 * Success: S_OK.
5657 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5659 * NOTES
5660 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5661 * negative numbers away from 0, while this function rounds them towards zero.
5663 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5665 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5666 return E_INVALIDARG;
5668 if (!DEC_SCALE(pDecIn))
5670 *pDecOut = *pDecIn; /* Already an integer */
5671 return S_OK;
5674 FIXME("semi-stub!\n");
5675 return DISP_E_OVERFLOW;
5678 /************************************************************************
5679 * VarDecInt (OLEAUT32.188)
5681 * Return the integer portion of a DECIMAL.
5683 * PARAMS
5684 * pDecIn [I] Source
5685 * pDecOut [O] Destination
5687 * RETURNS
5688 * Success: S_OK.
5689 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5691 * NOTES
5692 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5693 * negative numbers towards 0, while this function rounds them away from zero.
5695 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5697 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5698 return E_INVALIDARG;
5700 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5701 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5703 FIXME("semi-stub!\n");
5704 return DISP_E_OVERFLOW;
5707 /************************************************************************
5708 * VarDecNeg (OLEAUT32.189)
5710 * Change the sign of a DECIMAL.
5712 * PARAMS
5713 * pDecIn [I] Source
5714 * pDecOut [O] Destination
5716 * RETURNS
5717 * S_OK. This function does not fail.
5719 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5721 *pDecOut = *pDecIn;
5722 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5723 return S_OK;
5726 /************************************************************************
5727 * VarDecRound (OLEAUT32.203)
5729 * Change the precision of a DECIMAL.
5731 * PARAMS
5732 * pDecIn [I] Source
5733 * cDecimals [I] New number of decimals to keep
5734 * pDecOut [O] Destination
5736 * RETURNS
5737 * Success: S_OK. pDecOut contains the rounded value.
5738 * Failure: E_INVALIDARG if any argument is invalid.
5740 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5742 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5743 return E_INVALIDARG;
5745 if (cDecimals >= DEC_SCALE(pDecIn))
5747 *pDecOut = *pDecIn; /* More precision than we have */
5748 return S_OK;
5751 FIXME("semi-stub!\n");
5753 return DISP_E_OVERFLOW;
5756 /************************************************************************
5757 * VarDecCmp (OLEAUT32.204)
5759 * Compare two DECIMAL values.
5761 * PARAMS
5762 * pDecLeft [I] Source
5763 * pDecRight [I] Value to compare
5765 * RETURNS
5766 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5767 * is less than, equal to or greater than pDecRight respectively.
5768 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5770 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5772 HRESULT hRet;
5773 DECIMAL result;
5775 /* Subtract right from left, and compare the result to 0 */
5776 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5778 if (SUCCEEDED(hRet))
5780 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5782 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5783 hRet = (HRESULT)VARCMP_LT;
5784 else if (non_zero)
5785 hRet = (HRESULT)VARCMP_GT;
5786 else
5787 hRet = (HRESULT)VARCMP_EQ;
5789 return hRet;
5792 /************************************************************************
5793 * VarDecCmpR8 (OLEAUT32.298)
5795 * Compare a DECIMAL to a double
5797 * PARAMS
5798 * pDecLeft [I] DECIMAL Source
5799 * dblRight [I] double to compare to pDecLeft
5801 * RETURNS
5802 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5803 * is less than, equal to or greater than pDecLeft respectively.
5804 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5806 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5808 HRESULT hRet;
5809 DECIMAL decRight;
5811 hRet = VarDecFromR8(dblRight, &decRight);
5813 if (SUCCEEDED(hRet))
5814 hRet = VarDecCmp(pDecLeft, &decRight);
5816 return hRet;
5819 /* BOOL
5822 /************************************************************************
5823 * VarBoolFromUI1 (OLEAUT32.118)
5825 * Convert a VT_UI1 to a VT_BOOL.
5827 * PARAMS
5828 * bIn [I] Source
5829 * pBoolOut [O] Destination
5831 * RETURNS
5832 * S_OK.
5834 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5836 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5837 return S_OK;
5840 /************************************************************************
5841 * VarBoolFromI2 (OLEAUT32.119)
5843 * Convert a VT_I2 to a VT_BOOL.
5845 * PARAMS
5846 * sIn [I] Source
5847 * pBoolOut [O] Destination
5849 * RETURNS
5850 * S_OK.
5852 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5854 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5855 return S_OK;
5858 /************************************************************************
5859 * VarBoolFromI4 (OLEAUT32.120)
5861 * Convert a VT_I4 to a VT_BOOL.
5863 * PARAMS
5864 * sIn [I] Source
5865 * pBoolOut [O] Destination
5867 * RETURNS
5868 * S_OK.
5870 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
5872 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
5873 return S_OK;
5876 /************************************************************************
5877 * VarBoolFromR4 (OLEAUT32.121)
5879 * Convert a VT_R4 to a VT_BOOL.
5881 * PARAMS
5882 * fltIn [I] Source
5883 * pBoolOut [O] Destination
5885 * RETURNS
5886 * S_OK.
5888 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
5890 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
5891 return S_OK;
5894 /************************************************************************
5895 * VarBoolFromR8 (OLEAUT32.122)
5897 * Convert a VT_R8 to a VT_BOOL.
5899 * PARAMS
5900 * dblIn [I] Source
5901 * pBoolOut [O] Destination
5903 * RETURNS
5904 * S_OK.
5906 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
5908 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
5909 return S_OK;
5912 /************************************************************************
5913 * VarBoolFromDate (OLEAUT32.123)
5915 * Convert a VT_DATE to a VT_BOOL.
5917 * PARAMS
5918 * dateIn [I] Source
5919 * pBoolOut [O] Destination
5921 * RETURNS
5922 * S_OK.
5924 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
5926 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
5927 return S_OK;
5930 /************************************************************************
5931 * VarBoolFromCy (OLEAUT32.124)
5933 * Convert a VT_CY to a VT_BOOL.
5935 * PARAMS
5936 * cyIn [I] Source
5937 * pBoolOut [O] Destination
5939 * RETURNS
5940 * S_OK.
5942 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
5944 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
5945 return S_OK;
5948 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
5950 HRSRC hrsrc;
5952 hrsrc = FindResourceExW( OLEAUT32_hModule, (LPWSTR)RT_STRING,
5953 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
5954 if (hrsrc)
5956 HGLOBAL hmem = LoadResource( OLEAUT32_hModule, hrsrc );
5958 if (hmem)
5960 const WCHAR *p;
5961 unsigned int i;
5963 p = LockResource( hmem );
5964 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
5966 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
5967 lpszDest[*p] = '\0';
5968 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
5969 return TRUE;
5972 return FALSE;
5975 /************************************************************************
5976 * VarBoolFromStr (OLEAUT32.125)
5978 * Convert a VT_BSTR to a VT_BOOL.
5980 * PARAMS
5981 * strIn [I] Source
5982 * lcid [I] LCID for the conversion
5983 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5984 * pBoolOut [O] Destination
5986 * RETURNS
5987 * Success: S_OK.
5988 * Failure: E_INVALIDARG, if pBoolOut is invalid.
5989 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5991 * NOTES
5992 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
5993 * it may contain (in any case mapping) the text "true" or "false".
5994 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
5995 * localised text of "True" or "False" in the language specified by lcid.
5996 * - If none of these matches occur, the string is treated as a numeric string
5997 * and the boolean pBoolOut will be set according to whether the number is zero
5998 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
5999 * - If the text is not numeric and does not match any of the above, then
6000 * DISP_E_TYPEMISMATCH is returned.
6002 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
6004 /* Any VB/VBA programmers out there should recognise these strings... */
6005 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
6006 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
6007 WCHAR szBuff[64];
6008 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6009 HRESULT hRes = S_OK;
6011 if (!strIn || !pBoolOut)
6012 return DISP_E_TYPEMISMATCH;
6014 /* Check if we should be comparing against localised text */
6015 if (dwFlags & VAR_LOCALBOOL)
6017 /* Convert our LCID into a usable value */
6018 lcid = ConvertDefaultLocale(lcid);
6020 langId = LANGIDFROMLCID(lcid);
6022 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6023 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6025 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6026 * I don't think this is needed unless any of the localised text strings
6027 * contain characters that can be so mapped. In the event that this is
6028 * true for a given language (possibly some Asian languages), then strIn
6029 * should be mapped here _only_ if langId is an Id for which this can occur.
6033 /* Note that if we are not comparing against localised strings, langId
6034 * will have its default value of LANG_ENGLISH. This allows us to mimic
6035 * the native behaviour of always checking against English strings even
6036 * after we've checked for localised ones.
6038 VarBoolFromStr_CheckLocalised:
6039 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
6041 /* Compare against localised strings, ignoring case */
6042 if (!strcmpiW(strIn, szBuff))
6044 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
6045 return hRes;
6047 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
6048 if (!strcmpiW(strIn, szBuff))
6050 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
6051 return hRes;
6055 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6057 /* We have checked the localised text, now check English */
6058 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6059 goto VarBoolFromStr_CheckLocalised;
6062 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6063 if (!strcmpW(strIn, szFalse))
6064 *pBoolOut = VARIANT_FALSE;
6065 else if (!strcmpW(strIn, szTrue))
6066 *pBoolOut = VARIANT_TRUE;
6067 else
6069 double d;
6071 /* If this string is a number, convert it as one */
6072 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
6073 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
6075 return hRes;
6078 /************************************************************************
6079 * VarBoolFromDisp (OLEAUT32.126)
6081 * Convert a VT_DISPATCH to a VT_BOOL.
6083 * PARAMS
6084 * pdispIn [I] Source
6085 * lcid [I] LCID for conversion
6086 * pBoolOut [O] Destination
6088 * RETURNS
6089 * Success: S_OK.
6090 * Failure: E_INVALIDARG, if the source value is invalid
6091 * DISP_E_OVERFLOW, if the value will not fit in the destination
6092 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6094 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
6096 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
6099 /************************************************************************
6100 * VarBoolFromI1 (OLEAUT32.233)
6102 * Convert a VT_I1 to a VT_BOOL.
6104 * PARAMS
6105 * cIn [I] Source
6106 * pBoolOut [O] Destination
6108 * RETURNS
6109 * S_OK.
6111 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
6113 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
6114 return S_OK;
6117 /************************************************************************
6118 * VarBoolFromUI2 (OLEAUT32.234)
6120 * Convert a VT_UI2 to a VT_BOOL.
6122 * PARAMS
6123 * usIn [I] Source
6124 * pBoolOut [O] Destination
6126 * RETURNS
6127 * S_OK.
6129 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
6131 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
6132 return S_OK;
6135 /************************************************************************
6136 * VarBoolFromUI4 (OLEAUT32.235)
6138 * Convert a VT_UI4 to a VT_BOOL.
6140 * PARAMS
6141 * ulIn [I] Source
6142 * pBoolOut [O] Destination
6144 * RETURNS
6145 * S_OK.
6147 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
6149 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
6150 return S_OK;
6153 /************************************************************************
6154 * VarBoolFromDec (OLEAUT32.236)
6156 * Convert a VT_DECIMAL to a VT_BOOL.
6158 * PARAMS
6159 * pDecIn [I] Source
6160 * pBoolOut [O] Destination
6162 * RETURNS
6163 * Success: S_OK.
6164 * Failure: E_INVALIDARG, if pDecIn is invalid.
6166 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
6168 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
6169 return E_INVALIDARG;
6171 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
6172 *pBoolOut = VARIANT_TRUE;
6173 else
6174 *pBoolOut = VARIANT_FALSE;
6175 return S_OK;
6178 /************************************************************************
6179 * VarBoolFromI8 (OLEAUT32.370)
6181 * Convert a VT_I8 to a VT_BOOL.
6183 * PARAMS
6184 * ullIn [I] Source
6185 * pBoolOut [O] Destination
6187 * RETURNS
6188 * S_OK.
6190 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
6192 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
6193 return S_OK;
6196 /************************************************************************
6197 * VarBoolFromUI8 (OLEAUT32.371)
6199 * Convert a VT_UI8 to a VT_BOOL.
6201 * PARAMS
6202 * ullIn [I] Source
6203 * pBoolOut [O] Destination
6205 * RETURNS
6206 * S_OK.
6208 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
6210 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
6211 return S_OK;
6214 /* BSTR
6217 /* Write a number from a UI8 and sign */
6218 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
6222 WCHAR ulNextDigit = ulVal % 10;
6224 *szOut-- = '0' + ulNextDigit;
6225 ulVal = (ulVal - ulNextDigit) / 10;
6226 } while (ulVal);
6228 szOut++;
6229 return szOut;
6232 /* Create a (possibly localised) BSTR from a UI8 and sign */
6233 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
6235 WCHAR szConverted[256];
6237 if (dwFlags & VAR_NEGATIVE)
6238 *--szOut = '-';
6240 if (dwFlags & LOCALE_USE_NLS)
6242 /* Format the number for the locale */
6243 szConverted[0] = '\0';
6244 GetNumberFormatW(lcid,
6245 dwFlags & LOCALE_NOUSEROVERRIDE,
6246 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
6247 szOut = szConverted;
6249 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
6252 /* Create a (possibly localised) BSTR from a UI8 and sign */
6253 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
6255 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
6257 if (!pbstrOut)
6258 return E_INVALIDARG;
6260 /* Create the basic number string */
6261 *szOut-- = '\0';
6262 szOut = VARIANT_WriteNumber(ulVal, szOut);
6264 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
6265 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6266 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6269 /******************************************************************************
6270 * VarBstrFromUI1 (OLEAUT32.108)
6272 * Convert a VT_UI1 to a VT_BSTR.
6274 * PARAMS
6275 * bIn [I] Source
6276 * lcid [I] LCID for the conversion
6277 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6278 * pbstrOut [O] Destination
6280 * RETURNS
6281 * Success: S_OK.
6282 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6283 * E_OUTOFMEMORY, if memory allocation fails.
6285 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6287 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6290 /******************************************************************************
6291 * VarBstrFromI2 (OLEAUT32.109)
6293 * Convert a VT_I2 to a VT_BSTR.
6295 * PARAMS
6296 * sIn [I] Source
6297 * lcid [I] LCID for the conversion
6298 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6299 * pbstrOut [O] Destination
6301 * RETURNS
6302 * Success: S_OK.
6303 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6304 * E_OUTOFMEMORY, if memory allocation fails.
6306 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6308 ULONG64 ul64 = sIn;
6310 if (sIn < 0)
6312 ul64 = -sIn;
6313 dwFlags |= VAR_NEGATIVE;
6315 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6318 /******************************************************************************
6319 * VarBstrFromI4 (OLEAUT32.110)
6321 * Convert a VT_I4 to a VT_BSTR.
6323 * PARAMS
6324 * lIn [I] Source
6325 * lcid [I] LCID for the conversion
6326 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6327 * pbstrOut [O] Destination
6329 * RETURNS
6330 * Success: S_OK.
6331 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6332 * E_OUTOFMEMORY, if memory allocation fails.
6334 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6336 ULONG64 ul64 = lIn;
6338 if (lIn < 0)
6340 ul64 = (ULONG)-lIn;
6341 dwFlags |= VAR_NEGATIVE;
6343 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6346 static BSTR VARIANT_BstrReplaceDecimal(WCHAR * buff, LCID lcid, ULONG dwFlags)
6348 BSTR bstrOut;
6349 WCHAR lpDecimalSep[16];
6351 /* Native oleaut32 uses the locale-specific decimal separator even in the
6352 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6353 American locales will see "one thousand and one tenth" as "1000,1"
6354 instead of "1000.1" (notice the comma). The following code checks for
6355 the need to replace the decimal separator, and if so, will prepare an
6356 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6358 GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE),
6359 lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
6360 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6362 /* locale is compatible with English - return original string */
6363 bstrOut = SysAllocString(buff);
6365 else
6367 WCHAR *p;
6368 WCHAR numbuff[256];
6369 WCHAR empty[1] = {'\0'};
6370 NUMBERFMTW minFormat;
6372 minFormat.NumDigits = 0;
6373 minFormat.LeadingZero = 0;
6374 minFormat.Grouping = 0;
6375 minFormat.lpDecimalSep = lpDecimalSep;
6376 minFormat.lpThousandSep = empty;
6377 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6379 /* count number of decimal digits in string */
6380 p = strchrW( buff, '.' );
6381 if (p) minFormat.NumDigits = strlenW(p + 1);
6383 numbuff[0] = '\0';
6384 if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
6386 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6387 bstrOut = SysAllocString(buff);
6389 else
6391 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6392 bstrOut = SysAllocString(numbuff);
6395 return bstrOut;
6398 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6399 BSTR* pbstrOut, LPCWSTR lpszFormat)
6401 WCHAR buff[256];
6403 if (!pbstrOut)
6404 return E_INVALIDARG;
6406 sprintfW( buff, lpszFormat, dblIn );
6408 /* Negative zeroes are disallowed (some applications depend on this).
6409 If buff starts with a minus, and then nothing follows but zeroes
6410 and/or a period, it is a negative zero and is replaced with a
6411 canonical zero. This duplicates native oleaut32 behavior.
6413 if (buff[0] == '-')
6415 const WCHAR szAccept[] = {'0', '.', '\0'};
6416 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
6417 { buff[0] = '0'; buff[1] = '\0'; }
6420 TRACE("created string %s\n", debugstr_w(buff));
6421 if (dwFlags & LOCALE_USE_NLS)
6423 WCHAR numbuff[256];
6425 /* Format the number for the locale */
6426 numbuff[0] = '\0';
6427 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6428 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6429 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6430 *pbstrOut = SysAllocString(numbuff);
6432 else
6434 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6436 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6439 /******************************************************************************
6440 * VarBstrFromR4 (OLEAUT32.111)
6442 * Convert a VT_R4 to a VT_BSTR.
6444 * PARAMS
6445 * fltIn [I] Source
6446 * lcid [I] LCID for the conversion
6447 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6448 * pbstrOut [O] Destination
6450 * RETURNS
6451 * Success: S_OK.
6452 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6453 * E_OUTOFMEMORY, if memory allocation fails.
6455 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6457 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
6460 /******************************************************************************
6461 * VarBstrFromR8 (OLEAUT32.112)
6463 * Convert a VT_R8 to a VT_BSTR.
6465 * PARAMS
6466 * dblIn [I] Source
6467 * lcid [I] LCID for the conversion
6468 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6469 * pbstrOut [O] Destination
6471 * RETURNS
6472 * Success: S_OK.
6473 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6474 * E_OUTOFMEMORY, if memory allocation fails.
6476 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6478 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
6481 /******************************************************************************
6482 * VarBstrFromCy [OLEAUT32.113]
6484 * Convert a VT_CY to a VT_BSTR.
6486 * PARAMS
6487 * cyIn [I] Source
6488 * lcid [I] LCID for the conversion
6489 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6490 * pbstrOut [O] Destination
6492 * RETURNS
6493 * Success: S_OK.
6494 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6495 * E_OUTOFMEMORY, if memory allocation fails.
6497 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6499 WCHAR buff[256];
6500 VARIANT_DI decVal;
6502 if (!pbstrOut)
6503 return E_INVALIDARG;
6505 decVal.scale = 4;
6506 decVal.sign = 0;
6507 decVal.bitsnum[0] = cyIn.s.Lo;
6508 decVal.bitsnum[1] = cyIn.s.Hi;
6509 if (cyIn.s.Hi & 0x80000000UL) {
6510 DWORD one = 1;
6512 /* Negative number! */
6513 decVal.sign = 1;
6514 decVal.bitsnum[0] = ~decVal.bitsnum[0];
6515 decVal.bitsnum[1] = ~decVal.bitsnum[1];
6516 VARIANT_int_add(decVal.bitsnum, 3, &one, 1);
6518 decVal.bitsnum[2] = 0;
6519 VARIANT_DI_tostringW(&decVal, buff, sizeof(buff));
6521 if (dwFlags & LOCALE_USE_NLS)
6523 WCHAR cybuff[256];
6525 /* Format the currency for the locale */
6526 cybuff[0] = '\0';
6527 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6528 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR));
6529 *pbstrOut = SysAllocString(cybuff);
6531 else
6532 *pbstrOut = SysAllocString(buff);
6534 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6537 /******************************************************************************
6538 * VarBstrFromDate [OLEAUT32.114]
6540 * Convert a VT_DATE to a VT_BSTR.
6542 * PARAMS
6543 * dateIn [I] Source
6544 * lcid [I] LCID for the conversion
6545 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6546 * pbstrOut [O] Destination
6548 * RETURNS
6549 * Success: S_OK.
6550 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6551 * E_OUTOFMEMORY, if memory allocation fails.
6553 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6555 SYSTEMTIME st;
6556 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6557 WCHAR date[128], *time;
6559 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
6561 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6562 return E_INVALIDARG;
6564 *pbstrOut = NULL;
6566 if (dwFlags & VAR_CALENDAR_THAI)
6567 st.wYear += 553; /* Use the Thai buddhist calendar year */
6568 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6569 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6571 if (dwFlags & LOCALE_USE_NLS)
6572 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6573 else
6575 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6576 double partial = dateIn - whole;
6578 if (whole == 0.0)
6579 dwFlags |= VAR_TIMEVALUEONLY;
6580 else if (partial < 1e-12)
6581 dwFlags |= VAR_DATEVALUEONLY;
6584 if (dwFlags & VAR_TIMEVALUEONLY)
6585 date[0] = '\0';
6586 else
6587 if (!GetDateFormatW(lcid, dwFormatFlags|DATE_SHORTDATE, &st, NULL, date,
6588 sizeof(date)/sizeof(WCHAR)))
6589 return E_INVALIDARG;
6591 if (!(dwFlags & VAR_DATEVALUEONLY))
6593 time = date + strlenW(date);
6594 if (time != date)
6595 *time++ = ' ';
6596 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
6597 sizeof(date)/sizeof(WCHAR)-(time-date)))
6598 return E_INVALIDARG;
6601 *pbstrOut = SysAllocString(date);
6602 if (*pbstrOut)
6603 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6604 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6607 /******************************************************************************
6608 * VarBstrFromBool (OLEAUT32.116)
6610 * Convert a VT_BOOL to a VT_BSTR.
6612 * PARAMS
6613 * boolIn [I] Source
6614 * lcid [I] LCID for the conversion
6615 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6616 * pbstrOut [O] Destination
6618 * RETURNS
6619 * Success: S_OK.
6620 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6621 * E_OUTOFMEMORY, if memory allocation fails.
6623 * NOTES
6624 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6625 * localised text of "True" or "False". To convert a bool into a
6626 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6628 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6630 WCHAR szBuff[64];
6631 DWORD dwResId = IDS_TRUE;
6632 LANGID langId;
6634 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn, lcid, dwFlags, pbstrOut);
6636 if (!pbstrOut)
6637 return E_INVALIDARG;
6639 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6640 * for variant formatting */
6641 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6643 case VAR_BOOLONOFF:
6644 dwResId = IDS_ON;
6645 break;
6646 case VAR_BOOLYESNO:
6647 dwResId = IDS_YES;
6648 break;
6649 case VAR_LOCALBOOL:
6650 break;
6651 default:
6652 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6655 lcid = ConvertDefaultLocale(lcid);
6656 langId = LANGIDFROMLCID(lcid);
6657 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6658 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6660 if (boolIn == VARIANT_FALSE)
6661 dwResId++; /* Use negative form */
6663 VarBstrFromBool_GetLocalised:
6664 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6666 *pbstrOut = SysAllocString(szBuff);
6667 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6670 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6672 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6673 goto VarBstrFromBool_GetLocalised;
6676 /* Should never get here */
6677 WARN("Failed to load bool text!\n");
6678 return E_OUTOFMEMORY;
6681 /******************************************************************************
6682 * VarBstrFromI1 (OLEAUT32.229)
6684 * Convert a VT_I1 to a VT_BSTR.
6686 * PARAMS
6687 * cIn [I] Source
6688 * lcid [I] LCID for the conversion
6689 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6690 * pbstrOut [O] Destination
6692 * RETURNS
6693 * Success: S_OK.
6694 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6695 * E_OUTOFMEMORY, if memory allocation fails.
6697 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6699 ULONG64 ul64 = cIn;
6701 if (cIn < 0)
6703 ul64 = -cIn;
6704 dwFlags |= VAR_NEGATIVE;
6706 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6709 /******************************************************************************
6710 * VarBstrFromUI2 (OLEAUT32.230)
6712 * Convert a VT_UI2 to a VT_BSTR.
6714 * PARAMS
6715 * usIn [I] Source
6716 * lcid [I] LCID for the conversion
6717 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6718 * pbstrOut [O] Destination
6720 * RETURNS
6721 * Success: S_OK.
6722 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6723 * E_OUTOFMEMORY, if memory allocation fails.
6725 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6727 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6730 /******************************************************************************
6731 * VarBstrFromUI4 (OLEAUT32.231)
6733 * Convert a VT_UI4 to a VT_BSTR.
6735 * PARAMS
6736 * ulIn [I] Source
6737 * lcid [I] LCID for the conversion
6738 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6739 * pbstrOut [O] Destination
6741 * RETURNS
6742 * Success: S_OK.
6743 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6744 * E_OUTOFMEMORY, if memory allocation fails.
6746 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6748 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
6751 /******************************************************************************
6752 * VarBstrFromDec (OLEAUT32.232)
6754 * Convert a VT_DECIMAL to a VT_BSTR.
6756 * PARAMS
6757 * pDecIn [I] Source
6758 * lcid [I] LCID for the conversion
6759 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6760 * pbstrOut [O] Destination
6762 * RETURNS
6763 * Success: S_OK.
6764 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6765 * E_OUTOFMEMORY, if memory allocation fails.
6767 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6769 WCHAR buff[256];
6770 VARIANT_DI temp;
6772 if (!pbstrOut)
6773 return E_INVALIDARG;
6775 if (!DEC_HI32(pDecIn))
6777 WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
6778 INT scale = DEC_SCALE(pDecIn);
6780 /* Create the basic number string */
6781 *szOut-- = '\0';
6782 szOut = VARIANT_WriteNumber(DEC_LO64(pDecIn), szOut);
6783 if (DEC_SIGN(pDecIn))
6784 dwFlags |= VAR_NEGATIVE;
6786 /* modify for scale */
6787 if (scale)
6789 WCHAR* ptr;
6790 ptr = &szOut[strlenW(szOut)+1];
6791 while (ptr != &szOut[scale])
6793 *(ptr+1) = *ptr;
6794 ptr --;
6796 *(ptr+1) = *ptr;
6797 *ptr = '.';
6800 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
6801 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6802 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6805 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6806 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6809 /************************************************************************
6810 * VarBstrFromI8 (OLEAUT32.370)
6812 * Convert a VT_I8 to a VT_BSTR.
6814 * PARAMS
6815 * llIn [I] Source
6816 * lcid [I] LCID for the conversion
6817 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6818 * pbstrOut [O] Destination
6820 * RETURNS
6821 * Success: S_OK.
6822 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6823 * E_OUTOFMEMORY, if memory allocation fails.
6825 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6827 ULONG64 ul64 = llIn;
6829 if (llIn < 0)
6831 ul64 = -llIn;
6832 dwFlags |= VAR_NEGATIVE;
6834 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6837 /************************************************************************
6838 * VarBstrFromUI8 (OLEAUT32.371)
6840 * Convert a VT_UI8 to a VT_BSTR.
6842 * PARAMS
6843 * ullIn [I] Source
6844 * lcid [I] LCID for the conversion
6845 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6846 * pbstrOut [O] Destination
6848 * RETURNS
6849 * Success: S_OK.
6850 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6851 * E_OUTOFMEMORY, if memory allocation fails.
6853 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6855 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
6858 /************************************************************************
6859 * VarBstrFromDisp (OLEAUT32.115)
6861 * Convert a VT_DISPATCH to a BSTR.
6863 * PARAMS
6864 * pdispIn [I] Source
6865 * lcid [I] LCID for conversion
6866 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6867 * pbstrOut [O] Destination
6869 * RETURNS
6870 * Success: S_OK.
6871 * Failure: E_INVALIDARG, if the source value is invalid
6872 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6874 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6876 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
6879 /**********************************************************************
6880 * VarBstrCat (OLEAUT32.313)
6882 * Concatenate two BSTR values.
6884 * PARAMS
6885 * pbstrLeft [I] Source
6886 * pbstrRight [I] Value to concatenate
6887 * pbstrOut [O] Destination
6889 * RETURNS
6890 * Success: S_OK.
6891 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6892 * E_OUTOFMEMORY, if memory allocation fails.
6894 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
6896 unsigned int lenLeft, lenRight;
6898 TRACE("%s,%s,%p\n",
6899 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
6900 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
6902 if (!pbstrOut)
6903 return E_INVALIDARG;
6905 lenLeft = pbstrLeft ? SysStringLen(pbstrLeft) : 0;
6906 lenRight = pbstrRight ? SysStringLen(pbstrRight) : 0;
6908 *pbstrOut = SysAllocStringLen(NULL, lenLeft + lenRight);
6909 if (!*pbstrOut)
6910 return E_OUTOFMEMORY;
6912 (*pbstrOut)[0] = '\0';
6914 if (pbstrLeft)
6915 memcpy(*pbstrOut, pbstrLeft, lenLeft * sizeof(WCHAR));
6917 if (pbstrRight)
6918 memcpy(*pbstrOut + lenLeft, pbstrRight, lenRight * sizeof(WCHAR));
6920 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
6921 return S_OK;
6924 /**********************************************************************
6925 * VarBstrCmp (OLEAUT32.314)
6927 * Compare two BSTR values.
6929 * PARAMS
6930 * pbstrLeft [I] Source
6931 * pbstrRight [I] Value to compare
6932 * lcid [I] LCID for the comparison
6933 * dwFlags [I] Flags to pass directly to CompareStringW().
6935 * RETURNS
6936 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
6937 * than, equal to or greater than pbstrRight respectively.
6939 * NOTES
6940 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
6941 * states. A NULL BSTR pointer is equivalent to an empty string.
6942 * If LCID is equal to 0, a byte by byte comparison is performed.
6944 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
6946 HRESULT hres;
6947 int ret;
6949 TRACE("%s,%s,%d,%08x\n",
6950 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
6951 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
6953 if (!pbstrLeft || !*pbstrLeft)
6955 if (!pbstrRight || !*pbstrRight)
6956 return VARCMP_EQ;
6957 return VARCMP_LT;
6959 else if (!pbstrRight || !*pbstrRight)
6960 return VARCMP_GT;
6962 if (lcid == 0)
6964 unsigned int lenLeft = SysStringByteLen(pbstrLeft);
6965 unsigned int lenRight = SysStringByteLen(pbstrRight);
6966 ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight));
6967 if (ret < 0)
6968 return VARCMP_LT;
6969 if (ret > 0)
6970 return VARCMP_GT;
6971 if (lenLeft < lenRight)
6972 return VARCMP_LT;
6973 if (lenLeft > lenRight)
6974 return VARCMP_GT;
6975 return VARCMP_EQ;
6977 else
6979 hres = CompareStringW(lcid, dwFlags, pbstrLeft, SysStringLen(pbstrLeft),
6980 pbstrRight, SysStringLen(pbstrRight)) - 1;
6981 TRACE("%d\n", hres);
6982 return hres;
6987 * DATE
6990 /******************************************************************************
6991 * VarDateFromUI1 (OLEAUT32.88)
6993 * Convert a VT_UI1 to a VT_DATE.
6995 * PARAMS
6996 * bIn [I] Source
6997 * pdateOut [O] Destination
6999 * RETURNS
7000 * S_OK.
7002 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
7004 return VarR8FromUI1(bIn, pdateOut);
7007 /******************************************************************************
7008 * VarDateFromI2 (OLEAUT32.89)
7010 * Convert a VT_I2 to a VT_DATE.
7012 * PARAMS
7013 * sIn [I] Source
7014 * pdateOut [O] Destination
7016 * RETURNS
7017 * S_OK.
7019 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
7021 return VarR8FromI2(sIn, pdateOut);
7024 /******************************************************************************
7025 * VarDateFromI4 (OLEAUT32.90)
7027 * Convert a VT_I4 to a VT_DATE.
7029 * PARAMS
7030 * lIn [I] Source
7031 * pdateOut [O] Destination
7033 * RETURNS
7034 * S_OK.
7036 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
7038 return VarDateFromR8(lIn, pdateOut);
7041 /******************************************************************************
7042 * VarDateFromR4 (OLEAUT32.91)
7044 * Convert a VT_R4 to a VT_DATE.
7046 * PARAMS
7047 * fltIn [I] Source
7048 * pdateOut [O] Destination
7050 * RETURNS
7051 * S_OK.
7053 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
7055 return VarR8FromR4(fltIn, pdateOut);
7058 /******************************************************************************
7059 * VarDateFromR8 (OLEAUT32.92)
7061 * Convert a VT_R8 to a VT_DATE.
7063 * PARAMS
7064 * dblIn [I] Source
7065 * pdateOut [O] Destination
7067 * RETURNS
7068 * S_OK.
7070 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
7072 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
7073 *pdateOut = (DATE)dblIn;
7074 return S_OK;
7077 /**********************************************************************
7078 * VarDateFromDisp (OLEAUT32.95)
7080 * Convert a VT_DISPATCH to a VT_DATE.
7082 * PARAMS
7083 * pdispIn [I] Source
7084 * lcid [I] LCID for conversion
7085 * pdateOut [O] Destination
7087 * RETURNS
7088 * Success: S_OK.
7089 * Failure: E_INVALIDARG, if the source value is invalid
7090 * DISP_E_OVERFLOW, if the value will not fit in the destination
7091 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7093 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
7095 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
7098 /******************************************************************************
7099 * VarDateFromBool (OLEAUT32.96)
7101 * Convert a VT_BOOL to a VT_DATE.
7103 * PARAMS
7104 * boolIn [I] Source
7105 * pdateOut [O] Destination
7107 * RETURNS
7108 * S_OK.
7110 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
7112 return VarR8FromBool(boolIn, pdateOut);
7115 /**********************************************************************
7116 * VarDateFromCy (OLEAUT32.93)
7118 * Convert a VT_CY to a VT_DATE.
7120 * PARAMS
7121 * lIn [I] Source
7122 * pdateOut [O] Destination
7124 * RETURNS
7125 * S_OK.
7127 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
7129 return VarR8FromCy(cyIn, pdateOut);
7132 /* Date string parsing */
7133 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7134 #define DP_DATESEP 0x02 /* Date separator */
7135 #define DP_MONTH 0x04 /* Month name */
7136 #define DP_AM 0x08 /* AM */
7137 #define DP_PM 0x10 /* PM */
7139 typedef struct tagDATEPARSE
7141 DWORD dwCount; /* Number of fields found so far (maximum 6) */
7142 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
7143 DWORD dwFlags[6]; /* Flags for each field */
7144 DWORD dwValues[6]; /* Value of each field */
7145 } DATEPARSE;
7147 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7149 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7151 /* Determine if a day is valid in a given month of a given year */
7152 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
7154 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7156 if (day && month && month < 13)
7158 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
7159 return TRUE;
7161 return FALSE;
7164 /* Possible orders for 3 numbers making up a date */
7165 #define ORDER_MDY 0x01
7166 #define ORDER_YMD 0x02
7167 #define ORDER_YDM 0x04
7168 #define ORDER_DMY 0x08
7169 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7171 /* Determine a date for a particular locale, from 3 numbers */
7172 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
7173 DWORD offset, SYSTEMTIME *st)
7175 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
7177 if (!dp->dwCount)
7179 v1 = 30; /* Default to (Variant) 0 date part */
7180 v2 = 12;
7181 v3 = 1899;
7182 goto VARIANT_MakeDate_OK;
7185 v1 = dp->dwValues[offset + 0];
7186 v2 = dp->dwValues[offset + 1];
7187 if (dp->dwCount == 2)
7189 SYSTEMTIME current;
7190 GetSystemTime(&current);
7191 v3 = current.wYear;
7193 else
7194 v3 = dp->dwValues[offset + 2];
7196 TRACE("(%d,%d,%d,%d,%d)\n", v1, v2, v3, iDate, offset);
7198 /* If one number must be a month (Because a month name was given), then only
7199 * consider orders with the month in that position.
7200 * If we took the current year as 'v3', then only allow a year in that position.
7202 if (dp->dwFlags[offset + 0] & DP_MONTH)
7204 dwAllOrders = ORDER_MDY;
7206 else if (dp->dwFlags[offset + 1] & DP_MONTH)
7208 dwAllOrders = ORDER_DMY;
7209 if (dp->dwCount > 2)
7210 dwAllOrders |= ORDER_YMD;
7212 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
7214 dwAllOrders = ORDER_YDM;
7216 else
7218 dwAllOrders = ORDER_MDY|ORDER_DMY;
7219 if (dp->dwCount > 2)
7220 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
7223 VARIANT_MakeDate_Start:
7224 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders);
7226 while (dwAllOrders)
7228 DWORD dwTemp;
7230 if (dwCount == 0)
7232 /* First: Try the order given by iDate */
7233 switch (iDate)
7235 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
7236 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
7237 default: dwTry = dwAllOrders & ORDER_YMD; break;
7240 else if (dwCount == 1)
7242 /* Second: Try all the orders compatible with iDate */
7243 switch (iDate)
7245 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7246 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break;
7247 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7250 else
7252 /* Finally: Try any remaining orders */
7253 dwTry = dwAllOrders;
7256 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount, dwTry);
7258 dwCount++;
7259 if (!dwTry)
7260 continue;
7262 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7264 if (dwTry & ORDER_MDY)
7266 if (VARIANT_IsValidMonthDay(v2,v1,v3))
7268 DATE_SWAP(v1,v2);
7269 goto VARIANT_MakeDate_OK;
7271 dwAllOrders &= ~ORDER_MDY;
7273 if (dwTry & ORDER_YMD)
7275 if (VARIANT_IsValidMonthDay(v3,v2,v1))
7277 DATE_SWAP(v1,v3);
7278 goto VARIANT_MakeDate_OK;
7280 dwAllOrders &= ~ORDER_YMD;
7282 if (dwTry & ORDER_YDM)
7284 if (VARIANT_IsValidMonthDay(v2,v3,v1))
7286 DATE_SWAP(v1,v2);
7287 DATE_SWAP(v2,v3);
7288 goto VARIANT_MakeDate_OK;
7290 dwAllOrders &= ~ORDER_YDM;
7292 if (dwTry & ORDER_DMY)
7294 if (VARIANT_IsValidMonthDay(v1,v2,v3))
7295 goto VARIANT_MakeDate_OK;
7296 dwAllOrders &= ~ORDER_DMY;
7298 if (dwTry & ORDER_MYD)
7300 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7301 if (VARIANT_IsValidMonthDay(v3,v1,v2))
7303 DATE_SWAP(v1,v3);
7304 DATE_SWAP(v2,v3);
7305 goto VARIANT_MakeDate_OK;
7307 dwAllOrders &= ~ORDER_MYD;
7311 if (dp->dwCount == 2)
7313 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7314 v3 = 1; /* 1st of the month */
7315 dwAllOrders = ORDER_YMD|ORDER_MYD;
7316 dp->dwCount = 0; /* Don't return to this code path again */
7317 dwCount = 0;
7318 goto VARIANT_MakeDate_Start;
7321 /* No valid dates were able to be constructed */
7322 return DISP_E_TYPEMISMATCH;
7324 VARIANT_MakeDate_OK:
7326 /* Check that the time part is ok */
7327 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
7328 return DISP_E_TYPEMISMATCH;
7330 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7331 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
7332 st->wHour += 12;
7333 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
7334 st->wHour = 0;
7335 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7337 st->wDay = v1;
7338 st->wMonth = v2;
7339 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7340 * be retrieved from:
7341 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7342 * But Wine doesn't have/use that key as at the time of writing.
7344 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
7345 TRACE("Returning date %d/%d/%d\n", v1, v2, st->wYear);
7346 return S_OK;
7349 /******************************************************************************
7350 * VarDateFromStr [OLEAUT32.94]
7352 * Convert a VT_BSTR to at VT_DATE.
7354 * PARAMS
7355 * strIn [I] String to convert
7356 * lcid [I] Locale identifier for the conversion
7357 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7358 * pdateOut [O] Destination for the converted value
7360 * RETURNS
7361 * Success: S_OK. pdateOut contains the converted value.
7362 * FAILURE: An HRESULT error code indicating the prolem.
7364 * NOTES
7365 * Any date format that can be created using the date formats from lcid
7366 * (Either from kernel Nls functions, variant conversion or formatting) is a
7367 * valid input to this function. In addition, a few more esoteric formats are
7368 * also supported for compatibility with the native version. The date is
7369 * interpreted according to the date settings in the control panel, unless
7370 * the date is invalid in that format, in which the most compatible format
7371 * that produces a valid date will be used.
7373 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7375 static const USHORT ParseDateTokens[] =
7377 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7378 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7379 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7380 LOCALE_SMONTHNAME13,
7381 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7382 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7383 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7384 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7385 LOCALE_SABBREVMONTHNAME13,
7386 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7387 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7388 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7389 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7390 LOCALE_SABBREVDAYNAME7,
7391 LOCALE_S1159, LOCALE_S2359
7393 static const BYTE ParseDateMonths[] =
7395 1,2,3,4,5,6,7,8,9,10,11,12,13,
7396 1,2,3,4,5,6,7,8,9,10,11,12,13
7398 unsigned int i;
7399 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
7400 DATEPARSE dp;
7401 DWORD dwDateSeps = 0, iDate = 0;
7402 HRESULT hRet = S_OK;
7404 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7405 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7406 return E_INVALIDARG;
7408 if (!strIn)
7409 return DISP_E_TYPEMISMATCH;
7411 *pdateOut = 0.0;
7413 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7415 memset(&dp, 0, sizeof(dp));
7417 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7418 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7419 TRACE("iDate is %d\n", iDate);
7421 /* Get the month/day/am/pm tokens for this locale */
7422 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7424 WCHAR buff[128];
7425 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7427 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7428 * GetAltMonthNames(). We should really cache these strings too.
7430 buff[0] = '\0';
7431 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
7432 tokens[i] = SysAllocString(buff);
7433 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7436 /* Parse the string into our structure */
7437 while (*strIn)
7439 if (dp.dwCount > 6)
7440 break;
7442 if (isdigitW(*strIn))
7444 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
7445 dp.dwCount++;
7446 strIn--;
7448 else if (isalpha(*strIn))
7450 BOOL bFound = FALSE;
7452 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7454 DWORD dwLen = strlenW(tokens[i]);
7455 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
7457 if (i <= 25)
7459 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7460 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7461 dp.dwCount++;
7463 else if (i > 39)
7465 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7466 hRet = DISP_E_TYPEMISMATCH;
7467 else
7469 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7470 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7473 strIn += (dwLen - 1);
7474 bFound = TRUE;
7475 break;
7479 if (!bFound)
7481 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7482 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7484 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7485 if (*strIn == 'a' || *strIn == 'A')
7487 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7488 dp.dwParseFlags |= DP_AM;
7490 else
7492 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7493 dp.dwParseFlags |= DP_PM;
7495 strIn++;
7497 else
7499 TRACE("No matching token for %s\n", debugstr_w(strIn));
7500 hRet = DISP_E_TYPEMISMATCH;
7501 break;
7505 else if (*strIn == ':' || *strIn == '.')
7507 if (!dp.dwCount || !strIn[1])
7508 hRet = DISP_E_TYPEMISMATCH;
7509 else
7510 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7512 else if (*strIn == '-' || *strIn == '/')
7514 dwDateSeps++;
7515 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7516 hRet = DISP_E_TYPEMISMATCH;
7517 else
7518 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7520 else if (*strIn == ',' || isspaceW(*strIn))
7522 if (*strIn == ',' && !strIn[1])
7523 hRet = DISP_E_TYPEMISMATCH;
7525 else
7527 hRet = DISP_E_TYPEMISMATCH;
7529 strIn++;
7532 if (!dp.dwCount || dp.dwCount > 6 ||
7533 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7534 hRet = DISP_E_TYPEMISMATCH;
7536 if (SUCCEEDED(hRet))
7538 SYSTEMTIME st;
7539 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7541 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7543 /* Figure out which numbers correspond to which fields.
7545 * This switch statement works based on the fact that native interprets any
7546 * fields that are not joined with a time separator ('.' or ':') as date
7547 * fields. Thus we construct a value from 0-32 where each set bit indicates
7548 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7549 * For valid permutations, we set dwOffset to point to the first date field
7550 * and shorten dp.dwCount by the number of time fields found. The real
7551 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7552 * each date number must represent in the context of iDate.
7554 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7556 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7558 case 0x1: /* TT TTDD TTDDD */
7559 if (dp.dwCount > 3 &&
7560 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7561 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7562 hRet = DISP_E_TYPEMISMATCH;
7563 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7564 hRet = DISP_E_TYPEMISMATCH;
7565 st.wHour = dp.dwValues[0];
7566 st.wMinute = dp.dwValues[1];
7567 dp.dwCount -= 2;
7568 dwOffset = 2;
7569 break;
7571 case 0x3: /* TTT TTTDD TTTDDD */
7572 if (dp.dwCount > 4 &&
7573 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7574 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7575 hRet = DISP_E_TYPEMISMATCH;
7576 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7577 hRet = DISP_E_TYPEMISMATCH;
7578 st.wHour = dp.dwValues[0];
7579 st.wMinute = dp.dwValues[1];
7580 st.wSecond = dp.dwValues[2];
7581 dwOffset = 3;
7582 dp.dwCount -= 3;
7583 break;
7585 case 0x4: /* DDTT */
7586 if (dp.dwCount != 4 ||
7587 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7588 hRet = DISP_E_TYPEMISMATCH;
7590 st.wHour = dp.dwValues[2];
7591 st.wMinute = dp.dwValues[3];
7592 dp.dwCount -= 2;
7593 break;
7595 case 0x0: /* T DD DDD TDDD TDDD */
7596 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7598 st.wHour = dp.dwValues[0]; /* T */
7599 dp.dwCount = 0;
7600 break;
7602 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7604 hRet = DISP_E_TYPEMISMATCH;
7606 else if (dp.dwCount == 3)
7608 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7610 dp.dwCount = 2;
7611 st.wHour = dp.dwValues[0];
7612 dwOffset = 1;
7613 break;
7615 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7617 dp.dwCount = 2;
7618 st.wHour = dp.dwValues[2];
7619 break;
7621 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7622 hRet = DISP_E_TYPEMISMATCH;
7624 else if (dp.dwCount == 4)
7626 dp.dwCount = 3;
7627 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7629 st.wHour = dp.dwValues[0];
7630 dwOffset = 1;
7632 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7634 st.wHour = dp.dwValues[3];
7636 else
7637 hRet = DISP_E_TYPEMISMATCH;
7638 break;
7640 /* .. fall through .. */
7642 case 0x8: /* DDDTT */
7643 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7644 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7645 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7646 dp.dwCount == 4 || dp.dwCount == 6)
7647 hRet = DISP_E_TYPEMISMATCH;
7648 st.wHour = dp.dwValues[3];
7649 st.wMinute = dp.dwValues[4];
7650 if (dp.dwCount == 5)
7651 dp.dwCount -= 2;
7652 break;
7654 case 0xC: /* DDTTT */
7655 if (dp.dwCount != 5 ||
7656 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7657 hRet = DISP_E_TYPEMISMATCH;
7658 st.wHour = dp.dwValues[2];
7659 st.wMinute = dp.dwValues[3];
7660 st.wSecond = dp.dwValues[4];
7661 dp.dwCount -= 3;
7662 break;
7664 case 0x18: /* DDDTTT */
7665 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7666 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7667 hRet = DISP_E_TYPEMISMATCH;
7668 st.wHour = dp.dwValues[3];
7669 st.wMinute = dp.dwValues[4];
7670 st.wSecond = dp.dwValues[5];
7671 dp.dwCount -= 3;
7672 break;
7674 default:
7675 hRet = DISP_E_TYPEMISMATCH;
7676 break;
7679 if (SUCCEEDED(hRet))
7681 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7683 if (dwFlags & VAR_TIMEVALUEONLY)
7685 st.wYear = 1899;
7686 st.wMonth = 12;
7687 st.wDay = 30;
7689 else if (dwFlags & VAR_DATEVALUEONLY)
7690 st.wHour = st.wMinute = st.wSecond = 0;
7692 /* Finally, convert the value to a VT_DATE */
7693 if (SUCCEEDED(hRet))
7694 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7698 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7699 SysFreeString(tokens[i]);
7700 return hRet;
7703 /******************************************************************************
7704 * VarDateFromI1 (OLEAUT32.221)
7706 * Convert a VT_I1 to a VT_DATE.
7708 * PARAMS
7709 * cIn [I] Source
7710 * pdateOut [O] Destination
7712 * RETURNS
7713 * S_OK.
7715 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7717 return VarR8FromI1(cIn, pdateOut);
7720 /******************************************************************************
7721 * VarDateFromUI2 (OLEAUT32.222)
7723 * Convert a VT_UI2 to a VT_DATE.
7725 * PARAMS
7726 * uiIn [I] Source
7727 * pdateOut [O] Destination
7729 * RETURNS
7730 * S_OK.
7732 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7734 return VarR8FromUI2(uiIn, pdateOut);
7737 /******************************************************************************
7738 * VarDateFromUI4 (OLEAUT32.223)
7740 * Convert a VT_UI4 to a VT_DATE.
7742 * PARAMS
7743 * ulIn [I] Source
7744 * pdateOut [O] Destination
7746 * RETURNS
7747 * S_OK.
7749 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7751 return VarDateFromR8(ulIn, pdateOut);
7754 /**********************************************************************
7755 * VarDateFromDec (OLEAUT32.224)
7757 * Convert a VT_DECIMAL to a VT_DATE.
7759 * PARAMS
7760 * pdecIn [I] Source
7761 * pdateOut [O] Destination
7763 * RETURNS
7764 * S_OK.
7766 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
7768 return VarR8FromDec(pdecIn, pdateOut);
7771 /******************************************************************************
7772 * VarDateFromI8 (OLEAUT32.364)
7774 * Convert a VT_I8 to a VT_DATE.
7776 * PARAMS
7777 * llIn [I] Source
7778 * pdateOut [O] Destination
7780 * RETURNS
7781 * Success: S_OK.
7782 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7784 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
7786 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
7787 *pdateOut = (DATE)llIn;
7788 return S_OK;
7791 /******************************************************************************
7792 * VarDateFromUI8 (OLEAUT32.365)
7794 * Convert a VT_UI8 to a VT_DATE.
7796 * PARAMS
7797 * ullIn [I] Source
7798 * pdateOut [O] Destination
7800 * RETURNS
7801 * Success: S_OK.
7802 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7804 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
7806 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
7807 *pdateOut = (DATE)ullIn;
7808 return S_OK;