rsaenh: Change the way AES 128 is derived to match Windows behavior.
[wine.git] / dlls / oleaut32 / vartype.c
blobe9b45ffe94475bf37e711d83c79e651bdcb8948f
1 /*
2 * Low level variant functions
4 * Copyright 2003 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
25 #include "wine/debug.h"
26 #include "wine/unicode.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winnt.h"
30 #include "variant.h"
31 #include "resource.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(variant);
35 extern HMODULE hProxyDll DECLSPEC_HIDDEN;
37 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
38 #define CY_MULTIPLIER_F 10000.0
39 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
40 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
42 static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' };
43 static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' };
45 /* Copy data from one variant to another. */
46 static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
48 switch (vt)
50 case VT_I1:
51 case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
52 case VT_BOOL:
53 case VT_I2:
54 case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
55 case VT_R4:
56 case VT_INT:
57 case VT_I4:
58 case VT_UINT:
59 case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
60 case VT_R8:
61 case VT_DATE:
62 case VT_CY:
63 case VT_I8:
64 case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break;
65 case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break;
66 case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
67 case VT_BSTR: memcpy(pOut, &V_BSTR(srcVar), sizeof(BSTR)); break;
68 default:
69 FIXME("VT_ type %d unhandled, please report!\n", vt);
73 /* Macro to inline conversion from a float or double to any integer type,
74 * rounding according to the 'dutch' convention.
76 #define VARIANT_DutchRound(typ, value, res) do { \
77 double whole = value < 0 ? ceil(value) : floor(value); \
78 double fract = value - whole; \
79 if (fract > 0.5) res = (typ)whole + (typ)1; \
80 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
81 else if (fract >= 0.0) res = (typ)whole; \
82 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
83 else if (fract > -0.5) res = (typ)whole; \
84 else res = (typ)whole - (typ)1; \
85 } while(0)
88 /* Coerce VT_BSTR to a numeric type */
89 static HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
90 void* pOut, VARTYPE vt)
92 VARIANTARG dstVar;
93 HRESULT hRet;
94 NUMPARSE np;
95 BYTE rgb[1024];
97 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
98 np.cDig = 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 VariantInit(&srcVar);
126 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
127 &emptyParams, &srcVar, NULL, NULL);
129 if (SUCCEEDED(hRet))
131 /* Convert the property to the requested type */
132 V_VT(&dstVar) = VT_EMPTY;
133 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt);
134 VariantClear(&srcVar);
136 if (SUCCEEDED(hRet))
138 VARIANT_CopyData(&dstVar, vt, pOut);
139 VariantClear(&srcVar);
142 else
143 hRet = DISP_E_TYPEMISMATCH;
144 return hRet;
147 /* Inline return type */
148 #define RETTYP static inline HRESULT
151 /* Simple compiler cast from one type to another */
152 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
153 *out = in; return S_OK; }
155 /* Compiler cast where input cannot be negative */
156 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
157 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
159 /* Compiler cast where input cannot be > some number */
160 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
161 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
163 /* Compiler cast where input cannot be < some number or >= some other number */
164 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
165 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
167 /* I1 */
168 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX)
169 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX)
170 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX)
171 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool)
172 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX)
173 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX)
174 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX)
175 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX)
177 /* UI1 */
178 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX)
179 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool)
180 NEGTST(BYTE, signed char, VarUI1FromI1)
181 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX)
182 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX)
183 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX)
184 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX)
185 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX)
187 /* I2 */
188 SIMPLE(SHORT, BYTE, VarI2FromUI1)
189 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX)
190 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool)
191 SIMPLE(SHORT, signed char, VarI2FromI1)
192 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX)
193 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX)
194 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX)
195 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX)
197 /* UI2 */
198 SIMPLE(USHORT, BYTE, VarUI2FromUI1)
199 NEGTST(USHORT, SHORT, VarUI2FromI2)
200 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX)
201 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool)
202 NEGTST(USHORT, signed char, VarUI2FromI1)
203 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX)
204 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX)
205 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX)
207 /* I4 */
208 SIMPLE(LONG, BYTE, VarI4FromUI1)
209 SIMPLE(LONG, SHORT, VarI4FromI2)
210 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool)
211 SIMPLE(LONG, signed char, VarI4FromI1)
212 SIMPLE(LONG, USHORT, VarI4FromUI2)
213 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX)
214 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX)
215 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX)
217 /* UI4 */
218 SIMPLE(ULONG, BYTE, VarUI4FromUI1)
219 NEGTST(ULONG, SHORT, VarUI4FromI2)
220 NEGTST(ULONG, LONG, VarUI4FromI4)
221 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool)
222 NEGTST(ULONG, signed char, VarUI4FromI1)
223 SIMPLE(ULONG, USHORT, VarUI4FromUI2)
224 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX)
225 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX)
227 /* I8 */
228 SIMPLE(LONG64, BYTE, VarI8FromUI1)
229 SIMPLE(LONG64, SHORT, VarI8FromI2)
230 SIMPLE(LONG64, signed char, VarI8FromI1)
231 SIMPLE(LONG64, USHORT, VarI8FromUI2)
232 SIMPLE(LONG64, ULONG, VarI8FromUI4)
233 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX)
235 /* UI8 */
236 SIMPLE(ULONG64, BYTE, VarUI8FromUI1)
237 NEGTST(ULONG64, SHORT, VarUI8FromI2)
238 NEGTST(ULONG64, signed char, VarUI8FromI1)
239 SIMPLE(ULONG64, USHORT, VarUI8FromUI2)
240 SIMPLE(ULONG64, ULONG, VarUI8FromUI4)
241 NEGTST(ULONG64, LONG64, VarUI8FromI8)
243 /* R4 (float) */
244 SIMPLE(float, BYTE, VarR4FromUI1)
245 SIMPLE(float, SHORT, VarR4FromI2)
246 SIMPLE(float, signed char, VarR4FromI1)
247 SIMPLE(float, USHORT, VarR4FromUI2)
248 SIMPLE(float, LONG, VarR4FromI4)
249 SIMPLE(float, ULONG, VarR4FromUI4)
250 SIMPLE(float, LONG64, VarR4FromI8)
251 SIMPLE(float, ULONG64, VarR4FromUI8)
253 /* R8 (double) */
254 SIMPLE(double, BYTE, VarR8FromUI1)
255 SIMPLE(double, SHORT, VarR8FromI2)
256 SIMPLE(double, float, VarR8FromR4)
257 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
258 SIMPLE(double, DATE, VarR8FromDate)
259 SIMPLE(double, signed char, VarR8FromI1)
260 SIMPLE(double, USHORT, VarR8FromUI2)
261 SIMPLE(double, LONG, VarR8FromI4)
262 SIMPLE(double, ULONG, VarR8FromUI4)
263 SIMPLE(double, LONG64, VarR8FromI8)
264 SIMPLE(double, ULONG64, VarR8FromUI8)
267 /* I1
270 /************************************************************************
271 * VarI1FromUI1 (OLEAUT32.244)
273 * Convert a VT_UI1 to a VT_I1.
275 * PARAMS
276 * bIn [I] Source
277 * pcOut [O] Destination
279 * RETURNS
280 * Success: S_OK.
281 * Failure: E_INVALIDARG, if the source value is invalid
282 * DISP_E_OVERFLOW, if the value will not fit in the destination
284 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
286 return _VarI1FromUI1(bIn, pcOut);
289 /************************************************************************
290 * VarI1FromI2 (OLEAUT32.245)
292 * Convert a VT_I2 to a VT_I1.
294 * PARAMS
295 * sIn [I] Source
296 * pcOut [O] Destination
298 * RETURNS
299 * Success: S_OK.
300 * Failure: E_INVALIDARG, if the source value is invalid
301 * DISP_E_OVERFLOW, if the value will not fit in the destination
303 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
305 return _VarI1FromI2(sIn, pcOut);
308 /************************************************************************
309 * VarI1FromI4 (OLEAUT32.246)
311 * Convert a VT_I4 to a VT_I1.
313 * PARAMS
314 * iIn [I] Source
315 * pcOut [O] Destination
317 * RETURNS
318 * Success: S_OK.
319 * Failure: E_INVALIDARG, if the source value is invalid
320 * DISP_E_OVERFLOW, if the value will not fit in the destination
322 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
324 return _VarI1FromI4(iIn, pcOut);
327 /************************************************************************
328 * VarI1FromR4 (OLEAUT32.247)
330 * Convert a VT_R4 to a VT_I1.
332 * PARAMS
333 * fltIn [I] Source
334 * pcOut [O] Destination
336 * RETURNS
337 * Success: S_OK.
338 * Failure: E_INVALIDARG, if the source value is invalid
339 * DISP_E_OVERFLOW, if the value will not fit in the destination
341 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
343 return VarI1FromR8(fltIn, pcOut);
346 /************************************************************************
347 * VarI1FromR8 (OLEAUT32.248)
349 * Convert a VT_R8 to a VT_I1.
351 * PARAMS
352 * dblIn [I] Source
353 * pcOut [O] Destination
355 * RETURNS
356 * Success: S_OK.
357 * Failure: E_INVALIDARG, if the source value is invalid
358 * DISP_E_OVERFLOW, if the value will not fit in the destination
360 * NOTES
361 * See VarI8FromR8() for details concerning rounding.
363 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
365 if (dblIn < I1_MIN - 0.5 || dblIn >= I1_MAX + 0.5)
366 return DISP_E_OVERFLOW;
367 VARIANT_DutchRound(CHAR, dblIn, *pcOut);
368 return S_OK;
371 /************************************************************************
372 * VarI1FromDate (OLEAUT32.249)
374 * Convert a VT_DATE to a VT_I1.
376 * PARAMS
377 * dateIn [I] Source
378 * pcOut [O] Destination
380 * RETURNS
381 * Success: S_OK.
382 * Failure: E_INVALIDARG, if the source value is invalid
383 * DISP_E_OVERFLOW, if the value will not fit in the destination
385 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
387 return VarI1FromR8(dateIn, pcOut);
390 /************************************************************************
391 * VarI1FromCy (OLEAUT32.250)
393 * Convert a VT_CY to a VT_I1.
395 * PARAMS
396 * cyIn [I] Source
397 * pcOut [O] Destination
399 * RETURNS
400 * Success: S_OK.
401 * Failure: E_INVALIDARG, if the source value is invalid
402 * DISP_E_OVERFLOW, if the value will not fit in the destination
404 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
406 LONG i = I1_MAX + 1;
408 VarI4FromCy(cyIn, &i);
409 return _VarI1FromI4(i, pcOut);
412 /************************************************************************
413 * VarI1FromStr (OLEAUT32.251)
415 * Convert a VT_BSTR to a VT_I1.
417 * PARAMS
418 * strIn [I] Source
419 * lcid [I] LCID for the conversion
420 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
421 * pcOut [O] Destination
423 * RETURNS
424 * Success: S_OK.
425 * Failure: E_INVALIDARG, if the source value is invalid
426 * DISP_E_OVERFLOW, if the value will not fit in the destination
427 * DISP_E_TYPEMISMATCH, if the type cannot be converted
429 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
431 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
434 /************************************************************************
435 * VarI1FromDisp (OLEAUT32.252)
437 * Convert a VT_DISPATCH to a VT_I1.
439 * PARAMS
440 * pdispIn [I] Source
441 * lcid [I] LCID for conversion
442 * pcOut [O] Destination
444 * RETURNS
445 * Success: S_OK.
446 * Failure: E_INVALIDARG, if the source value is invalid
447 * DISP_E_OVERFLOW, if the value will not fit in the destination
448 * DISP_E_TYPEMISMATCH, if the type cannot be converted
450 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
452 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0);
455 /************************************************************************
456 * VarI1FromBool (OLEAUT32.253)
458 * Convert a VT_BOOL to a VT_I1.
460 * PARAMS
461 * boolIn [I] Source
462 * pcOut [O] Destination
464 * RETURNS
465 * S_OK.
467 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
469 return _VarI1FromBool(boolIn, pcOut);
472 /************************************************************************
473 * VarI1FromUI2 (OLEAUT32.254)
475 * Convert a VT_UI2 to a VT_I1.
477 * PARAMS
478 * usIn [I] Source
479 * pcOut [O] Destination
481 * RETURNS
482 * Success: S_OK.
483 * Failure: E_INVALIDARG, if the source value is invalid
484 * DISP_E_OVERFLOW, if the value will not fit in the destination
486 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
488 return _VarI1FromUI2(usIn, pcOut);
491 /************************************************************************
492 * VarI1FromUI4 (OLEAUT32.255)
494 * Convert a VT_UI4 to a VT_I1.
496 * PARAMS
497 * ulIn [I] Source
498 * pcOut [O] Destination
500 * RETURNS
501 * Success: S_OK.
502 * Failure: E_INVALIDARG, if the source value is invalid
503 * DISP_E_OVERFLOW, if the value will not fit in the destination
504 * DISP_E_TYPEMISMATCH, if the type cannot be converted
506 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
508 return _VarI1FromUI4(ulIn, pcOut);
511 /************************************************************************
512 * VarI1FromDec (OLEAUT32.256)
514 * Convert a VT_DECIMAL to a VT_I1.
516 * PARAMS
517 * pDecIn [I] Source
518 * pcOut [O] Destination
520 * RETURNS
521 * Success: S_OK.
522 * Failure: E_INVALIDARG, if the source value is invalid
523 * DISP_E_OVERFLOW, if the value will not fit in the destination
525 HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut)
527 LONG64 i64;
528 HRESULT hRet;
530 hRet = VarI8FromDec(pdecIn, &i64);
532 if (SUCCEEDED(hRet))
533 hRet = _VarI1FromI8(i64, pcOut);
534 return hRet;
537 /************************************************************************
538 * VarI1FromI8 (OLEAUT32.376)
540 * Convert a VT_I8 to a VT_I1.
542 * PARAMS
543 * llIn [I] Source
544 * pcOut [O] Destination
546 * RETURNS
547 * Success: S_OK.
548 * Failure: E_INVALIDARG, if the source value is invalid
549 * DISP_E_OVERFLOW, if the value will not fit in the destination
551 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
553 return _VarI1FromI8(llIn, pcOut);
556 /************************************************************************
557 * VarI1FromUI8 (OLEAUT32.377)
559 * Convert a VT_UI8 to a VT_I1.
561 * PARAMS
562 * ullIn [I] Source
563 * pcOut [O] Destination
565 * RETURNS
566 * Success: S_OK.
567 * Failure: E_INVALIDARG, if the source value is invalid
568 * DISP_E_OVERFLOW, if the value will not fit in the destination
570 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
572 return _VarI1FromUI8(ullIn, pcOut);
575 /* UI1
578 /************************************************************************
579 * VarUI1FromI2 (OLEAUT32.130)
581 * Convert a VT_I2 to a VT_UI1.
583 * PARAMS
584 * sIn [I] Source
585 * pbOut [O] Destination
587 * RETURNS
588 * Success: S_OK.
589 * Failure: E_INVALIDARG, if the source value is invalid
590 * DISP_E_OVERFLOW, if the value will not fit in the destination
592 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
594 return _VarUI1FromI2(sIn, pbOut);
597 /************************************************************************
598 * VarUI1FromI4 (OLEAUT32.131)
600 * Convert a VT_I4 to a VT_UI1.
602 * PARAMS
603 * iIn [I] Source
604 * pbOut [O] Destination
606 * RETURNS
607 * Success: S_OK.
608 * Failure: E_INVALIDARG, if the source value is invalid
609 * DISP_E_OVERFLOW, if the value will not fit in the destination
611 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
613 return _VarUI1FromI4(iIn, pbOut);
616 /************************************************************************
617 * VarUI1FromR4 (OLEAUT32.132)
619 * Convert a VT_R4 to a VT_UI1.
621 * PARAMS
622 * fltIn [I] Source
623 * pbOut [O] Destination
625 * RETURNS
626 * Success: S_OK.
627 * Failure: E_INVALIDARG, if the source value is invalid
628 * DISP_E_OVERFLOW, if the value will not fit in the destination
629 * DISP_E_TYPEMISMATCH, if the type cannot be converted
631 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
633 return VarUI1FromR8(fltIn, pbOut);
636 /************************************************************************
637 * VarUI1FromR8 (OLEAUT32.133)
639 * Convert a VT_R8 to a VT_UI1.
641 * PARAMS
642 * dblIn [I] Source
643 * pbOut [O] Destination
645 * RETURNS
646 * Success: S_OK.
647 * Failure: E_INVALIDARG, if the source value is invalid
648 * DISP_E_OVERFLOW, if the value will not fit in the destination
650 * NOTES
651 * See VarI8FromR8() for details concerning rounding.
653 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
655 if (dblIn < -0.5 || dblIn >= UI1_MAX + 0.5)
656 return DISP_E_OVERFLOW;
657 VARIANT_DutchRound(BYTE, dblIn, *pbOut);
658 return S_OK;
661 /************************************************************************
662 * VarUI1FromCy (OLEAUT32.134)
664 * Convert a VT_CY to a VT_UI1.
666 * PARAMS
667 * cyIn [I] Source
668 * pbOut [O] Destination
670 * RETURNS
671 * Success: S_OK.
672 * Failure: E_INVALIDARG, if the source value is invalid
673 * DISP_E_OVERFLOW, if the value will not fit in the destination
675 * NOTES
676 * Negative values >= -5000 will be converted to 0.
678 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
680 ULONG i = UI1_MAX + 1;
682 VarUI4FromCy(cyIn, &i);
683 return _VarUI1FromUI4(i, pbOut);
686 /************************************************************************
687 * VarUI1FromDate (OLEAUT32.135)
689 * Convert a VT_DATE to a VT_UI1.
691 * PARAMS
692 * dateIn [I] Source
693 * pbOut [O] Destination
695 * RETURNS
696 * Success: S_OK.
697 * Failure: E_INVALIDARG, if the source value is invalid
698 * DISP_E_OVERFLOW, if the value will not fit in the destination
700 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
702 return VarUI1FromR8(dateIn, pbOut);
705 /************************************************************************
706 * VarUI1FromStr (OLEAUT32.136)
708 * Convert a VT_BSTR to a VT_UI1.
710 * PARAMS
711 * strIn [I] Source
712 * lcid [I] LCID for the conversion
713 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
714 * pbOut [O] Destination
716 * RETURNS
717 * Success: S_OK.
718 * Failure: E_INVALIDARG, if the source value is invalid
719 * DISP_E_OVERFLOW, if the value will not fit in the destination
720 * DISP_E_TYPEMISMATCH, if the type cannot be converted
722 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
724 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
727 /************************************************************************
728 * VarUI1FromDisp (OLEAUT32.137)
730 * Convert a VT_DISPATCH to a VT_UI1.
732 * PARAMS
733 * pdispIn [I] Source
734 * lcid [I] LCID for conversion
735 * pbOut [O] Destination
737 * RETURNS
738 * Success: S_OK.
739 * Failure: E_INVALIDARG, if the source value is invalid
740 * DISP_E_OVERFLOW, if the value will not fit in the destination
741 * DISP_E_TYPEMISMATCH, if the type cannot be converted
743 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
745 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0);
748 /************************************************************************
749 * VarUI1FromBool (OLEAUT32.138)
751 * Convert a VT_BOOL to a VT_UI1.
753 * PARAMS
754 * boolIn [I] Source
755 * pbOut [O] Destination
757 * RETURNS
758 * S_OK.
760 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
762 return _VarUI1FromBool(boolIn, pbOut);
765 /************************************************************************
766 * VarUI1FromI1 (OLEAUT32.237)
768 * Convert a VT_I1 to a VT_UI1.
770 * PARAMS
771 * cIn [I] Source
772 * pbOut [O] Destination
774 * RETURNS
775 * Success: S_OK.
776 * Failure: E_INVALIDARG, if the source value is invalid
777 * DISP_E_OVERFLOW, if the value will not fit in the destination
779 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
781 return _VarUI1FromI1(cIn, pbOut);
784 /************************************************************************
785 * VarUI1FromUI2 (OLEAUT32.238)
787 * Convert a VT_UI2 to a VT_UI1.
789 * PARAMS
790 * usIn [I] Source
791 * pbOut [O] Destination
793 * RETURNS
794 * Success: S_OK.
795 * Failure: E_INVALIDARG, if the source value is invalid
796 * DISP_E_OVERFLOW, if the value will not fit in the destination
798 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
800 return _VarUI1FromUI2(usIn, pbOut);
803 /************************************************************************
804 * VarUI1FromUI4 (OLEAUT32.239)
806 * Convert a VT_UI4 to a VT_UI1.
808 * PARAMS
809 * ulIn [I] Source
810 * pbOut [O] Destination
812 * RETURNS
813 * Success: S_OK.
814 * Failure: E_INVALIDARG, if the source value is invalid
815 * DISP_E_OVERFLOW, if the value will not fit in the destination
817 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
819 return _VarUI1FromUI4(ulIn, pbOut);
822 /************************************************************************
823 * VarUI1FromDec (OLEAUT32.240)
825 * Convert a VT_DECIMAL to a VT_UI1.
827 * PARAMS
828 * pDecIn [I] Source
829 * pbOut [O] Destination
831 * RETURNS
832 * Success: S_OK.
833 * Failure: E_INVALIDARG, if the source value is invalid
834 * DISP_E_OVERFLOW, if the value will not fit in the destination
836 HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut)
838 LONG64 i64;
839 HRESULT hRet;
841 hRet = VarI8FromDec(pdecIn, &i64);
843 if (SUCCEEDED(hRet))
844 hRet = _VarUI1FromI8(i64, pbOut);
845 return hRet;
848 /************************************************************************
849 * VarUI1FromI8 (OLEAUT32.372)
851 * Convert a VT_I8 to a VT_UI1.
853 * PARAMS
854 * llIn [I] Source
855 * pbOut [O] Destination
857 * RETURNS
858 * Success: S_OK.
859 * Failure: E_INVALIDARG, if the source value is invalid
860 * DISP_E_OVERFLOW, if the value will not fit in the destination
862 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
864 return _VarUI1FromI8(llIn, pbOut);
867 /************************************************************************
868 * VarUI1FromUI8 (OLEAUT32.373)
870 * Convert a VT_UI8 to a VT_UI1.
872 * PARAMS
873 * ullIn [I] Source
874 * pbOut [O] Destination
876 * RETURNS
877 * Success: S_OK.
878 * Failure: E_INVALIDARG, if the source value is invalid
879 * DISP_E_OVERFLOW, if the value will not fit in the destination
881 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
883 return _VarUI1FromUI8(ullIn, pbOut);
887 /* I2
890 /************************************************************************
891 * VarI2FromUI1 (OLEAUT32.48)
893 * Convert a VT_UI2 to a VT_I2.
895 * PARAMS
896 * bIn [I] Source
897 * psOut [O] Destination
899 * RETURNS
900 * S_OK.
902 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
904 return _VarI2FromUI1(bIn, psOut);
907 /************************************************************************
908 * VarI2FromI4 (OLEAUT32.49)
910 * Convert a VT_I4 to a VT_I2.
912 * PARAMS
913 * iIn [I] Source
914 * psOut [O] Destination
916 * RETURNS
917 * Success: S_OK.
918 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
920 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
922 return _VarI2FromI4(iIn, psOut);
925 /************************************************************************
926 * VarI2FromR4 (OLEAUT32.50)
928 * Convert a VT_R4 to a VT_I2.
930 * PARAMS
931 * fltIn [I] Source
932 * psOut [O] Destination
934 * RETURNS
935 * Success: S_OK.
936 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
938 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
940 return VarI2FromR8(fltIn, psOut);
943 /************************************************************************
944 * VarI2FromR8 (OLEAUT32.51)
946 * Convert a VT_R8 to a VT_I2.
948 * PARAMS
949 * dblIn [I] Source
950 * psOut [O] Destination
952 * RETURNS
953 * Success: S_OK.
954 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
956 * NOTES
957 * See VarI8FromR8() for details concerning rounding.
959 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
961 if (dblIn < I2_MIN - 0.5 || dblIn >= I2_MAX + 0.5)
962 return DISP_E_OVERFLOW;
963 VARIANT_DutchRound(SHORT, dblIn, *psOut);
964 return S_OK;
967 /************************************************************************
968 * VarI2FromCy (OLEAUT32.52)
970 * Convert a VT_CY to a VT_I2.
972 * PARAMS
973 * cyIn [I] Source
974 * psOut [O] Destination
976 * RETURNS
977 * Success: S_OK.
978 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
980 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
982 LONG i = I2_MAX + 1;
984 VarI4FromCy(cyIn, &i);
985 return _VarI2FromI4(i, psOut);
988 /************************************************************************
989 * VarI2FromDate (OLEAUT32.53)
991 * Convert a VT_DATE to a VT_I2.
993 * PARAMS
994 * dateIn [I] Source
995 * psOut [O] Destination
997 * RETURNS
998 * Success: S_OK.
999 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1001 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
1003 return VarI2FromR8(dateIn, psOut);
1006 /************************************************************************
1007 * VarI2FromStr (OLEAUT32.54)
1009 * Convert a VT_BSTR to a VT_I2.
1011 * PARAMS
1012 * strIn [I] Source
1013 * lcid [I] LCID for the conversion
1014 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1015 * psOut [O] Destination
1017 * RETURNS
1018 * Success: S_OK.
1019 * Failure: E_INVALIDARG, if any parameter is invalid
1020 * DISP_E_OVERFLOW, if the value will not fit in the destination
1021 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1023 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
1025 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
1028 /************************************************************************
1029 * VarI2FromDisp (OLEAUT32.55)
1031 * Convert a VT_DISPATCH to a VT_I2.
1033 * PARAMS
1034 * pdispIn [I] Source
1035 * lcid [I] LCID for conversion
1036 * psOut [O] Destination
1038 * RETURNS
1039 * Success: S_OK.
1040 * Failure: E_INVALIDARG, if pdispIn is invalid,
1041 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1042 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1044 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
1046 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0);
1049 /************************************************************************
1050 * VarI2FromBool (OLEAUT32.56)
1052 * Convert a VT_BOOL to a VT_I2.
1054 * PARAMS
1055 * boolIn [I] Source
1056 * psOut [O] Destination
1058 * RETURNS
1059 * S_OK.
1061 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
1063 return _VarI2FromBool(boolIn, psOut);
1066 /************************************************************************
1067 * VarI2FromI1 (OLEAUT32.205)
1069 * Convert a VT_I1 to a VT_I2.
1071 * PARAMS
1072 * cIn [I] Source
1073 * psOut [O] Destination
1075 * RETURNS
1076 * S_OK.
1078 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
1080 return _VarI2FromI1(cIn, psOut);
1083 /************************************************************************
1084 * VarI2FromUI2 (OLEAUT32.206)
1086 * Convert a VT_UI2 to a VT_I2.
1088 * PARAMS
1089 * usIn [I] Source
1090 * psOut [O] Destination
1092 * RETURNS
1093 * Success: S_OK.
1094 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1096 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
1098 return _VarI2FromUI2(usIn, psOut);
1101 /************************************************************************
1102 * VarI2FromUI4 (OLEAUT32.207)
1104 * Convert a VT_UI4 to a VT_I2.
1106 * PARAMS
1107 * ulIn [I] Source
1108 * psOut [O] Destination
1110 * RETURNS
1111 * Success: S_OK.
1112 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1114 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
1116 return _VarI2FromUI4(ulIn, psOut);
1119 /************************************************************************
1120 * VarI2FromDec (OLEAUT32.208)
1122 * Convert a VT_DECIMAL to a VT_I2.
1124 * PARAMS
1125 * pDecIn [I] Source
1126 * psOut [O] Destination
1128 * RETURNS
1129 * Success: S_OK.
1130 * Failure: E_INVALIDARG, if the source value is invalid
1131 * DISP_E_OVERFLOW, if the value will not fit in the destination
1133 HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut)
1135 LONG64 i64;
1136 HRESULT hRet;
1138 hRet = VarI8FromDec(pdecIn, &i64);
1140 if (SUCCEEDED(hRet))
1141 hRet = _VarI2FromI8(i64, psOut);
1142 return hRet;
1145 /************************************************************************
1146 * VarI2FromI8 (OLEAUT32.346)
1148 * Convert a VT_I8 to a VT_I2.
1150 * PARAMS
1151 * llIn [I] Source
1152 * psOut [O] Destination
1154 * RETURNS
1155 * Success: S_OK.
1156 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1158 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
1160 return _VarI2FromI8(llIn, psOut);
1163 /************************************************************************
1164 * VarI2FromUI8 (OLEAUT32.347)
1166 * Convert a VT_UI8 to a VT_I2.
1168 * PARAMS
1169 * ullIn [I] Source
1170 * psOut [O] Destination
1172 * RETURNS
1173 * Success: S_OK.
1174 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1176 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
1178 return _VarI2FromUI8(ullIn, psOut);
1181 /* UI2
1184 /************************************************************************
1185 * VarUI2FromUI1 (OLEAUT32.257)
1187 * Convert a VT_UI1 to a VT_UI2.
1189 * PARAMS
1190 * bIn [I] Source
1191 * pusOut [O] Destination
1193 * RETURNS
1194 * S_OK.
1196 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
1198 return _VarUI2FromUI1(bIn, pusOut);
1201 /************************************************************************
1202 * VarUI2FromI2 (OLEAUT32.258)
1204 * Convert a VT_I2 to a VT_UI2.
1206 * PARAMS
1207 * sIn [I] Source
1208 * pusOut [O] Destination
1210 * RETURNS
1211 * Success: S_OK.
1212 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1214 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
1216 return _VarUI2FromI2(sIn, pusOut);
1219 /************************************************************************
1220 * VarUI2FromI4 (OLEAUT32.259)
1222 * Convert a VT_I4 to a VT_UI2.
1224 * PARAMS
1225 * iIn [I] Source
1226 * pusOut [O] Destination
1228 * RETURNS
1229 * Success: S_OK.
1230 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1232 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
1234 return _VarUI2FromI4(iIn, pusOut);
1237 /************************************************************************
1238 * VarUI2FromR4 (OLEAUT32.260)
1240 * Convert a VT_R4 to a VT_UI2.
1242 * PARAMS
1243 * fltIn [I] Source
1244 * pusOut [O] Destination
1246 * RETURNS
1247 * Success: S_OK.
1248 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1250 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
1252 return VarUI2FromR8(fltIn, pusOut);
1255 /************************************************************************
1256 * VarUI2FromR8 (OLEAUT32.261)
1258 * Convert a VT_R8 to a VT_UI2.
1260 * PARAMS
1261 * dblIn [I] Source
1262 * pusOut [O] Destination
1264 * RETURNS
1265 * Success: S_OK.
1266 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1268 * NOTES
1269 * See VarI8FromR8() for details concerning rounding.
1271 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
1273 if (dblIn < -0.5 || dblIn >= UI2_MAX + 0.5)
1274 return DISP_E_OVERFLOW;
1275 VARIANT_DutchRound(USHORT, dblIn, *pusOut);
1276 return S_OK;
1279 /************************************************************************
1280 * VarUI2FromDate (OLEAUT32.262)
1282 * Convert a VT_DATE to a VT_UI2.
1284 * PARAMS
1285 * dateIn [I] Source
1286 * pusOut [O] Destination
1288 * RETURNS
1289 * Success: S_OK.
1290 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1292 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
1294 return VarUI2FromR8(dateIn, pusOut);
1297 /************************************************************************
1298 * VarUI2FromCy (OLEAUT32.263)
1300 * Convert a VT_CY to a VT_UI2.
1302 * PARAMS
1303 * cyIn [I] Source
1304 * pusOut [O] Destination
1306 * RETURNS
1307 * Success: S_OK.
1308 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1310 * NOTES
1311 * Negative values >= -5000 will be converted to 0.
1313 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
1315 ULONG i = UI2_MAX + 1;
1317 VarUI4FromCy(cyIn, &i);
1318 return _VarUI2FromUI4(i, pusOut);
1321 /************************************************************************
1322 * VarUI2FromStr (OLEAUT32.264)
1324 * Convert a VT_BSTR to a VT_UI2.
1326 * PARAMS
1327 * strIn [I] Source
1328 * lcid [I] LCID for the conversion
1329 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1330 * pusOut [O] Destination
1332 * RETURNS
1333 * Success: S_OK.
1334 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1335 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1337 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
1339 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
1342 /************************************************************************
1343 * VarUI2FromDisp (OLEAUT32.265)
1345 * Convert a VT_DISPATCH to a VT_UI2.
1347 * PARAMS
1348 * pdispIn [I] Source
1349 * lcid [I] LCID for conversion
1350 * pusOut [O] Destination
1352 * RETURNS
1353 * Success: S_OK.
1354 * Failure: E_INVALIDARG, if the source value is invalid
1355 * DISP_E_OVERFLOW, if the value will not fit in the destination
1356 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1358 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
1360 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0);
1363 /************************************************************************
1364 * VarUI2FromBool (OLEAUT32.266)
1366 * Convert a VT_BOOL to a VT_UI2.
1368 * PARAMS
1369 * boolIn [I] Source
1370 * pusOut [O] Destination
1372 * RETURNS
1373 * S_OK.
1375 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
1377 return _VarUI2FromBool(boolIn, pusOut);
1380 /************************************************************************
1381 * VarUI2FromI1 (OLEAUT32.267)
1383 * Convert a VT_I1 to a VT_UI2.
1385 * PARAMS
1386 * cIn [I] Source
1387 * pusOut [O] Destination
1389 * RETURNS
1390 * Success: S_OK.
1391 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1393 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
1395 return _VarUI2FromI1(cIn, pusOut);
1398 /************************************************************************
1399 * VarUI2FromUI4 (OLEAUT32.268)
1401 * Convert a VT_UI4 to a VT_UI2.
1403 * PARAMS
1404 * ulIn [I] Source
1405 * pusOut [O] Destination
1407 * RETURNS
1408 * Success: S_OK.
1409 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1411 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
1413 return _VarUI2FromUI4(ulIn, pusOut);
1416 /************************************************************************
1417 * VarUI2FromDec (OLEAUT32.269)
1419 * Convert a VT_DECIMAL to a VT_UI2.
1421 * PARAMS
1422 * pDecIn [I] Source
1423 * pusOut [O] Destination
1425 * RETURNS
1426 * Success: S_OK.
1427 * Failure: E_INVALIDARG, if the source value is invalid
1428 * DISP_E_OVERFLOW, if the value will not fit in the destination
1430 HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut)
1432 LONG64 i64;
1433 HRESULT hRet;
1435 hRet = VarI8FromDec(pdecIn, &i64);
1437 if (SUCCEEDED(hRet))
1438 hRet = _VarUI2FromI8(i64, pusOut);
1439 return hRet;
1442 /************************************************************************
1443 * VarUI2FromI8 (OLEAUT32.378)
1445 * Convert a VT_I8 to a VT_UI2.
1447 * PARAMS
1448 * llIn [I] Source
1449 * pusOut [O] Destination
1451 * RETURNS
1452 * Success: S_OK.
1453 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1455 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
1457 return _VarUI2FromI8(llIn, pusOut);
1460 /************************************************************************
1461 * VarUI2FromUI8 (OLEAUT32.379)
1463 * Convert a VT_UI8 to a VT_UI2.
1465 * PARAMS
1466 * ullIn [I] Source
1467 * pusOut [O] Destination
1469 * RETURNS
1470 * Success: S_OK.
1471 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1473 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
1475 return _VarUI2FromUI8(ullIn, pusOut);
1478 /* I4
1481 /************************************************************************
1482 * VarI4FromUI1 (OLEAUT32.58)
1484 * Convert a VT_UI1 to a VT_I4.
1486 * PARAMS
1487 * bIn [I] Source
1488 * piOut [O] Destination
1490 * RETURNS
1491 * S_OK.
1493 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
1495 return _VarI4FromUI1(bIn, piOut);
1498 /************************************************************************
1499 * VarI4FromI2 (OLEAUT32.59)
1501 * Convert a VT_I2 to a VT_I4.
1503 * PARAMS
1504 * sIn [I] Source
1505 * piOut [O] Destination
1507 * RETURNS
1508 * Success: S_OK.
1509 * Failure: E_INVALIDARG, if the source value is invalid
1510 * DISP_E_OVERFLOW, if the value will not fit in the destination
1512 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
1514 return _VarI4FromI2(sIn, piOut);
1517 /************************************************************************
1518 * VarI4FromR4 (OLEAUT32.60)
1520 * Convert a VT_R4 to a VT_I4.
1522 * PARAMS
1523 * fltIn [I] Source
1524 * piOut [O] Destination
1526 * RETURNS
1527 * Success: S_OK.
1528 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1530 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
1532 return VarI4FromR8(fltIn, piOut);
1535 /************************************************************************
1536 * VarI4FromR8 (OLEAUT32.61)
1538 * Convert a VT_R8 to a VT_I4.
1540 * PARAMS
1541 * dblIn [I] Source
1542 * piOut [O] Destination
1544 * RETURNS
1545 * Success: S_OK.
1546 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1548 * NOTES
1549 * See VarI8FromR8() for details concerning rounding.
1551 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
1553 if (dblIn < I4_MIN - 0.5 || dblIn >= I4_MAX + 0.5)
1554 return DISP_E_OVERFLOW;
1555 VARIANT_DutchRound(LONG, dblIn, *piOut);
1556 return S_OK;
1559 /************************************************************************
1560 * VarI4FromCy (OLEAUT32.62)
1562 * Convert a VT_CY to a VT_I4.
1564 * PARAMS
1565 * cyIn [I] Source
1566 * piOut [O] Destination
1568 * RETURNS
1569 * Success: S_OK.
1570 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1572 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
1574 double d = cyIn.int64 / CY_MULTIPLIER_F;
1575 return VarI4FromR8(d, piOut);
1578 /************************************************************************
1579 * VarI4FromDate (OLEAUT32.63)
1581 * Convert a VT_DATE to a VT_I4.
1583 * PARAMS
1584 * dateIn [I] Source
1585 * piOut [O] Destination
1587 * RETURNS
1588 * Success: S_OK.
1589 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1591 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
1593 return VarI4FromR8(dateIn, piOut);
1596 /************************************************************************
1597 * VarI4FromStr (OLEAUT32.64)
1599 * Convert a VT_BSTR to a VT_I4.
1601 * PARAMS
1602 * strIn [I] Source
1603 * lcid [I] LCID for the conversion
1604 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1605 * piOut [O] Destination
1607 * RETURNS
1608 * Success: S_OK.
1609 * Failure: E_INVALIDARG, if any parameter is invalid
1610 * DISP_E_OVERFLOW, if the value will not fit in the destination
1611 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1613 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
1615 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
1618 /************************************************************************
1619 * VarI4FromDisp (OLEAUT32.65)
1621 * Convert a VT_DISPATCH to a VT_I4.
1623 * PARAMS
1624 * pdispIn [I] Source
1625 * lcid [I] LCID for conversion
1626 * piOut [O] Destination
1628 * RETURNS
1629 * Success: S_OK.
1630 * Failure: E_INVALIDARG, if the source value is invalid
1631 * DISP_E_OVERFLOW, if the value will not fit in the destination
1632 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1634 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
1636 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0);
1639 /************************************************************************
1640 * VarI4FromBool (OLEAUT32.66)
1642 * Convert a VT_BOOL to a VT_I4.
1644 * PARAMS
1645 * boolIn [I] Source
1646 * piOut [O] Destination
1648 * RETURNS
1649 * S_OK.
1651 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
1653 return _VarI4FromBool(boolIn, piOut);
1656 /************************************************************************
1657 * VarI4FromI1 (OLEAUT32.209)
1659 * Convert a VT_I1 to a VT_I4.
1661 * PARAMS
1662 * cIn [I] Source
1663 * piOut [O] Destination
1665 * RETURNS
1666 * S_OK.
1668 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
1670 return _VarI4FromI1(cIn, piOut);
1673 /************************************************************************
1674 * VarI4FromUI2 (OLEAUT32.210)
1676 * Convert a VT_UI2 to a VT_I4.
1678 * PARAMS
1679 * usIn [I] Source
1680 * piOut [O] Destination
1682 * RETURNS
1683 * S_OK.
1685 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
1687 return _VarI4FromUI2(usIn, piOut);
1690 /************************************************************************
1691 * VarI4FromUI4 (OLEAUT32.211)
1693 * Convert a VT_UI4 to a VT_I4.
1695 * PARAMS
1696 * ulIn [I] Source
1697 * piOut [O] Destination
1699 * RETURNS
1700 * Success: S_OK.
1701 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1703 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
1705 return _VarI4FromUI4(ulIn, piOut);
1708 /************************************************************************
1709 * VarI4FromDec (OLEAUT32.212)
1711 * Convert a VT_DECIMAL to a VT_I4.
1713 * PARAMS
1714 * pDecIn [I] Source
1715 * piOut [O] Destination
1717 * RETURNS
1718 * Success: S_OK.
1719 * Failure: E_INVALIDARG, if pdecIn is invalid
1720 * DISP_E_OVERFLOW, if the value will not fit in the destination
1722 HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut)
1724 LONG64 i64;
1725 HRESULT hRet;
1727 hRet = VarI8FromDec(pdecIn, &i64);
1729 if (SUCCEEDED(hRet))
1730 hRet = _VarI4FromI8(i64, piOut);
1731 return hRet;
1734 /************************************************************************
1735 * VarI4FromI8 (OLEAUT32.348)
1737 * Convert a VT_I8 to a VT_I4.
1739 * PARAMS
1740 * llIn [I] Source
1741 * piOut [O] Destination
1743 * RETURNS
1744 * Success: S_OK.
1745 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1747 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
1749 return _VarI4FromI8(llIn, piOut);
1752 /************************************************************************
1753 * VarI4FromUI8 (OLEAUT32.349)
1755 * Convert a VT_UI8 to a VT_I4.
1757 * PARAMS
1758 * ullIn [I] Source
1759 * piOut [O] Destination
1761 * RETURNS
1762 * Success: S_OK.
1763 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1765 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
1767 return _VarI4FromUI8(ullIn, piOut);
1770 /* UI4
1773 /************************************************************************
1774 * VarUI4FromUI1 (OLEAUT32.270)
1776 * Convert a VT_UI1 to a VT_UI4.
1778 * PARAMS
1779 * bIn [I] Source
1780 * pulOut [O] Destination
1782 * RETURNS
1783 * S_OK.
1785 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
1787 return _VarUI4FromUI1(bIn, pulOut);
1790 /************************************************************************
1791 * VarUI4FromI2 (OLEAUT32.271)
1793 * Convert a VT_I2 to a VT_UI4.
1795 * PARAMS
1796 * sIn [I] Source
1797 * pulOut [O] Destination
1799 * RETURNS
1800 * Success: S_OK.
1801 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1803 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
1805 return _VarUI4FromI2(sIn, pulOut);
1808 /************************************************************************
1809 * VarUI4FromI4 (OLEAUT32.272)
1811 * Convert a VT_I4 to a VT_UI4.
1813 * PARAMS
1814 * iIn [I] Source
1815 * pulOut [O] Destination
1817 * RETURNS
1818 * Success: S_OK.
1819 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1821 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
1823 return _VarUI4FromI4(iIn, pulOut);
1826 /************************************************************************
1827 * VarUI4FromR4 (OLEAUT32.273)
1829 * Convert a VT_R4 to a VT_UI4.
1831 * PARAMS
1832 * fltIn [I] Source
1833 * pulOut [O] Destination
1835 * RETURNS
1836 * Success: S_OK.
1837 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1839 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
1841 return VarUI4FromR8(fltIn, pulOut);
1844 /************************************************************************
1845 * VarUI4FromR8 (OLEAUT32.274)
1847 * Convert a VT_R8 to a VT_UI4.
1849 * PARAMS
1850 * dblIn [I] Source
1851 * pulOut [O] Destination
1853 * RETURNS
1854 * Success: S_OK.
1855 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1857 * NOTES
1858 * See VarI8FromR8() for details concerning rounding.
1860 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
1862 if (dblIn < -0.5 || dblIn >= UI4_MAX + 0.5)
1863 return DISP_E_OVERFLOW;
1864 VARIANT_DutchRound(ULONG, dblIn, *pulOut);
1865 return S_OK;
1868 /************************************************************************
1869 * VarUI4FromDate (OLEAUT32.275)
1871 * Convert a VT_DATE to a VT_UI4.
1873 * PARAMS
1874 * dateIn [I] Source
1875 * pulOut [O] Destination
1877 * RETURNS
1878 * Success: S_OK.
1879 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1881 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
1883 return VarUI4FromR8(dateIn, pulOut);
1886 /************************************************************************
1887 * VarUI4FromCy (OLEAUT32.276)
1889 * Convert a VT_CY to a VT_UI4.
1891 * PARAMS
1892 * cyIn [I] Source
1893 * pulOut [O] Destination
1895 * RETURNS
1896 * Success: S_OK.
1897 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1899 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
1901 double d = cyIn.int64 / CY_MULTIPLIER_F;
1902 return VarUI4FromR8(d, pulOut);
1905 /************************************************************************
1906 * VarUI4FromStr (OLEAUT32.277)
1908 * Convert a VT_BSTR to a VT_UI4.
1910 * PARAMS
1911 * strIn [I] Source
1912 * lcid [I] LCID for the conversion
1913 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1914 * pulOut [O] Destination
1916 * RETURNS
1917 * Success: S_OK.
1918 * Failure: E_INVALIDARG, if any parameter is invalid
1919 * DISP_E_OVERFLOW, if the value will not fit in the destination
1920 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1922 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
1924 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
1927 /************************************************************************
1928 * VarUI4FromDisp (OLEAUT32.278)
1930 * Convert a VT_DISPATCH to a VT_UI4.
1932 * PARAMS
1933 * pdispIn [I] Source
1934 * lcid [I] LCID for conversion
1935 * pulOut [O] Destination
1937 * RETURNS
1938 * Success: S_OK.
1939 * Failure: E_INVALIDARG, if the source value is invalid
1940 * DISP_E_OVERFLOW, if the value will not fit in the destination
1941 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1943 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
1945 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0);
1948 /************************************************************************
1949 * VarUI4FromBool (OLEAUT32.279)
1951 * Convert a VT_BOOL to a VT_UI4.
1953 * PARAMS
1954 * boolIn [I] Source
1955 * pulOut [O] Destination
1957 * RETURNS
1958 * S_OK.
1960 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
1962 return _VarUI4FromBool(boolIn, pulOut);
1965 /************************************************************************
1966 * VarUI4FromI1 (OLEAUT32.280)
1968 * Convert a VT_I1 to a VT_UI4.
1970 * PARAMS
1971 * cIn [I] Source
1972 * pulOut [O] Destination
1974 * RETURNS
1975 * Success: S_OK.
1976 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1978 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
1980 return _VarUI4FromI1(cIn, pulOut);
1983 /************************************************************************
1984 * VarUI4FromUI2 (OLEAUT32.281)
1986 * Convert a VT_UI2 to a VT_UI4.
1988 * PARAMS
1989 * usIn [I] Source
1990 * pulOut [O] Destination
1992 * RETURNS
1993 * S_OK.
1995 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
1997 return _VarUI4FromUI2(usIn, pulOut);
2000 /************************************************************************
2001 * VarUI4FromDec (OLEAUT32.282)
2003 * Convert a VT_DECIMAL to a VT_UI4.
2005 * PARAMS
2006 * pDecIn [I] Source
2007 * pulOut [O] Destination
2009 * RETURNS
2010 * Success: S_OK.
2011 * Failure: E_INVALIDARG, if pdecIn is invalid
2012 * DISP_E_OVERFLOW, if the value will not fit in the destination
2014 HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut)
2016 LONG64 i64;
2017 HRESULT hRet;
2019 hRet = VarI8FromDec(pdecIn, &i64);
2021 if (SUCCEEDED(hRet))
2022 hRet = _VarUI4FromI8(i64, pulOut);
2023 return hRet;
2026 /************************************************************************
2027 * VarUI4FromI8 (OLEAUT32.425)
2029 * Convert a VT_I8 to a VT_UI4.
2031 * PARAMS
2032 * llIn [I] Source
2033 * pulOut [O] Destination
2035 * RETURNS
2036 * Success: S_OK.
2037 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2039 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
2041 return _VarUI4FromI8(llIn, pulOut);
2044 /************************************************************************
2045 * VarUI4FromUI8 (OLEAUT32.426)
2047 * Convert a VT_UI8 to a VT_UI4.
2049 * PARAMS
2050 * ullIn [I] Source
2051 * pulOut [O] Destination
2053 * RETURNS
2054 * Success: S_OK.
2055 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2057 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
2059 return _VarUI4FromUI8(ullIn, pulOut);
2062 /* I8
2065 /************************************************************************
2066 * VarI8FromUI1 (OLEAUT32.333)
2068 * Convert a VT_UI1 to a VT_I8.
2070 * PARAMS
2071 * bIn [I] Source
2072 * pi64Out [O] Destination
2074 * RETURNS
2075 * S_OK.
2077 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
2079 return _VarI8FromUI1(bIn, pi64Out);
2083 /************************************************************************
2084 * VarI8FromI2 (OLEAUT32.334)
2086 * Convert a VT_I2 to a VT_I8.
2088 * PARAMS
2089 * sIn [I] Source
2090 * pi64Out [O] Destination
2092 * RETURNS
2093 * S_OK.
2095 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
2097 return _VarI8FromI2(sIn, pi64Out);
2100 /************************************************************************
2101 * VarI8FromR4 (OLEAUT32.335)
2103 * Convert a VT_R4 to a VT_I8.
2105 * PARAMS
2106 * fltIn [I] Source
2107 * pi64Out [O] Destination
2109 * RETURNS
2110 * Success: S_OK.
2111 * Failure: E_INVALIDARG, if the source value is invalid
2112 * DISP_E_OVERFLOW, if the value will not fit in the destination
2114 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
2116 return VarI8FromR8(fltIn, pi64Out);
2119 /************************************************************************
2120 * VarI8FromR8 (OLEAUT32.336)
2122 * Convert a VT_R8 to a VT_I8.
2124 * PARAMS
2125 * dblIn [I] Source
2126 * pi64Out [O] Destination
2128 * RETURNS
2129 * Success: S_OK.
2130 * Failure: E_INVALIDARG, if the source value is invalid
2131 * DISP_E_OVERFLOW, if the value will not fit in the destination
2133 * NOTES
2134 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2135 * very high or low values will not be accurately converted.
2137 * Numbers are rounded using Dutch rounding, as follows:
2139 *| Fractional Part Sign Direction Example
2140 *| --------------- ---- --------- -------
2141 *| < 0.5 + Down 0.4 -> 0.0
2142 *| < 0.5 - Up -0.4 -> 0.0
2143 *| > 0.5 + Up 0.6 -> 1.0
2144 *| < 0.5 - Up -0.6 -> -1.0
2145 *| = 0.5 + Up/Down Down if even, Up if odd
2146 *| = 0.5 - Up/Down Up if even, Down if odd
2148 * This system is often used in supermarkets.
2150 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
2152 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
2153 return DISP_E_OVERFLOW;
2154 VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
2155 return S_OK;
2158 /************************************************************************
2159 * VarI8FromCy (OLEAUT32.337)
2161 * Convert a VT_CY to a VT_I8.
2163 * PARAMS
2164 * cyIn [I] Source
2165 * pi64Out [O] Destination
2167 * RETURNS
2168 * S_OK.
2170 * NOTES
2171 * All negative numbers are rounded down by 1, including those that are
2172 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2173 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2174 * for details.
2176 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
2178 *pi64Out = cyIn.int64 / CY_MULTIPLIER;
2180 if (cyIn.int64 < 0)
2181 (*pi64Out)--; /* Mimic Win32 bug */
2182 else
2184 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2186 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1)))
2187 (*pi64Out)++;
2189 return S_OK;
2192 /************************************************************************
2193 * VarI8FromDate (OLEAUT32.338)
2195 * Convert a VT_DATE to a VT_I8.
2197 * PARAMS
2198 * dateIn [I] Source
2199 * pi64Out [O] Destination
2201 * RETURNS
2202 * Success: S_OK.
2203 * Failure: E_INVALIDARG, if the source value is invalid
2204 * DISP_E_OVERFLOW, if the value will not fit in the destination
2205 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2207 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
2209 return VarI8FromR8(dateIn, pi64Out);
2212 /************************************************************************
2213 * VarI8FromStr (OLEAUT32.339)
2215 * Convert a VT_BSTR to a VT_I8.
2217 * PARAMS
2218 * strIn [I] Source
2219 * lcid [I] LCID for the conversion
2220 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2221 * pi64Out [O] Destination
2223 * RETURNS
2224 * Success: S_OK.
2225 * Failure: E_INVALIDARG, if the source value is invalid
2226 * DISP_E_OVERFLOW, if the value will not fit in the destination
2227 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2229 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
2231 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
2234 /************************************************************************
2235 * VarI8FromDisp (OLEAUT32.340)
2237 * Convert a VT_DISPATCH to a VT_I8.
2239 * PARAMS
2240 * pdispIn [I] Source
2241 * lcid [I] LCID for conversion
2242 * pi64Out [O] Destination
2244 * RETURNS
2245 * Success: S_OK.
2246 * Failure: E_INVALIDARG, if the source value is invalid
2247 * DISP_E_OVERFLOW, if the value will not fit in the destination
2248 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2250 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
2252 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0);
2255 /************************************************************************
2256 * VarI8FromBool (OLEAUT32.341)
2258 * Convert a VT_BOOL to a VT_I8.
2260 * PARAMS
2261 * boolIn [I] Source
2262 * pi64Out [O] Destination
2264 * RETURNS
2265 * S_OK.
2267 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
2269 return VarI8FromI2(boolIn, pi64Out);
2272 /************************************************************************
2273 * VarI8FromI1 (OLEAUT32.342)
2275 * Convert a VT_I1 to a VT_I8.
2277 * PARAMS
2278 * cIn [I] Source
2279 * pi64Out [O] Destination
2281 * RETURNS
2282 * S_OK.
2284 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
2286 return _VarI8FromI1(cIn, pi64Out);
2289 /************************************************************************
2290 * VarI8FromUI2 (OLEAUT32.343)
2292 * Convert a VT_UI2 to a VT_I8.
2294 * PARAMS
2295 * usIn [I] Source
2296 * pi64Out [O] Destination
2298 * RETURNS
2299 * S_OK.
2301 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
2303 return _VarI8FromUI2(usIn, pi64Out);
2306 /************************************************************************
2307 * VarI8FromUI4 (OLEAUT32.344)
2309 * Convert a VT_UI4 to a VT_I8.
2311 * PARAMS
2312 * ulIn [I] Source
2313 * pi64Out [O] Destination
2315 * RETURNS
2316 * S_OK.
2318 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
2320 return _VarI8FromUI4(ulIn, pi64Out);
2323 /************************************************************************
2324 * VarI8FromDec (OLEAUT32.345)
2326 * Convert a VT_DECIMAL to a VT_I8.
2328 * PARAMS
2329 * pDecIn [I] Source
2330 * pi64Out [O] Destination
2332 * RETURNS
2333 * Success: S_OK.
2334 * Failure: E_INVALIDARG, if the source value is invalid
2335 * DISP_E_OVERFLOW, if the value will not fit in the destination
2337 HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out)
2339 if (!DEC_SCALE(pdecIn))
2341 /* This decimal is just a 96 bit integer */
2342 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2343 return E_INVALIDARG;
2345 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000)
2346 return DISP_E_OVERFLOW;
2348 if (DEC_SIGN(pdecIn))
2349 *pi64Out = -DEC_LO64(pdecIn);
2350 else
2351 *pi64Out = DEC_LO64(pdecIn);
2352 return S_OK;
2354 else
2356 /* Decimal contains a floating point number */
2357 HRESULT hRet;
2358 double dbl;
2360 hRet = VarR8FromDec(pdecIn, &dbl);
2361 if (SUCCEEDED(hRet))
2362 hRet = VarI8FromR8(dbl, pi64Out);
2363 return hRet;
2367 /************************************************************************
2368 * VarI8FromUI8 (OLEAUT32.427)
2370 * Convert a VT_UI8 to a VT_I8.
2372 * PARAMS
2373 * ullIn [I] Source
2374 * pi64Out [O] Destination
2376 * RETURNS
2377 * Success: S_OK.
2378 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2380 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
2382 return _VarI8FromUI8(ullIn, pi64Out);
2385 /* UI8
2388 /************************************************************************
2389 * VarUI8FromI8 (OLEAUT32.428)
2391 * Convert a VT_I8 to a VT_UI8.
2393 * PARAMS
2394 * ulIn [I] Source
2395 * pui64Out [O] Destination
2397 * RETURNS
2398 * Success: S_OK.
2399 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2401 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
2403 return _VarUI8FromI8(llIn, pui64Out);
2406 /************************************************************************
2407 * VarUI8FromUI1 (OLEAUT32.429)
2409 * Convert a VT_UI1 to a VT_UI8.
2411 * PARAMS
2412 * bIn [I] Source
2413 * pui64Out [O] Destination
2415 * RETURNS
2416 * S_OK.
2418 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
2420 return _VarUI8FromUI1(bIn, pui64Out);
2423 /************************************************************************
2424 * VarUI8FromI2 (OLEAUT32.430)
2426 * Convert a VT_I2 to a VT_UI8.
2428 * PARAMS
2429 * sIn [I] Source
2430 * pui64Out [O] Destination
2432 * RETURNS
2433 * S_OK.
2435 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
2437 return _VarUI8FromI2(sIn, pui64Out);
2440 /************************************************************************
2441 * VarUI8FromR4 (OLEAUT32.431)
2443 * Convert a VT_R4 to a VT_UI8.
2445 * PARAMS
2446 * fltIn [I] Source
2447 * pui64Out [O] Destination
2449 * RETURNS
2450 * Success: S_OK.
2451 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2453 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
2455 return VarUI8FromR8(fltIn, pui64Out);
2458 /************************************************************************
2459 * VarUI8FromR8 (OLEAUT32.432)
2461 * Convert a VT_R8 to a VT_UI8.
2463 * PARAMS
2464 * dblIn [I] Source
2465 * pui64Out [O] Destination
2467 * RETURNS
2468 * Success: S_OK.
2469 * Failure: E_INVALIDARG, if the source value is invalid
2470 * DISP_E_OVERFLOW, if the value will not fit in the destination
2472 * NOTES
2473 * See VarI8FromR8() for details concerning rounding.
2475 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
2477 if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
2478 return DISP_E_OVERFLOW;
2479 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
2480 return S_OK;
2483 /************************************************************************
2484 * VarUI8FromCy (OLEAUT32.433)
2486 * Convert a VT_CY to a VT_UI8.
2488 * PARAMS
2489 * cyIn [I] Source
2490 * pui64Out [O] Destination
2492 * RETURNS
2493 * Success: S_OK.
2494 * Failure: E_INVALIDARG, if the source value is invalid
2495 * DISP_E_OVERFLOW, if the value will not fit in the destination
2497 * NOTES
2498 * Negative values >= -5000 will be converted to 0.
2500 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
2502 if (cyIn.int64 < 0)
2504 if (cyIn.int64 < -CY_HALF)
2505 return DISP_E_OVERFLOW;
2506 *pui64Out = 0;
2508 else
2510 *pui64Out = cyIn.int64 / CY_MULTIPLIER;
2512 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2514 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1)))
2515 (*pui64Out)++;
2517 return S_OK;
2520 /************************************************************************
2521 * VarUI8FromDate (OLEAUT32.434)
2523 * Convert a VT_DATE to a VT_UI8.
2525 * PARAMS
2526 * dateIn [I] Source
2527 * pui64Out [O] Destination
2529 * RETURNS
2530 * Success: S_OK.
2531 * Failure: E_INVALIDARG, if the source value is invalid
2532 * DISP_E_OVERFLOW, if the value will not fit in the destination
2533 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2535 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
2537 return VarUI8FromR8(dateIn, pui64Out);
2540 /************************************************************************
2541 * VarUI8FromStr (OLEAUT32.435)
2543 * Convert a VT_BSTR to a VT_UI8.
2545 * PARAMS
2546 * strIn [I] Source
2547 * lcid [I] LCID for the conversion
2548 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2549 * pui64Out [O] Destination
2551 * RETURNS
2552 * Success: S_OK.
2553 * Failure: E_INVALIDARG, if the source value is invalid
2554 * DISP_E_OVERFLOW, if the value will not fit in the destination
2555 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2557 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
2559 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
2562 /************************************************************************
2563 * VarUI8FromDisp (OLEAUT32.436)
2565 * Convert a VT_DISPATCH to a VT_UI8.
2567 * PARAMS
2568 * pdispIn [I] Source
2569 * lcid [I] LCID for conversion
2570 * pui64Out [O] Destination
2572 * RETURNS
2573 * Success: S_OK.
2574 * Failure: E_INVALIDARG, if the source value is invalid
2575 * DISP_E_OVERFLOW, if the value will not fit in the destination
2576 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2578 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
2580 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0);
2583 /************************************************************************
2584 * VarUI8FromBool (OLEAUT32.437)
2586 * Convert a VT_BOOL to a VT_UI8.
2588 * PARAMS
2589 * boolIn [I] Source
2590 * pui64Out [O] Destination
2592 * RETURNS
2593 * Success: S_OK.
2594 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2596 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
2598 return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
2600 /************************************************************************
2601 * VarUI8FromI1 (OLEAUT32.438)
2603 * Convert a VT_I1 to a VT_UI8.
2605 * PARAMS
2606 * cIn [I] Source
2607 * pui64Out [O] Destination
2609 * RETURNS
2610 * Success: S_OK.
2611 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2613 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
2615 return _VarUI8FromI1(cIn, pui64Out);
2618 /************************************************************************
2619 * VarUI8FromUI2 (OLEAUT32.439)
2621 * Convert a VT_UI2 to a VT_UI8.
2623 * PARAMS
2624 * usIn [I] Source
2625 * pui64Out [O] Destination
2627 * RETURNS
2628 * S_OK.
2630 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
2632 return _VarUI8FromUI2(usIn, pui64Out);
2635 /************************************************************************
2636 * VarUI8FromUI4 (OLEAUT32.440)
2638 * Convert a VT_UI4 to a VT_UI8.
2640 * PARAMS
2641 * ulIn [I] Source
2642 * pui64Out [O] Destination
2644 * RETURNS
2645 * S_OK.
2647 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
2649 return _VarUI8FromUI4(ulIn, pui64Out);
2652 /************************************************************************
2653 * VarUI8FromDec (OLEAUT32.441)
2655 * Convert a VT_DECIMAL to a VT_UI8.
2657 * PARAMS
2658 * pDecIn [I] Source
2659 * pui64Out [O] Destination
2661 * RETURNS
2662 * Success: S_OK.
2663 * Failure: E_INVALIDARG, if the source value is invalid
2664 * DISP_E_OVERFLOW, if the value will not fit in the destination
2666 * NOTES
2667 * Under native Win32, if the source value has a scale of 0, its sign is
2668 * ignored, i.e. this function takes the absolute value rather than fail
2669 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2670 * (use VarAbs() on pDecIn first if you really want this behaviour).
2672 HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out)
2674 if (!DEC_SCALE(pdecIn))
2676 /* This decimal is just a 96 bit integer */
2677 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2678 return E_INVALIDARG;
2680 if (DEC_HI32(pdecIn))
2681 return DISP_E_OVERFLOW;
2683 if (DEC_SIGN(pdecIn))
2685 WARN("Sign would be ignored under Win32!\n");
2686 return DISP_E_OVERFLOW;
2689 *pui64Out = DEC_LO64(pdecIn);
2690 return S_OK;
2692 else
2694 /* Decimal contains a floating point number */
2695 HRESULT hRet;
2696 double dbl;
2698 hRet = VarR8FromDec(pdecIn, &dbl);
2699 if (SUCCEEDED(hRet))
2700 hRet = VarUI8FromR8(dbl, pui64Out);
2701 return hRet;
2705 /* R4
2708 /************************************************************************
2709 * VarR4FromUI1 (OLEAUT32.68)
2711 * Convert a VT_UI1 to a VT_R4.
2713 * PARAMS
2714 * bIn [I] Source
2715 * pFltOut [O] Destination
2717 * RETURNS
2718 * S_OK.
2720 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
2722 return _VarR4FromUI1(bIn, pFltOut);
2725 /************************************************************************
2726 * VarR4FromI2 (OLEAUT32.69)
2728 * Convert a VT_I2 to a VT_R4.
2730 * PARAMS
2731 * sIn [I] Source
2732 * pFltOut [O] Destination
2734 * RETURNS
2735 * S_OK.
2737 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
2739 return _VarR4FromI2(sIn, pFltOut);
2742 /************************************************************************
2743 * VarR4FromI4 (OLEAUT32.70)
2745 * Convert a VT_I4 to a VT_R4.
2747 * PARAMS
2748 * sIn [I] Source
2749 * pFltOut [O] Destination
2751 * RETURNS
2752 * S_OK.
2754 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
2756 return _VarR4FromI4(lIn, pFltOut);
2759 /************************************************************************
2760 * VarR4FromR8 (OLEAUT32.71)
2762 * Convert a VT_R8 to a VT_R4.
2764 * PARAMS
2765 * dblIn [I] Source
2766 * pFltOut [O] Destination
2768 * RETURNS
2769 * Success: S_OK.
2770 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2772 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
2774 double d = dblIn < 0.0 ? -dblIn : dblIn;
2775 if (d > R4_MAX) return DISP_E_OVERFLOW;
2776 *pFltOut = dblIn;
2777 return S_OK;
2780 /************************************************************************
2781 * VarR4FromCy (OLEAUT32.72)
2783 * Convert a VT_CY to a VT_R4.
2785 * PARAMS
2786 * cyIn [I] Source
2787 * pFltOut [O] Destination
2789 * RETURNS
2790 * S_OK.
2792 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
2794 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
2795 return S_OK;
2798 /************************************************************************
2799 * VarR4FromDate (OLEAUT32.73)
2801 * Convert a VT_DATE to a VT_R4.
2803 * PARAMS
2804 * dateIn [I] Source
2805 * pFltOut [O] Destination
2807 * RETURNS
2808 * Success: S_OK.
2809 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2811 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
2813 return VarR4FromR8(dateIn, pFltOut);
2816 /************************************************************************
2817 * VarR4FromStr (OLEAUT32.74)
2819 * Convert a VT_BSTR to a VT_R4.
2821 * PARAMS
2822 * strIn [I] Source
2823 * lcid [I] LCID for the conversion
2824 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2825 * pFltOut [O] Destination
2827 * RETURNS
2828 * Success: S_OK.
2829 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2830 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2832 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
2834 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
2837 /************************************************************************
2838 * VarR4FromDisp (OLEAUT32.75)
2840 * Convert a VT_DISPATCH to a VT_R4.
2842 * PARAMS
2843 * pdispIn [I] Source
2844 * lcid [I] LCID for conversion
2845 * pFltOut [O] Destination
2847 * RETURNS
2848 * Success: S_OK.
2849 * Failure: E_INVALIDARG, if the source value is invalid
2850 * DISP_E_OVERFLOW, if the value will not fit in the destination
2851 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2853 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
2855 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0);
2858 /************************************************************************
2859 * VarR4FromBool (OLEAUT32.76)
2861 * Convert a VT_BOOL to a VT_R4.
2863 * PARAMS
2864 * boolIn [I] Source
2865 * pFltOut [O] Destination
2867 * RETURNS
2868 * S_OK.
2870 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2872 return VarR4FromI2(boolIn, pFltOut);
2875 /************************************************************************
2876 * VarR4FromI1 (OLEAUT32.213)
2878 * Convert a VT_I1 to a VT_R4.
2880 * PARAMS
2881 * cIn [I] Source
2882 * pFltOut [O] Destination
2884 * RETURNS
2885 * Success: S_OK.
2886 * Failure: E_INVALIDARG, if the source value is invalid
2887 * DISP_E_OVERFLOW, if the value will not fit in the destination
2888 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2890 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2892 return _VarR4FromI1(cIn, pFltOut);
2895 /************************************************************************
2896 * VarR4FromUI2 (OLEAUT32.214)
2898 * Convert a VT_UI2 to a VT_R4.
2900 * PARAMS
2901 * usIn [I] Source
2902 * pFltOut [O] Destination
2904 * RETURNS
2905 * Success: S_OK.
2906 * Failure: E_INVALIDARG, if the source value is invalid
2907 * DISP_E_OVERFLOW, if the value will not fit in the destination
2908 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2910 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2912 return _VarR4FromUI2(usIn, pFltOut);
2915 /************************************************************************
2916 * VarR4FromUI4 (OLEAUT32.215)
2918 * Convert a VT_UI4 to a VT_R4.
2920 * PARAMS
2921 * ulIn [I] Source
2922 * pFltOut [O] Destination
2924 * RETURNS
2925 * Success: S_OK.
2926 * Failure: E_INVALIDARG, if the source value is invalid
2927 * DISP_E_OVERFLOW, if the value will not fit in the destination
2928 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2930 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2932 return _VarR4FromUI4(ulIn, pFltOut);
2935 /************************************************************************
2936 * VarR4FromDec (OLEAUT32.216)
2938 * Convert a VT_DECIMAL to a VT_R4.
2940 * PARAMS
2941 * pDecIn [I] Source
2942 * pFltOut [O] Destination
2944 * RETURNS
2945 * Success: S_OK.
2946 * Failure: E_INVALIDARG, if the source value is invalid.
2948 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
2950 BYTE scale = DEC_SCALE(pDecIn);
2951 int divisor = 1;
2952 double highPart;
2954 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2955 return E_INVALIDARG;
2957 while (scale--)
2958 divisor *= 10;
2960 if (DEC_SIGN(pDecIn))
2961 divisor = -divisor;
2963 if (DEC_HI32(pDecIn))
2965 highPart = (double)DEC_HI32(pDecIn) / (double)divisor;
2966 highPart *= 4294967296.0F;
2967 highPart *= 4294967296.0F;
2969 else
2970 highPart = 0.0;
2972 *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart;
2973 return S_OK;
2976 /************************************************************************
2977 * VarR4FromI8 (OLEAUT32.360)
2979 * Convert a VT_I8 to a VT_R4.
2981 * PARAMS
2982 * ullIn [I] Source
2983 * pFltOut [O] Destination
2985 * RETURNS
2986 * S_OK.
2988 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2990 return _VarR4FromI8(llIn, pFltOut);
2993 /************************************************************************
2994 * VarR4FromUI8 (OLEAUT32.361)
2996 * Convert a VT_UI8 to a VT_R4.
2998 * PARAMS
2999 * ullIn [I] Source
3000 * pFltOut [O] Destination
3002 * RETURNS
3003 * S_OK.
3005 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
3007 return _VarR4FromUI8(ullIn, pFltOut);
3010 /************************************************************************
3011 * VarR4CmpR8 (OLEAUT32.316)
3013 * Compare a VT_R4 to a VT_R8.
3015 * PARAMS
3016 * fltLeft [I] Source
3017 * dblRight [I] Value to compare
3019 * RETURNS
3020 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3021 * equal to or greater than dblRight respectively.
3023 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3025 if (fltLeft < dblRight)
3026 return VARCMP_LT;
3027 else if (fltLeft > dblRight)
3028 return VARCMP_GT;
3029 return VARCMP_EQ;
3032 /* R8
3035 /************************************************************************
3036 * VarR8FromUI1 (OLEAUT32.78)
3038 * Convert a VT_UI1 to a VT_R8.
3040 * PARAMS
3041 * bIn [I] Source
3042 * pDblOut [O] Destination
3044 * RETURNS
3045 * S_OK.
3047 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3049 return _VarR8FromUI1(bIn, pDblOut);
3052 /************************************************************************
3053 * VarR8FromI2 (OLEAUT32.79)
3055 * Convert a VT_I2 to a VT_R8.
3057 * PARAMS
3058 * sIn [I] Source
3059 * pDblOut [O] Destination
3061 * RETURNS
3062 * S_OK.
3064 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3066 return _VarR8FromI2(sIn, pDblOut);
3069 /************************************************************************
3070 * VarR8FromI4 (OLEAUT32.80)
3072 * Convert a VT_I4 to a VT_R8.
3074 * PARAMS
3075 * sIn [I] Source
3076 * pDblOut [O] Destination
3078 * RETURNS
3079 * S_OK.
3081 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3083 return _VarR8FromI4(lIn, pDblOut);
3086 /************************************************************************
3087 * VarR8FromR4 (OLEAUT32.81)
3089 * Convert a VT_R4 to a VT_R8.
3091 * PARAMS
3092 * fltIn [I] Source
3093 * pDblOut [O] Destination
3095 * RETURNS
3096 * S_OK.
3098 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3100 return _VarR8FromR4(fltIn, pDblOut);
3103 /************************************************************************
3104 * VarR8FromCy (OLEAUT32.82)
3106 * Convert a VT_CY to a VT_R8.
3108 * PARAMS
3109 * cyIn [I] Source
3110 * pDblOut [O] Destination
3112 * RETURNS
3113 * S_OK.
3115 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3117 return _VarR8FromCy(cyIn, pDblOut);
3120 /************************************************************************
3121 * VarR8FromDate (OLEAUT32.83)
3123 * Convert a VT_DATE to a VT_R8.
3125 * PARAMS
3126 * dateIn [I] Source
3127 * pDblOut [O] Destination
3129 * RETURNS
3130 * S_OK.
3132 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3134 return _VarR8FromDate(dateIn, pDblOut);
3137 /************************************************************************
3138 * VarR8FromStr (OLEAUT32.84)
3140 * Convert a VT_BSTR to a VT_R8.
3142 * PARAMS
3143 * strIn [I] Source
3144 * lcid [I] LCID for the conversion
3145 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3146 * pDblOut [O] Destination
3148 * RETURNS
3149 * Success: S_OK.
3150 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3151 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3153 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3155 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3158 /************************************************************************
3159 * VarR8FromDisp (OLEAUT32.85)
3161 * Convert a VT_DISPATCH to a VT_R8.
3163 * PARAMS
3164 * pdispIn [I] Source
3165 * lcid [I] LCID for conversion
3166 * pDblOut [O] Destination
3168 * RETURNS
3169 * Success: S_OK.
3170 * Failure: E_INVALIDARG, if the source value is invalid
3171 * DISP_E_OVERFLOW, if the value will not fit in the destination
3172 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3174 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3176 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0);
3179 /************************************************************************
3180 * VarR8FromBool (OLEAUT32.86)
3182 * Convert a VT_BOOL to a VT_R8.
3184 * PARAMS
3185 * boolIn [I] Source
3186 * pDblOut [O] Destination
3188 * RETURNS
3189 * S_OK.
3191 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3193 return VarR8FromI2(boolIn, pDblOut);
3196 /************************************************************************
3197 * VarR8FromI1 (OLEAUT32.217)
3199 * Convert a VT_I1 to a VT_R8.
3201 * PARAMS
3202 * cIn [I] Source
3203 * pDblOut [O] Destination
3205 * RETURNS
3206 * Success: S_OK.
3207 * Failure: E_INVALIDARG, if the source value is invalid
3208 * DISP_E_OVERFLOW, if the value will not fit in the destination
3209 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3211 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3213 return _VarR8FromI1(cIn, pDblOut);
3216 /************************************************************************
3217 * VarR8FromUI2 (OLEAUT32.218)
3219 * Convert a VT_UI2 to a VT_R8.
3221 * PARAMS
3222 * usIn [I] Source
3223 * pDblOut [O] Destination
3225 * RETURNS
3226 * Success: S_OK.
3227 * Failure: E_INVALIDARG, if the source value is invalid
3228 * DISP_E_OVERFLOW, if the value will not fit in the destination
3229 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3231 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3233 return _VarR8FromUI2(usIn, pDblOut);
3236 /************************************************************************
3237 * VarR8FromUI4 (OLEAUT32.219)
3239 * Convert a VT_UI4 to a VT_R8.
3241 * PARAMS
3242 * ulIn [I] Source
3243 * pDblOut [O] Destination
3245 * RETURNS
3246 * Success: S_OK.
3247 * Failure: E_INVALIDARG, if the source value is invalid
3248 * DISP_E_OVERFLOW, if the value will not fit in the destination
3249 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3251 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3253 return _VarR8FromUI4(ulIn, pDblOut);
3256 /************************************************************************
3257 * VarR8FromDec (OLEAUT32.220)
3259 * Convert a VT_DECIMAL to a VT_R8.
3261 * PARAMS
3262 * pDecIn [I] Source
3263 * pDblOut [O] Destination
3265 * RETURNS
3266 * Success: S_OK.
3267 * Failure: E_INVALIDARG, if the source value is invalid.
3269 HRESULT WINAPI VarR8FromDec(const DECIMAL* pDecIn, double *pDblOut)
3271 BYTE scale = DEC_SCALE(pDecIn);
3272 double divisor = 1.0, highPart;
3274 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3275 return E_INVALIDARG;
3277 while (scale--)
3278 divisor *= 10;
3280 if (DEC_SIGN(pDecIn))
3281 divisor = -divisor;
3283 if (DEC_HI32(pDecIn))
3285 highPart = (double)DEC_HI32(pDecIn) / divisor;
3286 highPart *= 4294967296.0F;
3287 highPart *= 4294967296.0F;
3289 else
3290 highPart = 0.0;
3292 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3293 return S_OK;
3296 /************************************************************************
3297 * VarR8FromI8 (OLEAUT32.362)
3299 * Convert a VT_I8 to a VT_R8.
3301 * PARAMS
3302 * ullIn [I] Source
3303 * pDblOut [O] Destination
3305 * RETURNS
3306 * S_OK.
3308 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3310 return _VarR8FromI8(llIn, pDblOut);
3313 /************************************************************************
3314 * VarR8FromUI8 (OLEAUT32.363)
3316 * Convert a VT_UI8 to a VT_R8.
3318 * PARAMS
3319 * ullIn [I] Source
3320 * pDblOut [O] Destination
3322 * RETURNS
3323 * S_OK.
3325 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3327 return _VarR8FromUI8(ullIn, pDblOut);
3330 /************************************************************************
3331 * VarR8Pow (OLEAUT32.315)
3333 * Raise a VT_R8 to a power.
3335 * PARAMS
3336 * dblLeft [I] Source
3337 * dblPow [I] Power to raise dblLeft by
3338 * pDblOut [O] Destination
3340 * RETURNS
3341 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3343 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3345 *pDblOut = pow(dblLeft, dblPow);
3346 return S_OK;
3349 /************************************************************************
3350 * VarR8Round (OLEAUT32.317)
3352 * Round a VT_R8 to a given number of decimal points.
3354 * PARAMS
3355 * dblIn [I] Source
3356 * nDig [I] Number of decimal points to round to
3357 * pDblOut [O] Destination for rounded number
3359 * RETURNS
3360 * Success: S_OK. pDblOut is rounded to nDig digits.
3361 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3363 * NOTES
3364 * The native version of this function rounds using the internal
3365 * binary representation of the number. Wine uses the dutch rounding
3366 * convention, so therefore small differences can occur in the value returned.
3367 * MSDN says that you should use your own rounding function if you want
3368 * rounding to be predictable in your application.
3370 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3372 double scale, whole, fract;
3374 if (nDig < 0)
3375 return E_INVALIDARG;
3377 scale = pow(10.0, nDig);
3379 dblIn *= scale;
3380 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3381 fract = dblIn - whole;
3383 if (fract > 0.5)
3384 dblIn = whole + 1.0;
3385 else if (fract == 0.5)
3386 dblIn = whole + fmod(whole, 2.0);
3387 else if (fract >= 0.0)
3388 dblIn = whole;
3389 else if (fract == -0.5)
3390 dblIn = whole - fmod(whole, 2.0);
3391 else if (fract > -0.5)
3392 dblIn = whole;
3393 else
3394 dblIn = whole - 1.0;
3396 *pDblOut = dblIn / scale;
3397 return S_OK;
3400 /* CY
3403 /* Powers of 10 from 0..4 D.P. */
3404 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3405 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3407 /************************************************************************
3408 * VarCyFromUI1 (OLEAUT32.98)
3410 * Convert a VT_UI1 to a VT_CY.
3412 * PARAMS
3413 * bIn [I] Source
3414 * pCyOut [O] Destination
3416 * RETURNS
3417 * Success: S_OK.
3418 * Failure: E_INVALIDARG, if the source value is invalid
3419 * DISP_E_OVERFLOW, if the value will not fit in the destination
3420 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3422 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3424 pCyOut->int64 = (ULONG64)bIn * CY_MULTIPLIER;
3425 return S_OK;
3428 /************************************************************************
3429 * VarCyFromI2 (OLEAUT32.99)
3431 * Convert a VT_I2 to a VT_CY.
3433 * PARAMS
3434 * sIn [I] Source
3435 * pCyOut [O] Destination
3437 * RETURNS
3438 * Success: S_OK.
3439 * Failure: E_INVALIDARG, if the source value is invalid
3440 * DISP_E_OVERFLOW, if the value will not fit in the destination
3441 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3443 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3445 pCyOut->int64 = (LONG64)sIn * CY_MULTIPLIER;
3446 return S_OK;
3449 /************************************************************************
3450 * VarCyFromI4 (OLEAUT32.100)
3452 * Convert a VT_I4 to a VT_CY.
3454 * PARAMS
3455 * sIn [I] Source
3456 * pCyOut [O] Destination
3458 * RETURNS
3459 * Success: S_OK.
3460 * Failure: E_INVALIDARG, if the source value is invalid
3461 * DISP_E_OVERFLOW, if the value will not fit in the destination
3462 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3464 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3466 pCyOut->int64 = (LONG64)lIn * CY_MULTIPLIER;
3467 return S_OK;
3470 /************************************************************************
3471 * VarCyFromR4 (OLEAUT32.101)
3473 * Convert a VT_R4 to a VT_CY.
3475 * PARAMS
3476 * fltIn [I] Source
3477 * pCyOut [O] Destination
3479 * RETURNS
3480 * Success: S_OK.
3481 * Failure: E_INVALIDARG, if the source value is invalid
3482 * DISP_E_OVERFLOW, if the value will not fit in the destination
3483 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3485 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3487 return VarCyFromR8(fltIn, pCyOut);
3490 /************************************************************************
3491 * VarCyFromR8 (OLEAUT32.102)
3493 * Convert a VT_R8 to a VT_CY.
3495 * PARAMS
3496 * dblIn [I] Source
3497 * pCyOut [O] Destination
3499 * RETURNS
3500 * Success: S_OK.
3501 * Failure: E_INVALIDARG, if the source value is invalid
3502 * DISP_E_OVERFLOW, if the value will not fit in the destination
3503 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3505 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3507 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3508 /* This code gives identical results to Win32 on Intel.
3509 * Here we use fp exceptions to catch overflows when storing the value.
3511 static const unsigned short r8_fpcontrol = 0x137f;
3512 static const double r8_multiplier = CY_MULTIPLIER_F;
3513 unsigned short old_fpcontrol, result_fpstatus;
3515 /* Clear exceptions, save the old fp state and load the new state */
3516 __asm__ __volatile__( "fnclex" );
3517 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3518 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3519 /* Perform the conversion. */
3520 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3521 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3522 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3523 /* Save the resulting fp state, load the old state and clear exceptions */
3524 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3525 __asm__ __volatile__( "fnclex" );
3526 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3528 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3529 return DISP_E_OVERFLOW;
3530 #else
3531 /* This version produces slightly different results for boundary cases */
3532 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3533 return DISP_E_OVERFLOW;
3534 dblIn *= CY_MULTIPLIER_F;
3535 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3536 #endif
3537 return S_OK;
3540 /************************************************************************
3541 * VarCyFromDate (OLEAUT32.103)
3543 * Convert a VT_DATE to a VT_CY.
3545 * PARAMS
3546 * dateIn [I] Source
3547 * pCyOut [O] Destination
3549 * RETURNS
3550 * Success: S_OK.
3551 * Failure: E_INVALIDARG, if the source value is invalid
3552 * DISP_E_OVERFLOW, if the value will not fit in the destination
3553 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3555 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3557 return VarCyFromR8(dateIn, pCyOut);
3560 /************************************************************************
3561 * VarCyFromStr (OLEAUT32.104)
3563 * Convert a VT_BSTR to a VT_CY.
3565 * PARAMS
3566 * strIn [I] Source
3567 * lcid [I] LCID for the conversion
3568 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3569 * pCyOut [O] Destination
3571 * RETURNS
3572 * Success: S_OK.
3573 * Failure: E_INVALIDARG, if the source value is invalid
3574 * DISP_E_OVERFLOW, if the value will not fit in the destination
3575 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3577 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3579 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3582 /************************************************************************
3583 * VarCyFromDisp (OLEAUT32.105)
3585 * Convert a VT_DISPATCH to a VT_CY.
3587 * PARAMS
3588 * pdispIn [I] Source
3589 * lcid [I] LCID for conversion
3590 * pCyOut [O] Destination
3592 * RETURNS
3593 * Success: S_OK.
3594 * Failure: E_INVALIDARG, if the source value is invalid
3595 * DISP_E_OVERFLOW, if the value will not fit in the destination
3596 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3598 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3600 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0);
3603 /************************************************************************
3604 * VarCyFromBool (OLEAUT32.106)
3606 * Convert a VT_BOOL to a VT_CY.
3608 * PARAMS
3609 * boolIn [I] Source
3610 * pCyOut [O] Destination
3612 * RETURNS
3613 * Success: S_OK.
3614 * Failure: E_INVALIDARG, if the source value is invalid
3615 * DISP_E_OVERFLOW, if the value will not fit in the destination
3616 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3618 * NOTES
3619 * While the sign of the boolean is stored in the currency, the value is
3620 * converted to either 0 or 1.
3622 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3624 pCyOut->int64 = (LONG64)boolIn * CY_MULTIPLIER;
3625 return S_OK;
3628 /************************************************************************
3629 * VarCyFromI1 (OLEAUT32.225)
3631 * Convert a VT_I1 to a VT_CY.
3633 * PARAMS
3634 * cIn [I] Source
3635 * pCyOut [O] Destination
3637 * RETURNS
3638 * Success: S_OK.
3639 * Failure: E_INVALIDARG, if the source value is invalid
3640 * DISP_E_OVERFLOW, if the value will not fit in the destination
3641 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3643 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3645 pCyOut->int64 = (LONG64)cIn * CY_MULTIPLIER;
3646 return S_OK;
3649 /************************************************************************
3650 * VarCyFromUI2 (OLEAUT32.226)
3652 * Convert a VT_UI2 to a VT_CY.
3654 * PARAMS
3655 * usIn [I] Source
3656 * pCyOut [O] Destination
3658 * RETURNS
3659 * Success: S_OK.
3660 * Failure: E_INVALIDARG, if the source value is invalid
3661 * DISP_E_OVERFLOW, if the value will not fit in the destination
3662 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3664 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3666 pCyOut->int64 = (ULONG64)usIn * CY_MULTIPLIER;
3667 return S_OK;
3670 /************************************************************************
3671 * VarCyFromUI4 (OLEAUT32.227)
3673 * Convert a VT_UI4 to a VT_CY.
3675 * PARAMS
3676 * ulIn [I] Source
3677 * pCyOut [O] Destination
3679 * RETURNS
3680 * Success: S_OK.
3681 * Failure: E_INVALIDARG, if the source value is invalid
3682 * DISP_E_OVERFLOW, if the value will not fit in the destination
3683 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3685 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3687 pCyOut->int64 = (ULONG64)ulIn * CY_MULTIPLIER;
3688 return S_OK;
3691 /************************************************************************
3692 * VarCyFromDec (OLEAUT32.228)
3694 * Convert a VT_DECIMAL to a VT_CY.
3696 * PARAMS
3697 * pdecIn [I] Source
3698 * pCyOut [O] Destination
3700 * RETURNS
3701 * Success: S_OK.
3702 * Failure: E_INVALIDARG, if the source value is invalid
3703 * DISP_E_OVERFLOW, if the value will not fit in the destination
3704 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3706 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
3708 DECIMAL rounded;
3709 HRESULT hRet;
3711 hRet = VarDecRound(pdecIn, 4, &rounded);
3713 if (SUCCEEDED(hRet))
3715 double d;
3717 if (DEC_HI32(&rounded))
3718 return DISP_E_OVERFLOW;
3720 /* Note: Without the casts this promotes to int64 which loses precision */
3721 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3722 if (DEC_SIGN(&rounded))
3723 d = -d;
3724 return VarCyFromR8(d, pCyOut);
3726 return hRet;
3729 /************************************************************************
3730 * VarCyFromI8 (OLEAUT32.366)
3732 * Convert a VT_I8 to a VT_CY.
3734 * PARAMS
3735 * ullIn [I] Source
3736 * pCyOut [O] Destination
3738 * RETURNS
3739 * Success: S_OK.
3740 * Failure: E_INVALIDARG, if the source value is invalid
3741 * DISP_E_OVERFLOW, if the value will not fit in the destination
3742 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3744 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3746 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3747 pCyOut->int64 = llIn * CY_MULTIPLIER;
3748 return S_OK;
3751 /************************************************************************
3752 * VarCyFromUI8 (OLEAUT32.375)
3754 * Convert a VT_UI8 to a VT_CY.
3756 * PARAMS
3757 * ullIn [I] Source
3758 * pCyOut [O] Destination
3760 * RETURNS
3761 * Success: S_OK.
3762 * Failure: E_INVALIDARG, if the source value is invalid
3763 * DISP_E_OVERFLOW, if the value will not fit in the destination
3764 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3766 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3768 if (ullIn > (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3769 pCyOut->int64 = ullIn * CY_MULTIPLIER;
3770 return S_OK;
3773 /************************************************************************
3774 * VarCyAdd (OLEAUT32.299)
3776 * Add one CY to another.
3778 * PARAMS
3779 * cyLeft [I] Source
3780 * cyRight [I] Value to add
3781 * pCyOut [O] Destination
3783 * RETURNS
3784 * Success: S_OK.
3785 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3787 HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut)
3789 double l,r;
3790 _VarR8FromCy(cyLeft, &l);
3791 _VarR8FromCy(cyRight, &r);
3792 l = l + r;
3793 return VarCyFromR8(l, pCyOut);
3796 /************************************************************************
3797 * VarCyMul (OLEAUT32.303)
3799 * Multiply one CY by another.
3801 * PARAMS
3802 * cyLeft [I] Source
3803 * cyRight [I] Value to multiply by
3804 * pCyOut [O] Destination
3806 * RETURNS
3807 * Success: S_OK.
3808 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3810 HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut)
3812 double l,r;
3813 _VarR8FromCy(cyLeft, &l);
3814 _VarR8FromCy(cyRight, &r);
3815 l = l * r;
3816 return VarCyFromR8(l, pCyOut);
3819 /************************************************************************
3820 * VarCyMulI4 (OLEAUT32.304)
3822 * Multiply one CY by a VT_I4.
3824 * PARAMS
3825 * cyLeft [I] Source
3826 * lRight [I] Value to multiply by
3827 * pCyOut [O] Destination
3829 * RETURNS
3830 * Success: S_OK.
3831 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3833 HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut)
3835 double d;
3837 _VarR8FromCy(cyLeft, &d);
3838 d = d * lRight;
3839 return VarCyFromR8(d, pCyOut);
3842 /************************************************************************
3843 * VarCySub (OLEAUT32.305)
3845 * Subtract one CY from another.
3847 * PARAMS
3848 * cyLeft [I] Source
3849 * cyRight [I] Value to subtract
3850 * pCyOut [O] Destination
3852 * RETURNS
3853 * Success: S_OK.
3854 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3856 HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut)
3858 double l,r;
3859 _VarR8FromCy(cyLeft, &l);
3860 _VarR8FromCy(cyRight, &r);
3861 l = l - r;
3862 return VarCyFromR8(l, pCyOut);
3865 /************************************************************************
3866 * VarCyAbs (OLEAUT32.306)
3868 * Convert a VT_CY into its absolute value.
3870 * PARAMS
3871 * cyIn [I] Source
3872 * pCyOut [O] Destination
3874 * RETURNS
3875 * Success: S_OK. pCyOut contains the absolute value.
3876 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3878 HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut)
3880 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3881 return DISP_E_OVERFLOW;
3883 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3884 return S_OK;
3887 /************************************************************************
3888 * VarCyFix (OLEAUT32.307)
3890 * Return the integer part of a VT_CY.
3892 * PARAMS
3893 * cyIn [I] Source
3894 * pCyOut [O] Destination
3896 * RETURNS
3897 * Success: S_OK.
3898 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3900 * NOTES
3901 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3902 * negative numbers away from 0, while this function rounds them towards zero.
3904 HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut)
3906 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3907 pCyOut->int64 *= CY_MULTIPLIER;
3908 return S_OK;
3911 /************************************************************************
3912 * VarCyInt (OLEAUT32.308)
3914 * Return the integer part of a VT_CY.
3916 * PARAMS
3917 * cyIn [I] Source
3918 * pCyOut [O] Destination
3920 * RETURNS
3921 * Success: S_OK.
3922 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3924 * NOTES
3925 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3926 * negative numbers towards 0, while this function rounds them away from zero.
3928 HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut)
3930 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3931 pCyOut->int64 *= CY_MULTIPLIER;
3933 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3935 pCyOut->int64 -= CY_MULTIPLIER;
3937 return S_OK;
3940 /************************************************************************
3941 * VarCyNeg (OLEAUT32.309)
3943 * Change the sign of a VT_CY.
3945 * PARAMS
3946 * cyIn [I] Source
3947 * pCyOut [O] Destination
3949 * RETURNS
3950 * Success: S_OK.
3951 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3953 HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut)
3955 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3956 return DISP_E_OVERFLOW;
3958 pCyOut->int64 = -cyIn.int64;
3959 return S_OK;
3962 /************************************************************************
3963 * VarCyRound (OLEAUT32.310)
3965 * Change the precision of a VT_CY.
3967 * PARAMS
3968 * cyIn [I] Source
3969 * cDecimals [I] New number of decimals to keep
3970 * pCyOut [O] Destination
3972 * RETURNS
3973 * Success: S_OK.
3974 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3976 HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
3978 if (cDecimals < 0)
3979 return E_INVALIDARG;
3981 if (cDecimals > 3)
3983 /* Rounding to more precision than we have */
3984 *pCyOut = cyIn;
3985 return S_OK;
3987 else
3989 double d, div = CY_Divisors[cDecimals];
3991 _VarR8FromCy(cyIn, &d);
3992 d = d * div;
3993 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3994 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3995 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3996 return S_OK;
4000 /************************************************************************
4001 * VarCyCmp (OLEAUT32.311)
4003 * Compare two VT_CY values.
4005 * PARAMS
4006 * cyLeft [I] Source
4007 * cyRight [I] Value to compare
4009 * RETURNS
4010 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4011 * compare is less, equal or greater than source respectively.
4012 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4014 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
4016 HRESULT hRet;
4017 CY result;
4019 /* Subtract right from left, and compare the result to 0 */
4020 hRet = VarCySub(cyLeft, cyRight, &result);
4022 if (SUCCEEDED(hRet))
4024 if (result.int64 < 0)
4025 hRet = (HRESULT)VARCMP_LT;
4026 else if (result.int64 > 0)
4027 hRet = (HRESULT)VARCMP_GT;
4028 else
4029 hRet = (HRESULT)VARCMP_EQ;
4031 return hRet;
4034 /************************************************************************
4035 * VarCyCmpR8 (OLEAUT32.312)
4037 * Compare a VT_CY to a double
4039 * PARAMS
4040 * cyLeft [I] Currency Source
4041 * dblRight [I] double to compare to cyLeft
4043 * RETURNS
4044 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4045 * less than, equal to or greater than cyLeft respectively.
4046 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4048 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight)
4050 HRESULT hRet;
4051 CY cyRight;
4053 hRet = VarCyFromR8(dblRight, &cyRight);
4055 if (SUCCEEDED(hRet))
4056 hRet = VarCyCmp(cyLeft, cyRight);
4058 return hRet;
4061 /************************************************************************
4062 * VarCyMulI8 (OLEAUT32.329)
4064 * Multiply a VT_CY by a VT_I8.
4066 * PARAMS
4067 * cyLeft [I] Source
4068 * llRight [I] Value to multiply by
4069 * pCyOut [O] Destination
4071 * RETURNS
4072 * Success: S_OK.
4073 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4075 HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
4077 double d;
4079 _VarR8FromCy(cyLeft, &d);
4080 d = d * (double)llRight;
4081 return VarCyFromR8(d, pCyOut);
4084 /* DECIMAL
4087 /************************************************************************
4088 * VarDecFromUI1 (OLEAUT32.190)
4090 * Convert a VT_UI1 to a DECIMAL.
4092 * PARAMS
4093 * bIn [I] Source
4094 * pDecOut [O] Destination
4096 * RETURNS
4097 * S_OK.
4099 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4101 return VarDecFromUI4(bIn, pDecOut);
4104 /************************************************************************
4105 * VarDecFromI2 (OLEAUT32.191)
4107 * Convert a VT_I2 to a DECIMAL.
4109 * PARAMS
4110 * sIn [I] Source
4111 * pDecOut [O] Destination
4113 * RETURNS
4114 * S_OK.
4116 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4118 return VarDecFromI4(sIn, pDecOut);
4121 /************************************************************************
4122 * VarDecFromI4 (OLEAUT32.192)
4124 * Convert a VT_I4 to a DECIMAL.
4126 * PARAMS
4127 * sIn [I] Source
4128 * pDecOut [O] Destination
4130 * RETURNS
4131 * S_OK.
4133 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4135 DEC_HI32(pDecOut) = 0;
4136 DEC_MID32(pDecOut) = 0;
4138 if (lIn < 0)
4140 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4141 DEC_LO32(pDecOut) = -lIn;
4143 else
4145 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4146 DEC_LO32(pDecOut) = lIn;
4148 return S_OK;
4151 #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT))
4153 /* internal representation of the value stored in a DECIMAL. The bytes are
4154 stored from LSB at index 0 to MSB at index 11
4156 typedef struct DECIMAL_internal
4158 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4159 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4160 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4161 } VARIANT_DI;
4163 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest);
4164 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest);
4165 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to);
4166 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to);
4167 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor);
4168 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n);
4170 /************************************************************************
4171 * VarDecFromR4 (OLEAUT32.193)
4173 * Convert a VT_R4 to a DECIMAL.
4175 * PARAMS
4176 * fltIn [I] Source
4177 * pDecOut [O] Destination
4179 * RETURNS
4180 * S_OK.
4182 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4184 VARIANT_DI di;
4185 HRESULT hres;
4187 hres = VARIANT_DI_FromR4(fltIn, &di);
4188 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4189 return hres;
4192 /************************************************************************
4193 * VarDecFromR8 (OLEAUT32.194)
4195 * Convert a VT_R8 to a DECIMAL.
4197 * PARAMS
4198 * dblIn [I] Source
4199 * pDecOut [O] Destination
4201 * RETURNS
4202 * S_OK.
4204 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4206 VARIANT_DI di;
4207 HRESULT hres;
4209 hres = VARIANT_DI_FromR8(dblIn, &di);
4210 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4211 return hres;
4214 /************************************************************************
4215 * VarDecFromDate (OLEAUT32.195)
4217 * Convert a VT_DATE to a DECIMAL.
4219 * PARAMS
4220 * dateIn [I] Source
4221 * pDecOut [O] Destination
4223 * RETURNS
4224 * S_OK.
4226 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4228 return VarDecFromR8(dateIn, pDecOut);
4231 /************************************************************************
4232 * VarDecFromCy (OLEAUT32.196)
4234 * Convert a VT_CY to a DECIMAL.
4236 * PARAMS
4237 * cyIn [I] Source
4238 * pDecOut [O] Destination
4240 * RETURNS
4241 * S_OK.
4243 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4245 DEC_HI32(pDecOut) = 0;
4247 /* Note: This assumes 2s complement integer representation */
4248 if (cyIn.s.Hi & 0x80000000)
4250 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4251 DEC_LO64(pDecOut) = -cyIn.int64;
4253 else
4255 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4256 DEC_MID32(pDecOut) = cyIn.s.Hi;
4257 DEC_LO32(pDecOut) = cyIn.s.Lo;
4259 return S_OK;
4262 /************************************************************************
4263 * VarDecFromStr (OLEAUT32.197)
4265 * Convert a VT_BSTR to a DECIMAL.
4267 * PARAMS
4268 * strIn [I] Source
4269 * lcid [I] LCID for the conversion
4270 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4271 * pDecOut [O] Destination
4273 * RETURNS
4274 * Success: S_OK.
4275 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4277 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4279 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4282 /************************************************************************
4283 * VarDecFromDisp (OLEAUT32.198)
4285 * Convert a VT_DISPATCH to a DECIMAL.
4287 * PARAMS
4288 * pdispIn [I] Source
4289 * lcid [I] LCID for conversion
4290 * pDecOut [O] Destination
4292 * RETURNS
4293 * Success: S_OK.
4294 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4296 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4298 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0);
4301 /************************************************************************
4302 * VarDecFromBool (OLEAUT32.199)
4304 * Convert a VT_BOOL to a DECIMAL.
4306 * PARAMS
4307 * bIn [I] Source
4308 * pDecOut [O] Destination
4310 * RETURNS
4311 * S_OK.
4313 * NOTES
4314 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4316 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4318 DEC_HI32(pDecOut) = 0;
4319 DEC_MID32(pDecOut) = 0;
4320 if (bIn)
4322 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4323 DEC_LO32(pDecOut) = 1;
4325 else
4327 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4328 DEC_LO32(pDecOut) = 0;
4330 return S_OK;
4333 /************************************************************************
4334 * VarDecFromI1 (OLEAUT32.241)
4336 * Convert a VT_I1 to a DECIMAL.
4338 * PARAMS
4339 * cIn [I] Source
4340 * pDecOut [O] Destination
4342 * RETURNS
4343 * S_OK.
4345 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4347 return VarDecFromI4(cIn, pDecOut);
4350 /************************************************************************
4351 * VarDecFromUI2 (OLEAUT32.242)
4353 * Convert a VT_UI2 to a DECIMAL.
4355 * PARAMS
4356 * usIn [I] Source
4357 * pDecOut [O] Destination
4359 * RETURNS
4360 * S_OK.
4362 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4364 return VarDecFromUI4(usIn, pDecOut);
4367 /************************************************************************
4368 * VarDecFromUI4 (OLEAUT32.243)
4370 * Convert a VT_UI4 to a DECIMAL.
4372 * PARAMS
4373 * ulIn [I] Source
4374 * pDecOut [O] Destination
4376 * RETURNS
4377 * S_OK.
4379 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4381 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4382 DEC_HI32(pDecOut) = 0;
4383 DEC_MID32(pDecOut) = 0;
4384 DEC_LO32(pDecOut) = ulIn;
4385 return S_OK;
4388 /************************************************************************
4389 * VarDecFromI8 (OLEAUT32.374)
4391 * Convert a VT_I8 to a DECIMAL.
4393 * PARAMS
4394 * llIn [I] Source
4395 * pDecOut [O] Destination
4397 * RETURNS
4398 * S_OK.
4400 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4402 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4404 DEC_HI32(pDecOut) = 0;
4406 /* Note: This assumes 2s complement integer representation */
4407 if (pLi->u.HighPart & 0x80000000)
4409 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4410 DEC_LO64(pDecOut) = -pLi->QuadPart;
4412 else
4414 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4415 DEC_MID32(pDecOut) = pLi->u.HighPart;
4416 DEC_LO32(pDecOut) = pLi->u.LowPart;
4418 return S_OK;
4421 /************************************************************************
4422 * VarDecFromUI8 (OLEAUT32.375)
4424 * Convert a VT_UI8 to a DECIMAL.
4426 * PARAMS
4427 * ullIn [I] Source
4428 * pDecOut [O] Destination
4430 * RETURNS
4431 * S_OK.
4433 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4435 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4436 DEC_HI32(pDecOut) = 0;
4437 DEC_LO64(pDecOut) = ullIn;
4438 return S_OK;
4441 /* Make two DECIMALS the same scale; used by math functions below */
4442 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4443 const DECIMAL** ppDecRight,
4444 DECIMAL pDecOut[2])
4446 static DECIMAL scaleFactor;
4447 unsigned char remainder;
4448 DECIMAL decTemp;
4449 VARIANT_DI di;
4450 int scaleAmount, i;
4452 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4453 return E_INVALIDARG;
4455 DEC_LO32(&scaleFactor) = 10;
4457 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4459 if (!scaleAmount)
4460 return S_OK; /* Same scale */
4462 if (scaleAmount > 0)
4464 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4465 *ppDecRight = &pDecOut[0];
4467 else
4469 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4470 *ppDecLeft = &pDecOut[0];
4471 i = -scaleAmount;
4474 /* Multiply up the value to be scaled by the correct amount (if possible) */
4475 while (i > 0 && SUCCEEDED(VarDecMul(&decTemp, &scaleFactor, &pDecOut[0])))
4477 decTemp = pDecOut[0];
4478 i--;
4481 if (!i)
4483 DEC_SCALE(&pDecOut[0]) += (scaleAmount > 0) ? scaleAmount : (-scaleAmount);
4484 return S_OK; /* Same scale */
4487 /* Scaling further not possible, reduce accuracy of other argument */
4488 pDecOut[0] = decTemp;
4489 if (scaleAmount > 0)
4491 DEC_SCALE(&pDecOut[0]) += scaleAmount - i;
4492 VARIANT_DIFromDec(*ppDecLeft, &di);
4493 *ppDecLeft = &pDecOut[1];
4495 else
4497 DEC_SCALE(&pDecOut[0]) += (-scaleAmount) - i;
4498 VARIANT_DIFromDec(*ppDecRight, &di);
4499 *ppDecRight = &pDecOut[1];
4502 di.scale -= i;
4503 remainder = 0;
4504 while (i-- > 0 && !VARIANT_int_iszero(di.bitsnum, sizeof(di.bitsnum)/sizeof(DWORD)))
4506 remainder = VARIANT_int_divbychar(di.bitsnum, sizeof(di.bitsnum)/sizeof(DWORD), 10);
4507 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4510 /* round up the result - native oleaut32 does this */
4511 if (remainder >= 5) {
4512 for (remainder = 1, i = 0; i < sizeof(di.bitsnum)/sizeof(DWORD) && remainder; i++) {
4513 ULONGLONG digit = di.bitsnum[i] + 1;
4514 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4515 di.bitsnum[i] = digit & 0xFFFFFFFF;
4519 VARIANT_DecFromDI(&di, &pDecOut[1]);
4520 return S_OK;
4523 /* Add two unsigned 32 bit values with overflow */
4524 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4526 ULARGE_INTEGER ul64;
4528 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4529 *pulHigh = ul64.u.HighPart;
4530 return ul64.u.LowPart;
4533 /* Subtract two unsigned 32 bit values with underflow */
4534 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4536 BOOL invert = FALSE;
4537 ULARGE_INTEGER ul64;
4539 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4540 if (ulLeft < ulRight)
4541 invert = TRUE;
4543 if (ul64.QuadPart > (ULONG64)*pulHigh)
4544 ul64.QuadPart -= (ULONG64)*pulHigh;
4545 else
4547 ul64.QuadPart -= (ULONG64)*pulHigh;
4548 invert = TRUE;
4550 if (invert)
4551 ul64.u.HighPart = -ul64.u.HighPart ;
4553 *pulHigh = ul64.u.HighPart;
4554 return ul64.u.LowPart;
4557 /* Multiply two unsigned 32 bit values with overflow */
4558 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4560 ULARGE_INTEGER ul64;
4562 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4563 *pulHigh = ul64.u.HighPart;
4564 return ul64.u.LowPart;
4567 /* Compare two decimals that have the same scale */
4568 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4570 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4571 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4572 return -1;
4573 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4574 return 0;
4575 return 1;
4578 /************************************************************************
4579 * VarDecAdd (OLEAUT32.177)
4581 * Add one DECIMAL to another.
4583 * PARAMS
4584 * pDecLeft [I] Source
4585 * pDecRight [I] Value to add
4586 * pDecOut [O] Destination
4588 * RETURNS
4589 * Success: S_OK.
4590 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4592 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4594 HRESULT hRet;
4595 DECIMAL scaled[2];
4597 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, scaled);
4599 if (SUCCEEDED(hRet))
4601 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4602 ULONG overflow = 0;
4603 BYTE sign = DECIMAL_POS;
4604 int cmp;
4606 /* Correct for the sign of the result */
4607 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4609 /* -x + -y : Negative */
4610 sign = DECIMAL_NEG;
4611 goto VarDecAdd_AsPositive;
4613 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4615 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4617 /* -x + y : Negative if x > y */
4618 if (cmp > 0)
4620 sign = DECIMAL_NEG;
4621 VarDecAdd_AsNegative:
4622 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4623 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4624 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4626 else
4628 VarDecAdd_AsInvertedNegative:
4629 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4630 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4631 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4634 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4636 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4638 /* x + -y : Negative if x <= y */
4639 if (cmp <= 0)
4641 sign = DECIMAL_NEG;
4642 goto VarDecAdd_AsInvertedNegative;
4644 goto VarDecAdd_AsNegative;
4646 else
4648 /* x + y : Positive */
4649 VarDecAdd_AsPositive:
4650 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4651 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4652 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4655 if (overflow)
4656 return DISP_E_OVERFLOW; /* overflowed */
4658 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4659 DEC_SIGN(pDecOut) = sign;
4661 return hRet;
4664 /* translate from external DECIMAL format into an internal representation */
4665 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4667 to->scale = DEC_SCALE(from);
4668 to->sign = DEC_SIGN(from) ? 1 : 0;
4670 to->bitsnum[0] = DEC_LO32(from);
4671 to->bitsnum[1] = DEC_MID32(from);
4672 to->bitsnum[2] = DEC_HI32(from);
4675 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to)
4677 if (from->sign) {
4678 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4679 } else {
4680 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4683 DEC_LO32(to) = from->bitsnum[0];
4684 DEC_MID32(to) = from->bitsnum[1];
4685 DEC_HI32(to) = from->bitsnum[2];
4688 /* clear an internal representation of a DECIMAL */
4689 static void VARIANT_DI_clear(VARIANT_DI * i)
4691 memset(i, 0, sizeof(VARIANT_DI));
4694 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4695 size is supported. The value in p is replaced by the quotient of the division, and
4696 the remainder is returned as a result. This routine is most often used with a divisor
4697 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4699 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4701 if (divisor == 0) {
4702 /* division by 0 */
4703 return 0xFF;
4704 } else if (divisor == 1) {
4705 /* dividend remains unchanged */
4706 return 0;
4707 } else {
4708 unsigned char remainder = 0;
4709 ULONGLONG iTempDividend;
4710 signed int i;
4712 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4713 for (; i >= 0; i--) {
4714 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4715 remainder = iTempDividend % divisor;
4716 p[i] = iTempDividend / divisor;
4719 return remainder;
4723 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4724 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n)
4726 for (; n > 0; n--) if (*p++ != 0) return FALSE;
4727 return TRUE;
4730 /* multiply two DECIMALS, without changing either one, and place result in third
4731 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4732 digits when scale > 0 in order to fit an overflowing result. Final overflow
4733 flag is returned.
4735 static int VARIANT_DI_mul(const VARIANT_DI * a, const VARIANT_DI * b, VARIANT_DI * result)
4737 BOOL r_overflow = FALSE;
4738 DWORD running[6];
4739 signed int mulstart;
4741 VARIANT_DI_clear(result);
4742 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4744 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4745 of the result is formed by adding the scales of the operands.
4747 result->scale = a->scale + b->scale;
4748 memset(running, 0, sizeof(running));
4750 /* count number of leading zero-bytes in operand A */
4751 for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4752 if (mulstart < 0) {
4753 /* result is 0, because operand A is 0 */
4754 result->scale = 0;
4755 result->sign = 0;
4756 } else {
4757 unsigned char remainder = 0;
4758 int iA;
4760 /* perform actual multiplication */
4761 for (iA = 0; iA <= mulstart; iA++) {
4762 ULONG iOverflowMul;
4763 int iB;
4765 for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
4766 ULONG iRV;
4767 int iR;
4769 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4770 iR = iA + iB;
4771 do {
4772 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4773 iR++;
4774 } while (iRV);
4778 /* Too bad - native oleaut does not do this, so we should not either */
4779 #if 0
4780 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4781 This operation should not lose significant digits, and gives an
4782 opportunity to reduce the possibility of overflows in future
4783 operations issued by the application.
4785 while (result->scale > 0) {
4786 memcpy(quotient, running, sizeof(quotient));
4787 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4788 if (remainder > 0) break;
4789 memcpy(running, quotient, sizeof(quotient));
4790 result->scale--;
4792 #endif
4793 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4794 This operation *will* lose significant digits of the result because
4795 all the factors of 10 were consumed by the previous operation.
4797 while (result->scale > 0 && !VARIANT_int_iszero(
4798 running + sizeof(result->bitsnum) / sizeof(DWORD),
4799 (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
4801 remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
4802 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4803 result->scale--;
4806 /* round up the result - native oleaut32 does this */
4807 if (remainder >= 5) {
4808 unsigned int i;
4809 for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
4810 ULONGLONG digit = running[i] + 1;
4811 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4812 running[i] = digit & 0xFFFFFFFF;
4816 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4817 and copy result bits into result structure
4819 r_overflow = !VARIANT_int_iszero(
4820 running + sizeof(result->bitsnum)/sizeof(DWORD),
4821 (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
4822 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4824 return r_overflow;
4827 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4828 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4829 success, FALSE if insufficient space in output buffer.
4831 static BOOL VARIANT_DI_tostringW(const VARIANT_DI * a, WCHAR * s, unsigned int n)
4833 BOOL overflow = FALSE;
4834 DWORD quotient[3];
4835 unsigned char remainder;
4836 unsigned int i;
4838 /* place negative sign */
4839 if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
4840 if (n > 0) {
4841 *s++ = '-';
4842 n--;
4844 else overflow = TRUE;
4847 /* prepare initial 0 */
4848 if (!overflow) {
4849 if (n >= 2) {
4850 s[0] = '0';
4851 s[1] = '\0';
4852 } else overflow = TRUE;
4855 i = 0;
4856 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4857 while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
4858 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4859 if (i + 2 > n) {
4860 overflow = TRUE;
4861 } else {
4862 s[i++] = '0' + remainder;
4863 s[i] = '\0';
4867 if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
4869 /* reverse order of digits */
4870 WCHAR * x = s; WCHAR * y = s + i - 1;
4871 while (x < y) {
4872 *x ^= *y;
4873 *y ^= *x;
4874 *x++ ^= *y--;
4877 /* check for decimal point. "i" now has string length */
4878 if (i <= a->scale) {
4879 unsigned int numzeroes = a->scale + 1 - i;
4880 if (i + 1 + numzeroes >= n) {
4881 overflow = TRUE;
4882 } else {
4883 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4884 i += numzeroes;
4885 while (numzeroes > 0) {
4886 s[--numzeroes] = '0';
4891 /* place decimal point */
4892 if (a->scale > 0) {
4893 unsigned int periodpos = i - a->scale;
4894 if (i + 2 >= n) {
4895 overflow = TRUE;
4896 } else {
4897 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4898 s[periodpos] = '.'; i++;
4900 /* remove extra zeros at the end, if any */
4901 while (s[i - 1] == '0') s[--i] = '\0';
4902 if (s[i - 1] == '.') s[--i] = '\0';
4907 return !overflow;
4910 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4911 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4913 DWORD shifted;
4914 unsigned int i;
4916 /* shift whole DWORDs to the left */
4917 while (shift >= 32)
4919 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4920 *p = 0; shift -= 32;
4923 /* shift remainder (1..31 bits) */
4924 shifted = 0;
4925 if (shift > 0) for (i = 0; i < n; i++)
4927 DWORD b;
4928 b = p[i] >> (32 - shift);
4929 p[i] = (p[i] << shift) | shifted;
4930 shifted = b;
4934 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4935 Value at v is incremented by the value at p. Any size is supported, provided
4936 that v is not shorter than p. Any unapplied carry is returned as a result.
4938 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, const DWORD * p,
4939 unsigned int np)
4941 unsigned char carry = 0;
4943 if (nv >= np) {
4944 ULONGLONG sum;
4945 unsigned int i;
4947 for (i = 0; i < np; i++) {
4948 sum = (ULONGLONG)v[i]
4949 + (ULONGLONG)p[i]
4950 + (ULONGLONG)carry;
4951 v[i] = sum & 0xffffffff;
4952 carry = sum >> 32;
4954 for (; i < nv && carry; i++) {
4955 sum = (ULONGLONG)v[i]
4956 + (ULONGLONG)carry;
4957 v[i] = sum & 0xffffffff;
4958 carry = sum >> 32;
4961 return carry;
4964 /* perform integral division with operand p as dividend. Parameter n indicates
4965 number of available DWORDs in divisor p, but available space in p must be
4966 actually at least 2 * n DWORDs, because the remainder of the integral
4967 division is built in the next n DWORDs past the start of the quotient. This
4968 routine replaces the dividend in p with the quotient, and appends n
4969 additional DWORDs for the remainder.
4971 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4972 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4973 source code to the VLI (Very Large Integer) division operator. This algorithm
4974 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4975 variably-scaled integers such as the MS DECIMAL representation.
4977 static void VARIANT_int_div(DWORD * p, unsigned int n, const DWORD * divisor,
4978 unsigned int dn)
4980 unsigned int i;
4981 DWORD tempsub[8];
4982 DWORD * negdivisor = tempsub + n;
4984 /* build 2s-complement of divisor */
4985 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
4986 p[n] = 1;
4987 VARIANT_int_add(negdivisor, n, p + n, 1);
4988 memset(p + n, 0, n * sizeof(DWORD));
4990 /* skip all leading zero DWORDs in quotient */
4991 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
4992 /* i is now number of DWORDs left to process */
4993 for (i <<= 5; i < (n << 5); i++) {
4994 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
4996 /* trial subtraction */
4997 memcpy(tempsub, p + n, n * sizeof(DWORD));
4998 VARIANT_int_add(tempsub, n, negdivisor, n);
5000 /* check whether result of subtraction was negative */
5001 if ((tempsub[n - 1] & 0x80000000) == 0) {
5002 memcpy(p + n, tempsub, n * sizeof(DWORD));
5003 p[0] |= 1;
5008 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
5009 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
5011 unsigned int i;
5012 ULONG iOverflowMul;
5014 for (iOverflowMul = 0, i = 0; i < n; i++)
5015 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
5016 return (unsigned char)iOverflowMul;
5019 /* increment value in A by the value indicated in B, with scale adjusting.
5020 Modifies parameters by adjusting scales. Returns 0 if addition was
5021 successful, nonzero if a parameter underflowed before it could be
5022 successfully used in the addition.
5024 static int VARIANT_int_addlossy(
5025 DWORD * a, int * ascale, unsigned int an,
5026 DWORD * b, int * bscale, unsigned int bn)
5028 int underflow = 0;
5030 if (VARIANT_int_iszero(a, an)) {
5031 /* if A is zero, copy B into A, after removing digits */
5032 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
5033 VARIANT_int_divbychar(b, bn, 10);
5034 (*bscale)--;
5036 memcpy(a, b, an * sizeof(DWORD));
5037 *ascale = *bscale;
5038 } else if (!VARIANT_int_iszero(b, bn)) {
5039 unsigned int tn = an + 1;
5040 DWORD t[5];
5042 if (bn + 1 > tn) tn = bn + 1;
5043 if (*ascale != *bscale) {
5044 /* first (optimistic) try - try to scale down the one with the bigger
5045 scale, while this number is divisible by 10 */
5046 DWORD * digitchosen;
5047 unsigned int nchosen;
5048 int * scalechosen;
5049 int targetscale;
5051 if (*ascale < *bscale) {
5052 targetscale = *ascale;
5053 scalechosen = bscale;
5054 digitchosen = b;
5055 nchosen = bn;
5056 } else {
5057 targetscale = *bscale;
5058 scalechosen = ascale;
5059 digitchosen = a;
5060 nchosen = an;
5062 memset(t, 0, tn * sizeof(DWORD));
5063 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5065 /* divide by 10 until target scale is reached */
5066 while (*scalechosen > targetscale) {
5067 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5068 if (!remainder) {
5069 (*scalechosen)--;
5070 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5071 } else break;
5075 if (*ascale != *bscale) {
5076 DWORD * digitchosen;
5077 unsigned int nchosen;
5078 int * scalechosen;
5079 int targetscale;
5081 /* try to scale up the one with the smaller scale */
5082 if (*ascale > *bscale) {
5083 targetscale = *ascale;
5084 scalechosen = bscale;
5085 digitchosen = b;
5086 nchosen = bn;
5087 } else {
5088 targetscale = *bscale;
5089 scalechosen = ascale;
5090 digitchosen = a;
5091 nchosen = an;
5093 memset(t, 0, tn * sizeof(DWORD));
5094 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5096 /* multiply by 10 until target scale is reached, or
5097 significant bytes overflow the number
5099 while (*scalechosen < targetscale && t[nchosen] == 0) {
5100 VARIANT_int_mulbychar(t, tn, 10);
5101 if (t[nchosen] == 0) {
5102 /* still does not overflow */
5103 (*scalechosen)++;
5104 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5109 if (*ascale != *bscale) {
5110 /* still different? try to scale down the one with the bigger scale
5111 (this *will* lose significant digits) */
5112 DWORD * digitchosen;
5113 unsigned int nchosen;
5114 int * scalechosen;
5115 int targetscale;
5117 if (*ascale < *bscale) {
5118 targetscale = *ascale;
5119 scalechosen = bscale;
5120 digitchosen = b;
5121 nchosen = bn;
5122 } else {
5123 targetscale = *bscale;
5124 scalechosen = ascale;
5125 digitchosen = a;
5126 nchosen = an;
5128 memset(t, 0, tn * sizeof(DWORD));
5129 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5131 /* divide by 10 until target scale is reached */
5132 while (*scalechosen > targetscale) {
5133 VARIANT_int_divbychar(t, tn, 10);
5134 (*scalechosen)--;
5135 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5139 /* check whether any of the operands still has significant digits
5140 (underflow case 1)
5142 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5143 underflow = 1;
5144 } else {
5145 /* at this step, both numbers have the same scale and can be added
5146 as integers. However, the result might not fit in A, so further
5147 scaling down might be necessary.
5149 while (!underflow) {
5150 memset(t, 0, tn * sizeof(DWORD));
5151 memcpy(t, a, an * sizeof(DWORD));
5153 VARIANT_int_add(t, tn, b, bn);
5154 if (VARIANT_int_iszero(t + an, tn - an)) {
5155 /* addition was successful */
5156 memcpy(a, t, an * sizeof(DWORD));
5157 break;
5158 } else {
5159 /* addition overflowed - remove significant digits
5160 from both operands and try again */
5161 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5162 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5163 /* check whether any operand keeps significant digits after
5164 scaledown (underflow case 2)
5166 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5171 return underflow;
5174 /* perform complete DECIMAL division in the internal representation. Returns
5175 0 if the division was completed (even if quotient is set to 0), or nonzero
5176 in case of quotient overflow.
5178 static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * divisor,
5179 VARIANT_DI * quotient, BOOL round_remainder)
5181 HRESULT r_overflow = S_OK;
5183 if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
5184 /* division by 0 */
5185 r_overflow = DISP_E_DIVBYZERO;
5186 } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
5187 VARIANT_DI_clear(quotient);
5188 } else {
5189 int quotientscale, remainderscale, tempquotientscale;
5190 DWORD remainderplusquotient[8];
5191 int underflow;
5193 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5194 tempquotientscale = quotientscale;
5195 VARIANT_DI_clear(quotient);
5196 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5198 /* The following strategy is used for division
5199 1) if there was a nonzero remainder from previous iteration, use it as
5200 dividend for this iteration, else (for first iteration) use intended
5201 dividend
5202 2) perform integer division in temporary buffer, develop quotient in
5203 low-order part, remainder in high-order part
5204 3) add quotient from step 2 to final result, with possible loss of
5205 significant digits
5206 4) multiply integer part of remainder by 10, while incrementing the
5207 scale of the remainder. This operation preserves the intended value
5208 of the remainder.
5209 5) loop to step 1 until one of the following is true:
5210 a) remainder is zero (exact division achieved)
5211 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5213 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5214 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5215 do {
5216 VARIANT_int_div(
5217 remainderplusquotient, 4,
5218 divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
5219 underflow = VARIANT_int_addlossy(
5220 quotient->bitsnum, &quotientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
5221 remainderplusquotient, &tempquotientscale, 4);
5222 if (round_remainder) {
5223 if(remainderplusquotient[4] >= 5){
5224 unsigned int i;
5225 unsigned char remainder = 1;
5226 for (i = 0; i < sizeof(quotient->bitsnum) / sizeof(DWORD) && remainder; i++) {
5227 ULONGLONG digit = quotient->bitsnum[i] + 1;
5228 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5229 quotient->bitsnum[i] = digit & 0xFFFFFFFF;
5232 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5233 } else {
5234 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5235 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5237 tempquotientscale = ++remainderscale;
5238 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5240 /* quotient scale might now be negative (extremely big number). If, so, try
5241 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5242 until scale is 0. If this cannot be done, it is a real overflow.
5244 while (r_overflow == S_OK && quotientscale < 0) {
5245 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5246 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5247 VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
5248 if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
5249 (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
5250 quotientscale++;
5251 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5252 } else r_overflow = DISP_E_OVERFLOW;
5254 if (r_overflow == S_OK) {
5255 if (quotientscale <= 255) quotient->scale = quotientscale;
5256 else VARIANT_DI_clear(quotient);
5259 return r_overflow;
5262 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5263 with an undefined scale, which will be assigned to (if possible). It also
5264 receives an exponent of 2. This procedure will then manipulate the mantissa
5265 and calculate a corresponding scale, so that the exponent2 value is assimilated
5266 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5267 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5268 a DECIMAL. */
5269 static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, BOOL isDouble)
5271 HRESULT hres = S_OK;
5272 int exponent5, exponent10;
5274 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5275 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5276 exponent10 might be used to set the VARIANT_DI scale directly. However,
5277 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5278 exponent5 = -exponent2;
5279 exponent10 = exponent2;
5281 /* Handle exponent5 > 0 */
5282 while (exponent5 > 0) {
5283 char bPrevCarryBit;
5284 char bCurrCarryBit;
5286 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5287 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5288 somehow the mantissa should be divided by 2. */
5289 if ((val->bitsnum[0] & 1) == 0) {
5290 /* The mantissa is divisible by 2. Therefore the division can be done
5291 without losing significant digits. */
5292 exponent10++; exponent5--;
5294 /* Shift right */
5295 bPrevCarryBit = val->bitsnum[2] & 1;
5296 val->bitsnum[2] >>= 1;
5297 bCurrCarryBit = val->bitsnum[1] & 1;
5298 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5299 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5300 } else {
5301 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5302 be multiplied by 5, unless the multiplication overflows. */
5303 DWORD temp_bitsnum[3];
5305 exponent5--;
5307 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5308 if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) {
5309 /* Multiplication succeeded without overflow, so copy result back
5310 into VARIANT_DI */
5311 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5313 /* Mask out 3 extraneous bits introduced by the multiply */
5314 } else {
5315 /* Multiplication by 5 overflows. The mantissa should be divided
5316 by 2, and therefore will lose significant digits. */
5317 exponent10++;
5319 /* Shift right */
5320 bPrevCarryBit = val->bitsnum[2] & 1;
5321 val->bitsnum[2] >>= 1;
5322 bCurrCarryBit = val->bitsnum[1] & 1;
5323 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5324 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5329 /* Handle exponent5 < 0 */
5330 while (exponent5 < 0) {
5331 /* In order to divide the value represented by the VARIANT_DI by 5, it
5332 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5333 and the mantissa should be multiplied by 2 */
5334 if ((val->bitsnum[2] & 0x80000000) == 0) {
5335 /* The mantissa can withstand a shift-left without overflowing */
5336 exponent10--; exponent5++;
5337 VARIANT_int_shiftleft(val->bitsnum, 3, 1);
5338 } else {
5339 /* The mantissa would overflow if shifted. Therefore it should be
5340 directly divided by 5. This will lose significant digits, unless
5341 by chance the mantissa happens to be divisible by 5 */
5342 exponent5++;
5343 VARIANT_int_divbychar(val->bitsnum, 3, 5);
5347 /* At this point, the mantissa has assimilated the exponent5, but the
5348 exponent10 might not be suitable for assignment. The exponent10 must be
5349 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5350 down appropriately. */
5351 while (hres == S_OK && exponent10 > 0) {
5352 /* In order to bring exponent10 down to 0, the mantissa should be
5353 multiplied by 10 to compensate. If the exponent10 is too big, this
5354 will cause the mantissa to overflow. */
5355 if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) {
5356 exponent10--;
5357 } else {
5358 hres = DISP_E_OVERFLOW;
5361 while (exponent10 < -DEC_MAX_SCALE) {
5362 int rem10;
5363 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5364 be divided by 10 to compensate. If the exponent10 is too small, this
5365 will cause the mantissa to underflow and become 0 */
5366 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5367 exponent10++;
5368 if (VARIANT_int_iszero(val->bitsnum, 3)) {
5369 /* Underflow, unable to keep dividing */
5370 exponent10 = 0;
5371 } else if (rem10 >= 5) {
5372 DWORD x = 1;
5373 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5376 /* This step is required in order to remove excess bits of precision from the
5377 end of the bit representation, down to the precision guaranteed by the
5378 floating point number. */
5379 if (isDouble) {
5380 while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[2] == 0 && (val->bitsnum[1] & 0xFFE00000) != 0))) {
5381 int rem10;
5383 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5384 exponent10++;
5385 if (rem10 >= 5) {
5386 DWORD x = 1;
5387 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5390 } else {
5391 while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 ||
5392 (val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) {
5393 int rem10;
5395 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5396 exponent10++;
5397 if (rem10 >= 5) {
5398 DWORD x = 1;
5399 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5403 /* Remove multiples of 10 from the representation */
5404 while (exponent10 < 0) {
5405 DWORD temp_bitsnum[3];
5407 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5408 if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) {
5409 exponent10++;
5410 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5411 } else break;
5414 /* Scale assignment */
5415 if (hres == S_OK) val->scale = -exponent10;
5417 return hres;
5420 typedef union
5422 struct
5424 unsigned int m : 23;
5425 unsigned int exp_bias : 8;
5426 unsigned int sign : 1;
5427 } i;
5428 float f;
5429 } R4_FIELDS;
5431 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5432 intermediate string step. */
5433 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest)
5435 HRESULT hres = S_OK;
5436 R4_FIELDS fx;
5438 fx.f = source;
5440 /* Detect special cases */
5441 if (fx.i.m == 0 && fx.i.exp_bias == 0) {
5442 /* Floating-point zero */
5443 VARIANT_DI_clear(dest);
5444 } else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) {
5445 /* Floating-point infinity */
5446 hres = DISP_E_OVERFLOW;
5447 } else if (fx.i.exp_bias == 0xFF) {
5448 /* Floating-point NaN */
5449 hres = DISP_E_BADVARTYPE;
5450 } else {
5451 int exponent2;
5452 VARIANT_DI_clear(dest);
5454 exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */
5455 dest->sign = fx.i.sign; /* Sign is simply copied */
5457 /* Copy significant bits to VARIANT_DI mantissa */
5458 dest->bitsnum[0] = fx.i.m;
5459 dest->bitsnum[0] &= 0x007FFFFF;
5460 if (fx.i.exp_bias == 0) {
5461 /* Denormalized number - correct exponent */
5462 exponent2++;
5463 } else {
5464 /* Add hidden bit to mantissa */
5465 dest->bitsnum[0] |= 0x00800000;
5468 /* The act of copying a FP mantissa as integer bits is equivalent to
5469 shifting left the mantissa 23 bits. The exponent2 is reduced to
5470 compensate. */
5471 exponent2 -= 23;
5473 hres = VARIANT_DI_normalize(dest, exponent2, FALSE);
5476 return hres;
5479 typedef union
5481 struct
5483 unsigned int m_lo : 32; /* 52 bits of precision */
5484 unsigned int m_hi : 20;
5485 unsigned int exp_bias : 11; /* bias == 1023 */
5486 unsigned int sign : 1;
5487 } i;
5488 double d;
5489 } R8_FIELDS;
5491 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5492 intermediate string step. */
5493 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest)
5495 HRESULT hres = S_OK;
5496 R8_FIELDS fx;
5498 fx.d = source;
5500 /* Detect special cases */
5501 if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) {
5502 /* Floating-point zero */
5503 VARIANT_DI_clear(dest);
5504 } else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) {
5505 /* Floating-point infinity */
5506 hres = DISP_E_OVERFLOW;
5507 } else if (fx.i.exp_bias == 0x7FF) {
5508 /* Floating-point NaN */
5509 hres = DISP_E_BADVARTYPE;
5510 } else {
5511 int exponent2;
5512 VARIANT_DI_clear(dest);
5514 exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */
5515 dest->sign = fx.i.sign; /* Sign is simply copied */
5517 /* Copy significant bits to VARIANT_DI mantissa */
5518 dest->bitsnum[0] = fx.i.m_lo;
5519 dest->bitsnum[1] = fx.i.m_hi;
5520 dest->bitsnum[1] &= 0x000FFFFF;
5521 if (fx.i.exp_bias == 0) {
5522 /* Denormalized number - correct exponent */
5523 exponent2++;
5524 } else {
5525 /* Add hidden bit to mantissa */
5526 dest->bitsnum[1] |= 0x00100000;
5529 /* The act of copying a FP mantissa as integer bits is equivalent to
5530 shifting left the mantissa 52 bits. The exponent2 is reduced to
5531 compensate. */
5532 exponent2 -= 52;
5534 hres = VARIANT_DI_normalize(dest, exponent2, TRUE);
5537 return hres;
5540 static HRESULT VARIANT_do_division(const DECIMAL *pDecLeft, const DECIMAL *pDecRight, DECIMAL *pDecOut,
5541 BOOL round)
5543 HRESULT hRet = S_OK;
5544 VARIANT_DI di_left, di_right, di_result;
5545 HRESULT divresult;
5547 VARIANT_DIFromDec(pDecLeft, &di_left);
5548 VARIANT_DIFromDec(pDecRight, &di_right);
5549 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result, round);
5550 if (divresult != S_OK)
5552 /* division actually overflowed */
5553 hRet = divresult;
5555 else
5557 hRet = S_OK;
5559 if (di_result.scale > DEC_MAX_SCALE)
5561 unsigned char remainder = 0;
5563 /* division underflowed. In order to comply with the MSDN
5564 specifications for DECIMAL ranges, some significant digits
5565 must be removed
5567 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5568 di_result.scale);
5569 while (di_result.scale > DEC_MAX_SCALE &&
5570 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
5572 remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
5573 di_result.scale--;
5575 if (di_result.scale > DEC_MAX_SCALE)
5577 WARN("result underflowed, setting to 0\n");
5578 di_result.scale = 0;
5579 di_result.sign = 0;
5581 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5583 unsigned int i;
5584 for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
5585 ULONGLONG digit = di_result.bitsnum[i] + 1;
5586 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5587 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5591 VARIANT_DecFromDI(&di_result, pDecOut);
5593 return hRet;
5596 /************************************************************************
5597 * VarDecDiv (OLEAUT32.178)
5599 * Divide one DECIMAL by another.
5601 * PARAMS
5602 * pDecLeft [I] Source
5603 * pDecRight [I] Value to divide by
5604 * pDecOut [O] Destination
5606 * RETURNS
5607 * Success: S_OK.
5608 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5610 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5612 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5614 return VARIANT_do_division(pDecLeft, pDecRight, pDecOut, FALSE);
5617 /************************************************************************
5618 * VarDecMul (OLEAUT32.179)
5620 * Multiply one DECIMAL by another.
5622 * PARAMS
5623 * pDecLeft [I] Source
5624 * pDecRight [I] Value to multiply by
5625 * pDecOut [O] Destination
5627 * RETURNS
5628 * Success: S_OK.
5629 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5631 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5633 HRESULT hRet = S_OK;
5634 VARIANT_DI di_left, di_right, di_result;
5635 int mulresult;
5637 VARIANT_DIFromDec(pDecLeft, &di_left);
5638 VARIANT_DIFromDec(pDecRight, &di_right);
5639 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5640 if (mulresult)
5642 /* multiplication actually overflowed */
5643 hRet = DISP_E_OVERFLOW;
5645 else
5647 if (di_result.scale > DEC_MAX_SCALE)
5649 /* multiplication underflowed. In order to comply with the MSDN
5650 specifications for DECIMAL ranges, some significant digits
5651 must be removed
5653 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5654 di_result.scale);
5655 while (di_result.scale > DEC_MAX_SCALE &&
5656 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
5658 VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
5659 di_result.scale--;
5661 if (di_result.scale > DEC_MAX_SCALE)
5663 WARN("result underflowed, setting to 0\n");
5664 di_result.scale = 0;
5665 di_result.sign = 0;
5668 VARIANT_DecFromDI(&di_result, pDecOut);
5670 return hRet;
5673 /************************************************************************
5674 * VarDecSub (OLEAUT32.181)
5676 * Subtract one DECIMAL from another.
5678 * PARAMS
5679 * pDecLeft [I] Source
5680 * pDecRight [I] DECIMAL to subtract from pDecLeft
5681 * pDecOut [O] Destination
5683 * RETURNS
5684 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5686 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5688 DECIMAL decRight;
5690 /* Implement as addition of the negative */
5691 VarDecNeg(pDecRight, &decRight);
5692 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5695 /************************************************************************
5696 * VarDecAbs (OLEAUT32.182)
5698 * Convert a DECIMAL into its absolute value.
5700 * PARAMS
5701 * pDecIn [I] Source
5702 * pDecOut [O] Destination
5704 * RETURNS
5705 * S_OK. This function does not fail.
5707 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5709 *pDecOut = *pDecIn;
5710 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5711 return S_OK;
5714 /************************************************************************
5715 * VarDecFix (OLEAUT32.187)
5717 * Return the integer portion of a DECIMAL.
5719 * PARAMS
5720 * pDecIn [I] Source
5721 * pDecOut [O] Destination
5723 * RETURNS
5724 * Success: S_OK.
5725 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5727 * NOTES
5728 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5729 * negative numbers away from 0, while this function rounds them towards zero.
5731 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5733 double dbl;
5734 HRESULT hr;
5736 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5737 return E_INVALIDARG;
5739 if (!DEC_SCALE(pDecIn))
5741 *pDecOut = *pDecIn; /* Already an integer */
5742 return S_OK;
5745 hr = VarR8FromDec(pDecIn, &dbl);
5746 if (SUCCEEDED(hr)) {
5747 LONGLONG rounded = dbl;
5749 hr = VarDecFromI8(rounded, pDecOut);
5751 return hr;
5754 /************************************************************************
5755 * VarDecInt (OLEAUT32.188)
5757 * Return the integer portion of a DECIMAL.
5759 * PARAMS
5760 * pDecIn [I] Source
5761 * pDecOut [O] Destination
5763 * RETURNS
5764 * Success: S_OK.
5765 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5767 * NOTES
5768 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5769 * negative numbers towards 0, while this function rounds them away from zero.
5771 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5773 double dbl;
5774 HRESULT hr;
5776 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5777 return E_INVALIDARG;
5779 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5780 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5782 hr = VarR8FromDec(pDecIn, &dbl);
5783 if (SUCCEEDED(hr)) {
5784 LONGLONG rounded = dbl >= 0.0 ? dbl + 0.5 : dbl - 0.5;
5786 hr = VarDecFromI8(rounded, pDecOut);
5788 return hr;
5791 /************************************************************************
5792 * VarDecNeg (OLEAUT32.189)
5794 * Change the sign of a DECIMAL.
5796 * PARAMS
5797 * pDecIn [I] Source
5798 * pDecOut [O] Destination
5800 * RETURNS
5801 * S_OK. This function does not fail.
5803 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5805 *pDecOut = *pDecIn;
5806 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5807 return S_OK;
5810 /************************************************************************
5811 * VarDecRound (OLEAUT32.203)
5813 * Change the precision of a DECIMAL.
5815 * PARAMS
5816 * pDecIn [I] Source
5817 * cDecimals [I] New number of decimals to keep
5818 * pDecOut [O] Destination
5820 * RETURNS
5821 * Success: S_OK. pDecOut contains the rounded value.
5822 * Failure: E_INVALIDARG if any argument is invalid.
5824 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5826 DECIMAL divisor, tmp;
5827 HRESULT hr;
5828 unsigned int i;
5830 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5831 return E_INVALIDARG;
5833 if (cDecimals >= DEC_SCALE(pDecIn))
5835 *pDecOut = *pDecIn; /* More precision than we have */
5836 return S_OK;
5839 /* truncate significant digits and rescale */
5840 memset(&divisor, 0, sizeof(divisor));
5841 DEC_LO64(&divisor) = 1;
5843 memset(&tmp, 0, sizeof(tmp));
5844 DEC_LO64(&tmp) = 10;
5845 for (i = 0; i < DEC_SCALE(pDecIn) - cDecimals; ++i)
5847 hr = VarDecMul(&divisor, &tmp, &divisor);
5848 if (FAILED(hr))
5849 return hr;
5852 hr = VARIANT_do_division(pDecIn, &divisor, pDecOut, TRUE);
5853 if (FAILED(hr))
5854 return hr;
5856 DEC_SCALE(pDecOut) = cDecimals;
5858 return S_OK;
5861 /************************************************************************
5862 * VarDecCmp (OLEAUT32.204)
5864 * Compare two DECIMAL values.
5866 * PARAMS
5867 * pDecLeft [I] Source
5868 * pDecRight [I] Value to compare
5870 * RETURNS
5871 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5872 * is less than, equal to or greater than pDecRight respectively.
5873 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5875 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5877 HRESULT hRet;
5878 DECIMAL result;
5880 if (!pDecLeft || !pDecRight)
5881 return VARCMP_NULL;
5883 if ((!(DEC_SIGN(pDecLeft) & DECIMAL_NEG)) && (DEC_SIGN(pDecRight) & DECIMAL_NEG) &&
5884 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5885 return VARCMP_GT;
5886 else if ((DEC_SIGN(pDecLeft) & DECIMAL_NEG) && (!(DEC_SIGN(pDecRight) & DECIMAL_NEG)) &&
5887 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5888 return VARCMP_LT;
5890 /* Subtract right from left, and compare the result to 0 */
5891 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5893 if (SUCCEEDED(hRet))
5895 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5897 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5898 hRet = (HRESULT)VARCMP_LT;
5899 else if (non_zero)
5900 hRet = (HRESULT)VARCMP_GT;
5901 else
5902 hRet = (HRESULT)VARCMP_EQ;
5904 return hRet;
5907 /************************************************************************
5908 * VarDecCmpR8 (OLEAUT32.298)
5910 * Compare a DECIMAL to a double
5912 * PARAMS
5913 * pDecLeft [I] DECIMAL Source
5914 * dblRight [I] double to compare to pDecLeft
5916 * RETURNS
5917 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5918 * is less than, equal to or greater than pDecLeft respectively.
5919 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5921 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5923 HRESULT hRet;
5924 DECIMAL decRight;
5926 hRet = VarDecFromR8(dblRight, &decRight);
5928 if (SUCCEEDED(hRet))
5929 hRet = VarDecCmp(pDecLeft, &decRight);
5931 return hRet;
5934 /* BOOL
5937 /************************************************************************
5938 * VarBoolFromUI1 (OLEAUT32.118)
5940 * Convert a VT_UI1 to a VT_BOOL.
5942 * PARAMS
5943 * bIn [I] Source
5944 * pBoolOut [O] Destination
5946 * RETURNS
5947 * S_OK.
5949 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5951 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5952 return S_OK;
5955 /************************************************************************
5956 * VarBoolFromI2 (OLEAUT32.119)
5958 * Convert a VT_I2 to a VT_BOOL.
5960 * PARAMS
5961 * sIn [I] Source
5962 * pBoolOut [O] Destination
5964 * RETURNS
5965 * S_OK.
5967 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5969 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5970 return S_OK;
5973 /************************************************************************
5974 * VarBoolFromI4 (OLEAUT32.120)
5976 * Convert a VT_I4 to a VT_BOOL.
5978 * PARAMS
5979 * sIn [I] Source
5980 * pBoolOut [O] Destination
5982 * RETURNS
5983 * S_OK.
5985 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
5987 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
5988 return S_OK;
5991 /************************************************************************
5992 * VarBoolFromR4 (OLEAUT32.121)
5994 * Convert a VT_R4 to a VT_BOOL.
5996 * PARAMS
5997 * fltIn [I] Source
5998 * pBoolOut [O] Destination
6000 * RETURNS
6001 * S_OK.
6003 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
6005 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
6006 return S_OK;
6009 /************************************************************************
6010 * VarBoolFromR8 (OLEAUT32.122)
6012 * Convert a VT_R8 to a VT_BOOL.
6014 * PARAMS
6015 * dblIn [I] Source
6016 * pBoolOut [O] Destination
6018 * RETURNS
6019 * S_OK.
6021 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
6023 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
6024 return S_OK;
6027 /************************************************************************
6028 * VarBoolFromDate (OLEAUT32.123)
6030 * Convert a VT_DATE to a VT_BOOL.
6032 * PARAMS
6033 * dateIn [I] Source
6034 * pBoolOut [O] Destination
6036 * RETURNS
6037 * S_OK.
6039 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
6041 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
6042 return S_OK;
6045 /************************************************************************
6046 * VarBoolFromCy (OLEAUT32.124)
6048 * Convert a VT_CY to a VT_BOOL.
6050 * PARAMS
6051 * cyIn [I] Source
6052 * pBoolOut [O] Destination
6054 * RETURNS
6055 * S_OK.
6057 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
6059 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
6060 return S_OK;
6063 /************************************************************************
6064 * VARIANT_GetLocalisedText [internal]
6066 * Get a localized string from the resources
6069 BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
6071 HRSRC hrsrc;
6073 hrsrc = FindResourceExW( hProxyDll, (LPWSTR)RT_STRING,
6074 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
6075 if (hrsrc)
6077 HGLOBAL hmem = LoadResource( hProxyDll, hrsrc );
6079 if (hmem)
6081 const WCHAR *p;
6082 unsigned int i;
6084 p = LockResource( hmem );
6085 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
6087 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
6088 lpszDest[*p] = '\0';
6089 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
6090 return TRUE;
6093 return FALSE;
6096 /************************************************************************
6097 * VarBoolFromStr (OLEAUT32.125)
6099 * Convert a VT_BSTR to a VT_BOOL.
6101 * PARAMS
6102 * strIn [I] Source
6103 * lcid [I] LCID for the conversion
6104 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6105 * pBoolOut [O] Destination
6107 * RETURNS
6108 * Success: S_OK.
6109 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6110 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6112 * NOTES
6113 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6114 * it may contain (in any case mapping) the text "true" or "false".
6115 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6116 * localised text of "True" or "False" in the language specified by lcid.
6117 * - If none of these matches occur, the string is treated as a numeric string
6118 * and the boolean pBoolOut will be set according to whether the number is zero
6119 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6120 * - If the text is not numeric and does not match any of the above, then
6121 * DISP_E_TYPEMISMATCH is returned.
6123 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
6125 /* Any VB/VBA programmers out there should recognise these strings... */
6126 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
6127 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
6128 WCHAR szBuff[64];
6129 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6130 HRESULT hRes = S_OK;
6132 if (!strIn || !pBoolOut)
6133 return DISP_E_TYPEMISMATCH;
6135 /* Check if we should be comparing against localised text */
6136 if (dwFlags & VAR_LOCALBOOL)
6138 /* Convert our LCID into a usable value */
6139 lcid = ConvertDefaultLocale(lcid);
6141 langId = LANGIDFROMLCID(lcid);
6143 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6144 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6146 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6147 * I don't think this is needed unless any of the localised text strings
6148 * contain characters that can be so mapped. In the event that this is
6149 * true for a given language (possibly some Asian languages), then strIn
6150 * should be mapped here _only_ if langId is an Id for which this can occur.
6154 /* Note that if we are not comparing against localised strings, langId
6155 * will have its default value of LANG_ENGLISH. This allows us to mimic
6156 * the native behaviour of always checking against English strings even
6157 * after we've checked for localised ones.
6159 VarBoolFromStr_CheckLocalised:
6160 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
6162 /* Compare against localised strings, ignoring case */
6163 if (!strcmpiW(strIn, szBuff))
6165 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
6166 return hRes;
6168 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
6169 if (!strcmpiW(strIn, szBuff))
6171 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
6172 return hRes;
6176 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6178 /* We have checked the localised text, now check English */
6179 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6180 goto VarBoolFromStr_CheckLocalised;
6183 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6184 if (!strcmpW(strIn, szFalse))
6185 *pBoolOut = VARIANT_FALSE;
6186 else if (!strcmpW(strIn, szTrue))
6187 *pBoolOut = VARIANT_TRUE;
6188 else
6190 double d;
6192 /* If this string is a number, convert it as one */
6193 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
6194 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
6196 return hRes;
6199 /************************************************************************
6200 * VarBoolFromDisp (OLEAUT32.126)
6202 * Convert a VT_DISPATCH to a VT_BOOL.
6204 * PARAMS
6205 * pdispIn [I] Source
6206 * lcid [I] LCID for conversion
6207 * pBoolOut [O] Destination
6209 * RETURNS
6210 * Success: S_OK.
6211 * Failure: E_INVALIDARG, if the source value is invalid
6212 * DISP_E_OVERFLOW, if the value will not fit in the destination
6213 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6215 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
6217 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
6220 /************************************************************************
6221 * VarBoolFromI1 (OLEAUT32.233)
6223 * Convert a VT_I1 to a VT_BOOL.
6225 * PARAMS
6226 * cIn [I] Source
6227 * pBoolOut [O] Destination
6229 * RETURNS
6230 * S_OK.
6232 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
6234 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
6235 return S_OK;
6238 /************************************************************************
6239 * VarBoolFromUI2 (OLEAUT32.234)
6241 * Convert a VT_UI2 to a VT_BOOL.
6243 * PARAMS
6244 * usIn [I] Source
6245 * pBoolOut [O] Destination
6247 * RETURNS
6248 * S_OK.
6250 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
6252 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
6253 return S_OK;
6256 /************************************************************************
6257 * VarBoolFromUI4 (OLEAUT32.235)
6259 * Convert a VT_UI4 to a VT_BOOL.
6261 * PARAMS
6262 * ulIn [I] Source
6263 * pBoolOut [O] Destination
6265 * RETURNS
6266 * S_OK.
6268 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
6270 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
6271 return S_OK;
6274 /************************************************************************
6275 * VarBoolFromDec (OLEAUT32.236)
6277 * Convert a VT_DECIMAL to a VT_BOOL.
6279 * PARAMS
6280 * pDecIn [I] Source
6281 * pBoolOut [O] Destination
6283 * RETURNS
6284 * Success: S_OK.
6285 * Failure: E_INVALIDARG, if pDecIn is invalid.
6287 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
6289 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
6290 return E_INVALIDARG;
6292 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
6293 *pBoolOut = VARIANT_TRUE;
6294 else
6295 *pBoolOut = VARIANT_FALSE;
6296 return S_OK;
6299 /************************************************************************
6300 * VarBoolFromI8 (OLEAUT32.370)
6302 * Convert a VT_I8 to a VT_BOOL.
6304 * PARAMS
6305 * ullIn [I] Source
6306 * pBoolOut [O] Destination
6308 * RETURNS
6309 * S_OK.
6311 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
6313 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
6314 return S_OK;
6317 /************************************************************************
6318 * VarBoolFromUI8 (OLEAUT32.371)
6320 * Convert a VT_UI8 to a VT_BOOL.
6322 * PARAMS
6323 * ullIn [I] Source
6324 * pBoolOut [O] Destination
6326 * RETURNS
6327 * S_OK.
6329 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
6331 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
6332 return S_OK;
6335 /* BSTR
6338 /* Write a number from a UI8 and sign */
6339 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
6343 WCHAR ulNextDigit = ulVal % 10;
6345 *szOut-- = '0' + ulNextDigit;
6346 ulVal = (ulVal - ulNextDigit) / 10;
6347 } while (ulVal);
6349 szOut++;
6350 return szOut;
6353 /* Create a (possibly localised) BSTR from a UI8 and sign */
6354 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
6356 WCHAR szConverted[256];
6358 if (dwFlags & VAR_NEGATIVE)
6359 *--szOut = '-';
6361 if (dwFlags & LOCALE_USE_NLS)
6363 /* Format the number for the locale */
6364 szConverted[0] = '\0';
6365 GetNumberFormatW(lcid,
6366 dwFlags & LOCALE_NOUSEROVERRIDE,
6367 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
6368 szOut = szConverted;
6370 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
6373 /* Create a (possibly localised) BSTR from a UI8 and sign */
6374 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
6376 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
6378 if (!pbstrOut)
6379 return E_INVALIDARG;
6381 /* Create the basic number string */
6382 *szOut-- = '\0';
6383 szOut = VARIANT_WriteNumber(ulVal, szOut);
6385 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
6386 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6387 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6390 /******************************************************************************
6391 * VarBstrFromUI1 (OLEAUT32.108)
6393 * Convert a VT_UI1 to a VT_BSTR.
6395 * PARAMS
6396 * bIn [I] Source
6397 * lcid [I] LCID for the conversion
6398 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6399 * pbstrOut [O] Destination
6401 * RETURNS
6402 * Success: S_OK.
6403 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6404 * E_OUTOFMEMORY, if memory allocation fails.
6406 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6408 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6411 /******************************************************************************
6412 * VarBstrFromI2 (OLEAUT32.109)
6414 * Convert a VT_I2 to a VT_BSTR.
6416 * PARAMS
6417 * sIn [I] Source
6418 * lcid [I] LCID for the conversion
6419 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6420 * pbstrOut [O] Destination
6422 * RETURNS
6423 * Success: S_OK.
6424 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6425 * E_OUTOFMEMORY, if memory allocation fails.
6427 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6429 ULONG64 ul64 = sIn;
6431 if (sIn < 0)
6433 ul64 = -sIn;
6434 dwFlags |= VAR_NEGATIVE;
6436 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6439 /******************************************************************************
6440 * VarBstrFromI4 (OLEAUT32.110)
6442 * Convert a VT_I4 to a VT_BSTR.
6444 * PARAMS
6445 * lIn [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 VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6457 ULONG64 ul64 = lIn;
6459 if (lIn < 0)
6461 ul64 = (ULONG)-lIn;
6462 dwFlags |= VAR_NEGATIVE;
6464 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6467 static BSTR VARIANT_BstrReplaceDecimal(const WCHAR * buff, LCID lcid, ULONG dwFlags)
6469 BSTR bstrOut;
6470 WCHAR lpDecimalSep[16];
6472 /* Native oleaut32 uses the locale-specific decimal separator even in the
6473 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6474 American locales will see "one thousand and one tenth" as "1000,1"
6475 instead of "1000.1" (notice the comma). The following code checks for
6476 the need to replace the decimal separator, and if so, will prepare an
6477 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6479 GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE),
6480 lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
6481 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6483 /* locale is compatible with English - return original string */
6484 bstrOut = SysAllocString(buff);
6486 else
6488 WCHAR *p;
6489 WCHAR numbuff[256];
6490 WCHAR empty[] = {'\0'};
6491 NUMBERFMTW minFormat;
6493 minFormat.NumDigits = 0;
6494 minFormat.LeadingZero = 0;
6495 minFormat.Grouping = 0;
6496 minFormat.lpDecimalSep = lpDecimalSep;
6497 minFormat.lpThousandSep = empty;
6498 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6500 /* count number of decimal digits in string */
6501 p = strchrW( buff, '.' );
6502 if (p) minFormat.NumDigits = strlenW(p + 1);
6504 numbuff[0] = '\0';
6505 if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
6507 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6508 bstrOut = SysAllocString(buff);
6510 else
6512 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6513 bstrOut = SysAllocString(numbuff);
6516 return bstrOut;
6519 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6520 BSTR* pbstrOut, LPCWSTR lpszFormat)
6522 WCHAR buff[256];
6524 if (!pbstrOut)
6525 return E_INVALIDARG;
6527 sprintfW( buff, lpszFormat, dblIn );
6529 /* Negative zeroes are disallowed (some applications depend on this).
6530 If buff starts with a minus, and then nothing follows but zeroes
6531 and/or a period, it is a negative zero and is replaced with a
6532 canonical zero. This duplicates native oleaut32 behavior.
6534 if (buff[0] == '-')
6536 const WCHAR szAccept[] = {'0', '.', '\0'};
6537 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
6538 { buff[0] = '0'; buff[1] = '\0'; }
6541 TRACE("created string %s\n", debugstr_w(buff));
6542 if (dwFlags & LOCALE_USE_NLS)
6544 WCHAR numbuff[256];
6546 /* Format the number for the locale */
6547 numbuff[0] = '\0';
6548 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6549 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6550 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6551 *pbstrOut = SysAllocString(numbuff);
6553 else
6555 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6557 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6560 /******************************************************************************
6561 * VarBstrFromR4 (OLEAUT32.111)
6563 * Convert a VT_R4 to a VT_BSTR.
6565 * PARAMS
6566 * fltIn [I] Source
6567 * lcid [I] LCID for the conversion
6568 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6569 * pbstrOut [O] Destination
6571 * RETURNS
6572 * Success: S_OK.
6573 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6574 * E_OUTOFMEMORY, if memory allocation fails.
6576 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6578 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
6581 /******************************************************************************
6582 * VarBstrFromR8 (OLEAUT32.112)
6584 * Convert a VT_R8 to a VT_BSTR.
6586 * PARAMS
6587 * dblIn [I] Source
6588 * lcid [I] LCID for the conversion
6589 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6590 * pbstrOut [O] Destination
6592 * RETURNS
6593 * Success: S_OK.
6594 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6595 * E_OUTOFMEMORY, if memory allocation fails.
6597 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6599 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
6602 /******************************************************************************
6603 * VarBstrFromCy [OLEAUT32.113]
6605 * Convert a VT_CY to a VT_BSTR.
6607 * PARAMS
6608 * cyIn [I] Source
6609 * lcid [I] LCID for the conversion
6610 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6611 * pbstrOut [O] Destination
6613 * RETURNS
6614 * Success: S_OK.
6615 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6616 * E_OUTOFMEMORY, if memory allocation fails.
6618 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6620 WCHAR buff[256];
6621 VARIANT_DI decVal;
6623 if (!pbstrOut)
6624 return E_INVALIDARG;
6626 decVal.scale = 4;
6627 decVal.sign = 0;
6628 decVal.bitsnum[0] = cyIn.s.Lo;
6629 decVal.bitsnum[1] = cyIn.s.Hi;
6630 if (cyIn.s.Hi & 0x80000000UL) {
6631 DWORD one = 1;
6633 /* Negative number! */
6634 decVal.sign = 1;
6635 decVal.bitsnum[0] = ~decVal.bitsnum[0];
6636 decVal.bitsnum[1] = ~decVal.bitsnum[1];
6637 VARIANT_int_add(decVal.bitsnum, 3, &one, 1);
6639 decVal.bitsnum[2] = 0;
6640 VARIANT_DI_tostringW(&decVal, buff, sizeof(buff)/sizeof(buff[0]));
6642 if (dwFlags & LOCALE_USE_NLS)
6644 WCHAR cybuff[256];
6646 /* Format the currency for the locale */
6647 cybuff[0] = '\0';
6648 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6649 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR));
6650 *pbstrOut = SysAllocString(cybuff);
6652 else
6653 *pbstrOut = VARIANT_BstrReplaceDecimal(buff,lcid,dwFlags);
6655 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6658 static inline int output_int_len(int o, int min_len, WCHAR *date, int date_len)
6660 int len, tmp;
6662 if(min_len >= date_len)
6663 return -1;
6665 for(len=0, tmp=o; tmp; tmp/=10) len++;
6666 if(!len) len++;
6667 if(len >= date_len)
6668 return -1;
6670 for(tmp=min_len-len; tmp>0; tmp--)
6671 *date++ = '0';
6672 for(tmp=len; tmp>0; tmp--, o/=10)
6673 date[tmp-1] = '0' + o%10;
6674 return min_len>len ? min_len : len;
6677 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6678 BOOL get_date_format(LCID lcid, DWORD flags, const SYSTEMTIME *st,
6679 const WCHAR *fmt, WCHAR *date, int date_len)
6681 static const LCTYPE dayname[] = {
6682 LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
6683 LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6
6685 static const LCTYPE sdayname[] = {
6686 LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
6687 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
6688 LOCALE_SABBREVDAYNAME6
6690 static const LCTYPE monthname[] = {
6691 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
6692 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
6693 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12
6695 static const LCTYPE smonthname[] = {
6696 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
6697 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
6698 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
6699 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12
6702 if(flags & ~(LOCALE_NOUSEROVERRIDE|VAR_DATEVALUEONLY))
6703 FIXME("ignoring flags %x\n", flags);
6704 flags &= LOCALE_NOUSEROVERRIDE;
6706 while(*fmt && date_len) {
6707 int count = 1;
6709 switch(*fmt) {
6710 case 'd':
6711 case 'M':
6712 case 'y':
6713 case 'g':
6714 while(*fmt == *(fmt+count))
6715 count++;
6716 fmt += count-1;
6719 switch(*fmt) {
6720 case 'd':
6721 if(count >= 4)
6722 count = GetLocaleInfoW(lcid, dayname[st->wDayOfWeek] | flags, date, date_len)-1;
6723 else if(count == 3)
6724 count = GetLocaleInfoW(lcid, sdayname[st->wDayOfWeek] | flags, date, date_len)-1;
6725 else
6726 count = output_int_len(st->wDay, count, date, date_len);
6727 break;
6728 case 'M':
6729 if(count >= 4)
6730 count = GetLocaleInfoW(lcid, monthname[st->wMonth-1] | flags, date, date_len)-1;
6731 else if(count == 3)
6732 count = GetLocaleInfoW(lcid, smonthname[st->wMonth-1] | flags, date, date_len)-1;
6733 else
6734 count = output_int_len(st->wMonth, count, date, date_len);
6735 break;
6736 case 'y':
6737 if(count >= 3)
6738 count = output_int_len(st->wYear, 0, date, date_len);
6739 else
6740 count = output_int_len(st->wYear%100, count, date, date_len);
6741 break;
6742 case 'g':
6743 if(count == 2) {
6744 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6746 *date++ = 'A';
6747 date_len--;
6748 if(date_len)
6749 *date = 'D';
6750 else
6751 count = -1;
6752 break;
6754 /* fall through */
6755 default:
6756 *date = *fmt;
6759 if(count < 0)
6760 break;
6761 fmt++;
6762 date += count;
6763 date_len -= count;
6766 if(!date_len)
6767 return FALSE;
6768 *date++ = 0;
6769 return TRUE;
6772 /******************************************************************************
6773 * VarBstrFromDate [OLEAUT32.114]
6775 * Convert a VT_DATE to a VT_BSTR.
6777 * PARAMS
6778 * dateIn [I] Source
6779 * lcid [I] LCID for the conversion
6780 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6781 * pbstrOut [O] Destination
6783 * RETURNS
6784 * Success: S_OK.
6785 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6786 * E_OUTOFMEMORY, if memory allocation fails.
6788 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6790 SYSTEMTIME st;
6791 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6792 WCHAR date[128], fmt_buff[80], *time;
6794 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
6796 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6797 return E_INVALIDARG;
6799 *pbstrOut = NULL;
6801 if (dwFlags & VAR_CALENDAR_THAI)
6802 st.wYear += 553; /* Use the Thai buddhist calendar year */
6803 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6804 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6806 if (dwFlags & LOCALE_USE_NLS)
6807 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6808 else
6810 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6811 double partial = dateIn - whole;
6813 if (whole == 0.0)
6814 dwFlags |= VAR_TIMEVALUEONLY;
6815 else if (partial > -1e-12 && partial < 1e-12)
6816 dwFlags |= VAR_DATEVALUEONLY;
6819 if (dwFlags & VAR_TIMEVALUEONLY)
6820 date[0] = '\0';
6821 else
6822 if (!GetLocaleInfoW(lcid, LOCALE_SSHORTDATE, fmt_buff, sizeof(fmt_buff)/sizeof(WCHAR)) ||
6823 !get_date_format(lcid, dwFlags, &st, fmt_buff, date, sizeof(date)/sizeof(WCHAR)))
6824 return E_INVALIDARG;
6826 if (!(dwFlags & VAR_DATEVALUEONLY))
6828 time = date + strlenW(date);
6829 if (time != date)
6830 *time++ = ' ';
6831 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
6832 sizeof(date)/sizeof(WCHAR)-(time-date)))
6833 return E_INVALIDARG;
6836 *pbstrOut = SysAllocString(date);
6837 if (*pbstrOut)
6838 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6839 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6842 /******************************************************************************
6843 * VarBstrFromBool (OLEAUT32.116)
6845 * Convert a VT_BOOL to a VT_BSTR.
6847 * PARAMS
6848 * boolIn [I] Source
6849 * lcid [I] LCID for the conversion
6850 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6851 * pbstrOut [O] Destination
6853 * RETURNS
6854 * Success: S_OK.
6855 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6856 * E_OUTOFMEMORY, if memory allocation fails.
6858 * NOTES
6859 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6860 * localised text of "True" or "False". To convert a bool into a
6861 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6863 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6865 WCHAR szBuff[64];
6866 DWORD dwResId = IDS_TRUE;
6867 LANGID langId;
6869 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn, lcid, dwFlags, pbstrOut);
6871 if (!pbstrOut)
6872 return E_INVALIDARG;
6874 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6875 * for variant formatting */
6876 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6878 case VAR_BOOLONOFF:
6879 dwResId = IDS_ON;
6880 break;
6881 case VAR_BOOLYESNO:
6882 dwResId = IDS_YES;
6883 break;
6884 case VAR_LOCALBOOL:
6885 break;
6886 default:
6887 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6890 lcid = ConvertDefaultLocale(lcid);
6891 langId = LANGIDFROMLCID(lcid);
6892 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6893 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6895 if (boolIn == VARIANT_FALSE)
6896 dwResId++; /* Use negative form */
6898 VarBstrFromBool_GetLocalised:
6899 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6901 *pbstrOut = SysAllocString(szBuff);
6902 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6905 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6907 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6908 goto VarBstrFromBool_GetLocalised;
6911 /* Should never get here */
6912 WARN("Failed to load bool text!\n");
6913 return E_OUTOFMEMORY;
6916 /******************************************************************************
6917 * VarBstrFromI1 (OLEAUT32.229)
6919 * Convert a VT_I1 to a VT_BSTR.
6921 * PARAMS
6922 * cIn [I] Source
6923 * lcid [I] LCID for the conversion
6924 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6925 * pbstrOut [O] Destination
6927 * RETURNS
6928 * Success: S_OK.
6929 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6930 * E_OUTOFMEMORY, if memory allocation fails.
6932 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6934 ULONG64 ul64 = cIn;
6936 if (cIn < 0)
6938 ul64 = -cIn;
6939 dwFlags |= VAR_NEGATIVE;
6941 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6944 /******************************************************************************
6945 * VarBstrFromUI2 (OLEAUT32.230)
6947 * Convert a VT_UI2 to a VT_BSTR.
6949 * PARAMS
6950 * usIn [I] Source
6951 * lcid [I] LCID for the conversion
6952 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6953 * pbstrOut [O] Destination
6955 * RETURNS
6956 * Success: S_OK.
6957 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6958 * E_OUTOFMEMORY, if memory allocation fails.
6960 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6962 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6965 /******************************************************************************
6966 * VarBstrFromUI4 (OLEAUT32.231)
6968 * Convert a VT_UI4 to a VT_BSTR.
6970 * PARAMS
6971 * ulIn [I] Source
6972 * lcid [I] LCID for the conversion
6973 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6974 * pbstrOut [O] Destination
6976 * RETURNS
6977 * Success: S_OK.
6978 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6979 * E_OUTOFMEMORY, if memory allocation fails.
6981 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6983 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
6986 /******************************************************************************
6987 * VarBstrFromDec (OLEAUT32.232)
6989 * Convert a VT_DECIMAL to a VT_BSTR.
6991 * PARAMS
6992 * pDecIn [I] Source
6993 * lcid [I] LCID for the conversion
6994 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6995 * pbstrOut [O] Destination
6997 * RETURNS
6998 * Success: S_OK.
6999 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7000 * E_OUTOFMEMORY, if memory allocation fails.
7002 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7004 WCHAR buff[256];
7005 VARIANT_DI temp;
7007 if (!pbstrOut)
7008 return E_INVALIDARG;
7010 VARIANT_DIFromDec(pDecIn, &temp);
7011 VARIANT_DI_tostringW(&temp, buff, 256);
7013 if (dwFlags & LOCALE_USE_NLS)
7015 WCHAR numbuff[256];
7017 /* Format the number for the locale */
7018 numbuff[0] = '\0';
7019 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
7020 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
7021 TRACE("created NLS string %s\n", debugstr_w(numbuff));
7022 *pbstrOut = SysAllocString(numbuff);
7024 else
7026 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
7029 TRACE("returning %s\n", debugstr_w(*pbstrOut));
7030 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
7033 /************************************************************************
7034 * VarBstrFromI8 (OLEAUT32.370)
7036 * Convert a VT_I8 to a VT_BSTR.
7038 * PARAMS
7039 * llIn [I] Source
7040 * lcid [I] LCID for the conversion
7041 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7042 * pbstrOut [O] Destination
7044 * RETURNS
7045 * Success: S_OK.
7046 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7047 * E_OUTOFMEMORY, if memory allocation fails.
7049 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7051 ULONG64 ul64 = llIn;
7053 if (llIn < 0)
7055 ul64 = -llIn;
7056 dwFlags |= VAR_NEGATIVE;
7058 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
7061 /************************************************************************
7062 * VarBstrFromUI8 (OLEAUT32.371)
7064 * Convert a VT_UI8 to a VT_BSTR.
7066 * PARAMS
7067 * ullIn [I] Source
7068 * lcid [I] LCID for the conversion
7069 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7070 * pbstrOut [O] Destination
7072 * RETURNS
7073 * Success: S_OK.
7074 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7075 * E_OUTOFMEMORY, if memory allocation fails.
7077 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7079 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
7082 /************************************************************************
7083 * VarBstrFromDisp (OLEAUT32.115)
7085 * Convert a VT_DISPATCH to a BSTR.
7087 * PARAMS
7088 * pdispIn [I] Source
7089 * lcid [I] LCID for conversion
7090 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7091 * pbstrOut [O] Destination
7093 * RETURNS
7094 * Success: S_OK.
7095 * Failure: E_INVALIDARG, if the source value is invalid
7096 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7098 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7100 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
7103 /**********************************************************************
7104 * VarBstrCat (OLEAUT32.313)
7106 * Concatenate two BSTR values.
7108 * PARAMS
7109 * pbstrLeft [I] Source
7110 * pbstrRight [I] Value to concatenate
7111 * pbstrOut [O] Destination
7113 * RETURNS
7114 * Success: S_OK.
7115 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7116 * E_OUTOFMEMORY, if memory allocation fails.
7118 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
7120 unsigned int lenLeft, lenRight;
7122 TRACE("%s,%s,%p\n",
7123 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7124 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
7126 if (!pbstrOut)
7127 return E_INVALIDARG;
7129 /* use byte length here to properly handle ansi-allocated BSTRs */
7130 lenLeft = pbstrLeft ? SysStringByteLen(pbstrLeft) : 0;
7131 lenRight = pbstrRight ? SysStringByteLen(pbstrRight) : 0;
7133 *pbstrOut = SysAllocStringByteLen(NULL, lenLeft + lenRight);
7134 if (!*pbstrOut)
7135 return E_OUTOFMEMORY;
7137 (*pbstrOut)[0] = '\0';
7139 if (pbstrLeft)
7140 memcpy(*pbstrOut, pbstrLeft, lenLeft);
7142 if (pbstrRight)
7143 memcpy((CHAR*)*pbstrOut + lenLeft, pbstrRight, lenRight);
7145 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
7146 return S_OK;
7149 /**********************************************************************
7150 * VarBstrCmp (OLEAUT32.314)
7152 * Compare two BSTR values.
7154 * PARAMS
7155 * pbstrLeft [I] Source
7156 * pbstrRight [I] Value to compare
7157 * lcid [I] LCID for the comparison
7158 * dwFlags [I] Flags to pass directly to CompareStringW().
7160 * RETURNS
7161 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7162 * than, equal to or greater than pbstrRight respectively.
7164 * NOTES
7165 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7166 * states. A NULL BSTR pointer is equivalent to an empty string.
7167 * If LCID is equal to 0, a byte by byte comparison is performed.
7169 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
7171 HRESULT hres;
7172 int ret;
7174 TRACE("%s,%s,%d,%08x\n",
7175 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7176 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
7178 if (!pbstrLeft || !*pbstrLeft)
7180 if (pbstrRight && *pbstrRight)
7181 return VARCMP_LT;
7183 else if (!pbstrRight || !*pbstrRight)
7184 return VARCMP_GT;
7186 if (lcid == 0)
7188 unsigned int lenLeft = SysStringByteLen(pbstrLeft);
7189 unsigned int lenRight = SysStringByteLen(pbstrRight);
7190 ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight));
7191 if (ret < 0)
7192 return VARCMP_LT;
7193 if (ret > 0)
7194 return VARCMP_GT;
7195 if (lenLeft < lenRight)
7196 return VARCMP_LT;
7197 if (lenLeft > lenRight)
7198 return VARCMP_GT;
7199 return VARCMP_EQ;
7201 else
7203 unsigned int lenLeft = SysStringLen(pbstrLeft);
7204 unsigned int lenRight = SysStringLen(pbstrRight);
7206 if (lenLeft == 0 || lenRight == 0)
7208 if (lenLeft == 0 && lenRight == 0) return VARCMP_EQ;
7209 return lenLeft < lenRight ? VARCMP_LT : VARCMP_GT;
7212 hres = CompareStringW(lcid, dwFlags, pbstrLeft, lenLeft,
7213 pbstrRight, lenRight) - CSTR_LESS_THAN;
7214 TRACE("%d\n", hres);
7215 return hres;
7220 * DATE
7223 /******************************************************************************
7224 * VarDateFromUI1 (OLEAUT32.88)
7226 * Convert a VT_UI1 to a VT_DATE.
7228 * PARAMS
7229 * bIn [I] Source
7230 * pdateOut [O] Destination
7232 * RETURNS
7233 * S_OK.
7235 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
7237 return VarR8FromUI1(bIn, pdateOut);
7240 /******************************************************************************
7241 * VarDateFromI2 (OLEAUT32.89)
7243 * Convert a VT_I2 to a VT_DATE.
7245 * PARAMS
7246 * sIn [I] Source
7247 * pdateOut [O] Destination
7249 * RETURNS
7250 * S_OK.
7252 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
7254 return VarR8FromI2(sIn, pdateOut);
7257 /******************************************************************************
7258 * VarDateFromI4 (OLEAUT32.90)
7260 * Convert a VT_I4 to a VT_DATE.
7262 * PARAMS
7263 * lIn [I] Source
7264 * pdateOut [O] Destination
7266 * RETURNS
7267 * S_OK.
7269 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
7271 return VarDateFromR8(lIn, pdateOut);
7274 /******************************************************************************
7275 * VarDateFromR4 (OLEAUT32.91)
7277 * Convert a VT_R4 to a VT_DATE.
7279 * PARAMS
7280 * fltIn [I] Source
7281 * pdateOut [O] Destination
7283 * RETURNS
7284 * S_OK.
7286 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
7288 return VarR8FromR4(fltIn, pdateOut);
7291 /******************************************************************************
7292 * VarDateFromR8 (OLEAUT32.92)
7294 * Convert a VT_R8 to a VT_DATE.
7296 * PARAMS
7297 * dblIn [I] Source
7298 * pdateOut [O] Destination
7300 * RETURNS
7301 * S_OK.
7303 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
7305 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
7306 *pdateOut = (DATE)dblIn;
7307 return S_OK;
7310 /**********************************************************************
7311 * VarDateFromDisp (OLEAUT32.95)
7313 * Convert a VT_DISPATCH to a VT_DATE.
7315 * PARAMS
7316 * pdispIn [I] Source
7317 * lcid [I] LCID for conversion
7318 * pdateOut [O] Destination
7320 * RETURNS
7321 * Success: S_OK.
7322 * Failure: E_INVALIDARG, if the source value is invalid
7323 * DISP_E_OVERFLOW, if the value will not fit in the destination
7324 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7326 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
7328 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
7331 /******************************************************************************
7332 * VarDateFromBool (OLEAUT32.96)
7334 * Convert a VT_BOOL to a VT_DATE.
7336 * PARAMS
7337 * boolIn [I] Source
7338 * pdateOut [O] Destination
7340 * RETURNS
7341 * S_OK.
7343 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
7345 return VarR8FromBool(boolIn, pdateOut);
7348 /**********************************************************************
7349 * VarDateFromCy (OLEAUT32.93)
7351 * Convert a VT_CY to a VT_DATE.
7353 * PARAMS
7354 * lIn [I] Source
7355 * pdateOut [O] Destination
7357 * RETURNS
7358 * S_OK.
7360 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
7362 return VarR8FromCy(cyIn, pdateOut);
7365 /* Date string parsing */
7366 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7367 #define DP_DATESEP 0x02 /* Date separator */
7368 #define DP_MONTH 0x04 /* Month name */
7369 #define DP_AM 0x08 /* AM */
7370 #define DP_PM 0x10 /* PM */
7372 typedef struct tagDATEPARSE
7374 DWORD dwCount; /* Number of fields found so far (maximum 6) */
7375 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
7376 DWORD dwFlags[6]; /* Flags for each field */
7377 DWORD dwValues[6]; /* Value of each field */
7378 } DATEPARSE;
7380 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7382 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7384 /* Determine if a day is valid in a given month of a given year */
7385 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
7387 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7389 if (day && month && month < 13)
7391 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
7392 return TRUE;
7394 return FALSE;
7397 /* Possible orders for 3 numbers making up a date */
7398 #define ORDER_MDY 0x01
7399 #define ORDER_YMD 0x02
7400 #define ORDER_YDM 0x04
7401 #define ORDER_DMY 0x08
7402 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7404 /* Determine a date for a particular locale, from 3 numbers */
7405 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
7406 DWORD offset, SYSTEMTIME *st)
7408 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
7410 if (!dp->dwCount)
7412 v1 = 30; /* Default to (Variant) 0 date part */
7413 v2 = 12;
7414 v3 = 1899;
7415 goto VARIANT_MakeDate_OK;
7418 v1 = dp->dwValues[offset + 0];
7419 v2 = dp->dwValues[offset + 1];
7420 if (dp->dwCount == 2)
7422 SYSTEMTIME current;
7423 GetSystemTime(&current);
7424 v3 = current.wYear;
7426 else
7427 v3 = dp->dwValues[offset + 2];
7429 TRACE("(%d,%d,%d,%d,%d)\n", v1, v2, v3, iDate, offset);
7431 /* If one number must be a month (Because a month name was given), then only
7432 * consider orders with the month in that position.
7433 * If we took the current year as 'v3', then only allow a year in that position.
7435 if (dp->dwFlags[offset + 0] & DP_MONTH)
7437 dwAllOrders = ORDER_MDY;
7439 else if (dp->dwFlags[offset + 1] & DP_MONTH)
7441 dwAllOrders = ORDER_DMY;
7442 if (dp->dwCount > 2)
7443 dwAllOrders |= ORDER_YMD;
7445 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
7447 dwAllOrders = ORDER_YDM;
7449 else
7451 dwAllOrders = ORDER_MDY|ORDER_DMY;
7452 if (dp->dwCount > 2)
7453 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
7456 VARIANT_MakeDate_Start:
7457 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders);
7459 while (dwAllOrders)
7461 DWORD dwTemp;
7463 if (dwCount == 0)
7465 /* First: Try the order given by iDate */
7466 switch (iDate)
7468 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
7469 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
7470 default: dwTry = dwAllOrders & ORDER_YMD; break;
7473 else if (dwCount == 1)
7475 /* Second: Try all the orders compatible with iDate */
7476 switch (iDate)
7478 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7479 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YDM|ORDER_MYD); break;
7480 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7483 else
7485 /* Finally: Try any remaining orders */
7486 dwTry = dwAllOrders;
7489 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount, dwTry);
7491 dwCount++;
7492 if (!dwTry)
7493 continue;
7495 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7497 if (dwTry & ORDER_MDY)
7499 if (VARIANT_IsValidMonthDay(v2,v1,v3))
7501 DATE_SWAP(v1,v2);
7502 goto VARIANT_MakeDate_OK;
7504 dwAllOrders &= ~ORDER_MDY;
7506 if (dwTry & ORDER_YMD)
7508 if (VARIANT_IsValidMonthDay(v3,v2,v1))
7510 DATE_SWAP(v1,v3);
7511 goto VARIANT_MakeDate_OK;
7513 dwAllOrders &= ~ORDER_YMD;
7515 if (dwTry & ORDER_YDM)
7517 if (VARIANT_IsValidMonthDay(v2,v3,v1))
7519 DATE_SWAP(v1,v2);
7520 DATE_SWAP(v2,v3);
7521 goto VARIANT_MakeDate_OK;
7523 dwAllOrders &= ~ORDER_YDM;
7525 if (dwTry & ORDER_DMY)
7527 if (VARIANT_IsValidMonthDay(v1,v2,v3))
7528 goto VARIANT_MakeDate_OK;
7529 dwAllOrders &= ~ORDER_DMY;
7531 if (dwTry & ORDER_MYD)
7533 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7534 if (VARIANT_IsValidMonthDay(v3,v1,v2))
7536 DATE_SWAP(v1,v3);
7537 DATE_SWAP(v2,v3);
7538 goto VARIANT_MakeDate_OK;
7540 dwAllOrders &= ~ORDER_MYD;
7544 if (dp->dwCount == 2)
7546 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7547 v3 = 1; /* 1st of the month */
7548 dwAllOrders = ORDER_YMD|ORDER_MYD;
7549 dp->dwCount = 0; /* Don't return to this code path again */
7550 dwCount = 0;
7551 goto VARIANT_MakeDate_Start;
7554 /* No valid dates were able to be constructed */
7555 return DISP_E_TYPEMISMATCH;
7557 VARIANT_MakeDate_OK:
7559 /* Check that the time part is ok */
7560 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
7561 return DISP_E_TYPEMISMATCH;
7563 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7564 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
7565 st->wHour += 12;
7566 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
7567 st->wHour = 0;
7568 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7570 st->wDay = v1;
7571 st->wMonth = v2;
7572 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7573 * be retrieved from:
7574 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7575 * But Wine doesn't have/use that key as at the time of writing.
7577 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
7578 TRACE("Returning date %d/%d/%d\n", v1, v2, st->wYear);
7579 return S_OK;
7582 /******************************************************************************
7583 * VarDateFromStr [OLEAUT32.94]
7585 * Convert a VT_BSTR to at VT_DATE.
7587 * PARAMS
7588 * strIn [I] String to convert
7589 * lcid [I] Locale identifier for the conversion
7590 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7591 * pdateOut [O] Destination for the converted value
7593 * RETURNS
7594 * Success: S_OK. pdateOut contains the converted value.
7595 * FAILURE: An HRESULT error code indicating the problem.
7597 * NOTES
7598 * Any date format that can be created using the date formats from lcid
7599 * (Either from kernel Nls functions, variant conversion or formatting) is a
7600 * valid input to this function. In addition, a few more esoteric formats are
7601 * also supported for compatibility with the native version. The date is
7602 * interpreted according to the date settings in the control panel, unless
7603 * the date is invalid in that format, in which the most compatible format
7604 * that produces a valid date will be used.
7606 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7608 static const USHORT ParseDateTokens[] =
7610 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7611 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7612 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7613 LOCALE_SMONTHNAME13,
7614 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7615 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7616 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7617 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7618 LOCALE_SABBREVMONTHNAME13,
7619 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7620 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7621 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7622 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7623 LOCALE_SABBREVDAYNAME7,
7624 LOCALE_S1159, LOCALE_S2359,
7625 LOCALE_SDATE
7627 static const BYTE ParseDateMonths[] =
7629 1,2,3,4,5,6,7,8,9,10,11,12,13,
7630 1,2,3,4,5,6,7,8,9,10,11,12,13
7632 unsigned int i;
7633 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
7634 DATEPARSE dp;
7635 DWORD dwDateSeps = 0, iDate = 0;
7636 HRESULT hRet = S_OK;
7638 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7639 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7640 return E_INVALIDARG;
7642 if (!strIn)
7643 return DISP_E_TYPEMISMATCH;
7645 *pdateOut = 0.0;
7647 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7649 memset(&dp, 0, sizeof(dp));
7651 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7652 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7653 TRACE("iDate is %d\n", iDate);
7655 /* Get the month/day/am/pm tokens for this locale */
7656 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7658 WCHAR buff[128];
7659 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7661 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7662 * GetAltMonthNames(). We should really cache these strings too.
7664 buff[0] = '\0';
7665 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
7666 tokens[i] = SysAllocString(buff);
7667 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7670 /* Parse the string into our structure */
7671 while (*strIn)
7673 if (dp.dwCount >= 6)
7674 break;
7676 if (isdigitW(*strIn))
7678 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
7679 dp.dwCount++;
7680 strIn--;
7682 else if (isalpha(*strIn))
7684 BOOL bFound = FALSE;
7686 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7688 DWORD dwLen = strlenW(tokens[i]);
7689 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
7691 if (i <= 25)
7693 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7694 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7695 dp.dwCount++;
7697 else if (i > 39 && i < 42)
7699 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7700 hRet = DISP_E_TYPEMISMATCH;
7701 else
7703 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7704 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7707 strIn += (dwLen - 1);
7708 bFound = TRUE;
7709 break;
7713 if (!bFound)
7715 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7716 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7718 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7719 if (*strIn == 'a' || *strIn == 'A')
7721 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7722 dp.dwParseFlags |= DP_AM;
7724 else
7726 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7727 dp.dwParseFlags |= DP_PM;
7729 strIn++;
7731 else
7733 TRACE("No matching token for %s\n", debugstr_w(strIn));
7734 hRet = DISP_E_TYPEMISMATCH;
7735 break;
7739 else if (*strIn == ':' || *strIn == '.')
7741 if (!dp.dwCount || !strIn[1])
7742 hRet = DISP_E_TYPEMISMATCH;
7743 else
7744 if (tokens[42][0] == *strIn)
7746 dwDateSeps++;
7747 if (dwDateSeps > 2)
7748 hRet = DISP_E_TYPEMISMATCH;
7749 else
7750 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7752 else
7753 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7755 else if (*strIn == '-' || *strIn == '/')
7757 dwDateSeps++;
7758 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7759 hRet = DISP_E_TYPEMISMATCH;
7760 else
7761 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7763 else if (*strIn == ',' || isspaceW(*strIn))
7765 if (*strIn == ',' && !strIn[1])
7766 hRet = DISP_E_TYPEMISMATCH;
7768 else
7770 hRet = DISP_E_TYPEMISMATCH;
7772 strIn++;
7775 if (!dp.dwCount || dp.dwCount > 6 ||
7776 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7777 hRet = DISP_E_TYPEMISMATCH;
7779 if (SUCCEEDED(hRet))
7781 SYSTEMTIME st;
7782 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7784 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7786 /* Figure out which numbers correspond to which fields.
7788 * This switch statement works based on the fact that native interprets any
7789 * fields that are not joined with a time separator ('.' or ':') as date
7790 * fields. Thus we construct a value from 0-32 where each set bit indicates
7791 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7792 * For valid permutations, we set dwOffset to point to the first date field
7793 * and shorten dp.dwCount by the number of time fields found. The real
7794 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7795 * each date number must represent in the context of iDate.
7797 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7799 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7801 case 0x1: /* TT TTDD TTDDD */
7802 if (dp.dwCount > 3 &&
7803 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7804 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7805 hRet = DISP_E_TYPEMISMATCH;
7806 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7807 hRet = DISP_E_TYPEMISMATCH;
7808 st.wHour = dp.dwValues[0];
7809 st.wMinute = dp.dwValues[1];
7810 dp.dwCount -= 2;
7811 dwOffset = 2;
7812 break;
7814 case 0x3: /* TTT TTTDD TTTDDD */
7815 if (dp.dwCount > 4 &&
7816 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7817 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7818 hRet = DISP_E_TYPEMISMATCH;
7819 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7820 hRet = DISP_E_TYPEMISMATCH;
7821 st.wHour = dp.dwValues[0];
7822 st.wMinute = dp.dwValues[1];
7823 st.wSecond = dp.dwValues[2];
7824 dwOffset = 3;
7825 dp.dwCount -= 3;
7826 break;
7828 case 0x4: /* DDTT */
7829 if (dp.dwCount != 4 ||
7830 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7831 hRet = DISP_E_TYPEMISMATCH;
7833 st.wHour = dp.dwValues[2];
7834 st.wMinute = dp.dwValues[3];
7835 dp.dwCount -= 2;
7836 break;
7838 case 0x0: /* T DD DDD TDDD TDDD */
7839 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7841 st.wHour = dp.dwValues[0]; /* T */
7842 dp.dwCount = 0;
7843 break;
7845 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7847 hRet = DISP_E_TYPEMISMATCH;
7849 else if (dp.dwCount == 3)
7851 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7853 dp.dwCount = 2;
7854 st.wHour = dp.dwValues[0];
7855 dwOffset = 1;
7856 break;
7858 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7860 dp.dwCount = 2;
7861 st.wHour = dp.dwValues[2];
7862 break;
7864 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7865 hRet = DISP_E_TYPEMISMATCH;
7867 else if (dp.dwCount == 4)
7869 dp.dwCount = 3;
7870 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7872 st.wHour = dp.dwValues[0];
7873 dwOffset = 1;
7875 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7877 st.wHour = dp.dwValues[3];
7879 else
7880 hRet = DISP_E_TYPEMISMATCH;
7881 break;
7883 /* .. fall through .. */
7885 case 0x8: /* DDDTT */
7886 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7887 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7888 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7889 dp.dwCount == 4 || dp.dwCount == 6)
7890 hRet = DISP_E_TYPEMISMATCH;
7891 st.wHour = dp.dwValues[3];
7892 st.wMinute = dp.dwValues[4];
7893 if (dp.dwCount == 5)
7894 dp.dwCount -= 2;
7895 break;
7897 case 0xC: /* DDTTT */
7898 if (dp.dwCount != 5 ||
7899 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7900 hRet = DISP_E_TYPEMISMATCH;
7901 st.wHour = dp.dwValues[2];
7902 st.wMinute = dp.dwValues[3];
7903 st.wSecond = dp.dwValues[4];
7904 dp.dwCount -= 3;
7905 break;
7907 case 0x18: /* DDDTTT */
7908 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7909 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7910 hRet = DISP_E_TYPEMISMATCH;
7911 st.wHour = dp.dwValues[3];
7912 st.wMinute = dp.dwValues[4];
7913 st.wSecond = dp.dwValues[5];
7914 dp.dwCount -= 3;
7915 break;
7917 default:
7918 hRet = DISP_E_TYPEMISMATCH;
7919 break;
7922 if (SUCCEEDED(hRet))
7924 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7926 if (dwFlags & VAR_TIMEVALUEONLY)
7928 st.wYear = 1899;
7929 st.wMonth = 12;
7930 st.wDay = 30;
7932 else if (dwFlags & VAR_DATEVALUEONLY)
7933 st.wHour = st.wMinute = st.wSecond = 0;
7935 /* Finally, convert the value to a VT_DATE */
7936 if (SUCCEEDED(hRet))
7937 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7941 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7942 SysFreeString(tokens[i]);
7943 return hRet;
7946 /******************************************************************************
7947 * VarDateFromI1 (OLEAUT32.221)
7949 * Convert a VT_I1 to a VT_DATE.
7951 * PARAMS
7952 * cIn [I] Source
7953 * pdateOut [O] Destination
7955 * RETURNS
7956 * S_OK.
7958 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7960 return VarR8FromI1(cIn, pdateOut);
7963 /******************************************************************************
7964 * VarDateFromUI2 (OLEAUT32.222)
7966 * Convert a VT_UI2 to a VT_DATE.
7968 * PARAMS
7969 * uiIn [I] Source
7970 * pdateOut [O] Destination
7972 * RETURNS
7973 * S_OK.
7975 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7977 return VarR8FromUI2(uiIn, pdateOut);
7980 /******************************************************************************
7981 * VarDateFromUI4 (OLEAUT32.223)
7983 * Convert a VT_UI4 to a VT_DATE.
7985 * PARAMS
7986 * ulIn [I] Source
7987 * pdateOut [O] Destination
7989 * RETURNS
7990 * S_OK.
7992 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7994 return VarDateFromR8(ulIn, pdateOut);
7997 /**********************************************************************
7998 * VarDateFromDec (OLEAUT32.224)
8000 * Convert a VT_DECIMAL to a VT_DATE.
8002 * PARAMS
8003 * pdecIn [I] Source
8004 * pdateOut [O] Destination
8006 * RETURNS
8007 * S_OK.
8009 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
8011 return VarR8FromDec(pdecIn, pdateOut);
8014 /******************************************************************************
8015 * VarDateFromI8 (OLEAUT32.364)
8017 * Convert a VT_I8 to a VT_DATE.
8019 * PARAMS
8020 * llIn [I] Source
8021 * pdateOut [O] Destination
8023 * RETURNS
8024 * Success: S_OK.
8025 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8027 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
8029 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
8030 *pdateOut = (DATE)llIn;
8031 return S_OK;
8034 /******************************************************************************
8035 * VarDateFromUI8 (OLEAUT32.365)
8037 * Convert a VT_UI8 to a VT_DATE.
8039 * PARAMS
8040 * ullIn [I] Source
8041 * pdateOut [O] Destination
8043 * RETURNS
8044 * Success: S_OK.
8045 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8047 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
8049 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
8050 *pdateOut = (DATE)ullIn;
8051 return S_OK;