mshtml: Use proper BINF flags for form submit.
[wine.git] / dlls / oleaut32 / vartype.c
blobe1672a1dd35742ccf9288ba481217ec9f31f1179
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 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
126 &emptyParams, &srcVar, NULL, NULL);
128 if (SUCCEEDED(hRet))
130 /* Convert the property to the requested type */
131 V_VT(&dstVar) = VT_EMPTY;
132 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt);
133 VariantClear(&srcVar);
135 if (SUCCEEDED(hRet))
137 VARIANT_CopyData(&dstVar, vt, pOut);
138 VariantClear(&srcVar);
141 else
142 hRet = DISP_E_TYPEMISMATCH;
143 return hRet;
146 /* Inline return type */
147 #define RETTYP static inline HRESULT
150 /* Simple compiler cast from one type to another */
151 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
152 *out = in; return S_OK; }
154 /* Compiler cast where input cannot be negative */
155 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
156 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
158 /* Compiler cast where input cannot be > some number */
159 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
160 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
162 /* Compiler cast where input cannot be < some number or >= some other number */
163 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
164 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
166 /* I1 */
167 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX)
168 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX)
169 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX)
170 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool)
171 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX)
172 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX)
173 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX)
174 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX)
176 /* UI1 */
177 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX)
178 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool)
179 NEGTST(BYTE, signed char, VarUI1FromI1)
180 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX)
181 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX)
182 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX)
183 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX)
184 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX)
186 /* I2 */
187 SIMPLE(SHORT, BYTE, VarI2FromUI1)
188 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX)
189 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool)
190 SIMPLE(SHORT, signed char, VarI2FromI1)
191 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX)
192 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX)
193 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX)
194 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX)
196 /* UI2 */
197 SIMPLE(USHORT, BYTE, VarUI2FromUI1)
198 NEGTST(USHORT, SHORT, VarUI2FromI2)
199 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX)
200 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool)
201 NEGTST(USHORT, signed char, VarUI2FromI1)
202 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX)
203 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX)
204 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX)
206 /* I4 */
207 SIMPLE(LONG, BYTE, VarI4FromUI1)
208 SIMPLE(LONG, SHORT, VarI4FromI2)
209 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool)
210 SIMPLE(LONG, signed char, VarI4FromI1)
211 SIMPLE(LONG, USHORT, VarI4FromUI2)
212 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX)
213 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX)
214 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX)
216 /* UI4 */
217 SIMPLE(ULONG, BYTE, VarUI4FromUI1)
218 NEGTST(ULONG, SHORT, VarUI4FromI2)
219 NEGTST(ULONG, LONG, VarUI4FromI4)
220 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool)
221 NEGTST(ULONG, signed char, VarUI4FromI1)
222 SIMPLE(ULONG, USHORT, VarUI4FromUI2)
223 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX)
224 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX)
226 /* I8 */
227 SIMPLE(LONG64, BYTE, VarI8FromUI1)
228 SIMPLE(LONG64, SHORT, VarI8FromI2)
229 SIMPLE(LONG64, signed char, VarI8FromI1)
230 SIMPLE(LONG64, USHORT, VarI8FromUI2)
231 SIMPLE(LONG64, ULONG, VarI8FromUI4)
232 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX)
234 /* UI8 */
235 SIMPLE(ULONG64, BYTE, VarUI8FromUI1)
236 NEGTST(ULONG64, SHORT, VarUI8FromI2)
237 NEGTST(ULONG64, signed char, VarUI8FromI1)
238 SIMPLE(ULONG64, USHORT, VarUI8FromUI2)
239 SIMPLE(ULONG64, ULONG, VarUI8FromUI4)
240 NEGTST(ULONG64, LONG64, VarUI8FromI8)
242 /* R4 (float) */
243 SIMPLE(float, BYTE, VarR4FromUI1)
244 SIMPLE(float, SHORT, VarR4FromI2)
245 SIMPLE(float, signed char, VarR4FromI1)
246 SIMPLE(float, USHORT, VarR4FromUI2)
247 SIMPLE(float, LONG, VarR4FromI4)
248 SIMPLE(float, ULONG, VarR4FromUI4)
249 SIMPLE(float, LONG64, VarR4FromI8)
250 SIMPLE(float, ULONG64, VarR4FromUI8)
252 /* R8 (double) */
253 SIMPLE(double, BYTE, VarR8FromUI1)
254 SIMPLE(double, SHORT, VarR8FromI2)
255 SIMPLE(double, float, VarR8FromR4)
256 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
257 SIMPLE(double, DATE, VarR8FromDate)
258 SIMPLE(double, signed char, VarR8FromI1)
259 SIMPLE(double, USHORT, VarR8FromUI2)
260 SIMPLE(double, LONG, VarR8FromI4)
261 SIMPLE(double, ULONG, VarR8FromUI4)
262 SIMPLE(double, LONG64, VarR8FromI8)
263 SIMPLE(double, ULONG64, VarR8FromUI8)
266 /* I1
269 /************************************************************************
270 * VarI1FromUI1 (OLEAUT32.244)
272 * Convert a VT_UI1 to a VT_I1.
274 * PARAMS
275 * bIn [I] Source
276 * pcOut [O] Destination
278 * RETURNS
279 * Success: S_OK.
280 * Failure: E_INVALIDARG, if the source value is invalid
281 * DISP_E_OVERFLOW, if the value will not fit in the destination
283 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
285 return _VarI1FromUI1(bIn, pcOut);
288 /************************************************************************
289 * VarI1FromI2 (OLEAUT32.245)
291 * Convert a VT_I2 to a VT_I1.
293 * PARAMS
294 * sIn [I] Source
295 * pcOut [O] Destination
297 * RETURNS
298 * Success: S_OK.
299 * Failure: E_INVALIDARG, if the source value is invalid
300 * DISP_E_OVERFLOW, if the value will not fit in the destination
302 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
304 return _VarI1FromI2(sIn, pcOut);
307 /************************************************************************
308 * VarI1FromI4 (OLEAUT32.246)
310 * Convert a VT_I4 to a VT_I1.
312 * PARAMS
313 * iIn [I] Source
314 * pcOut [O] Destination
316 * RETURNS
317 * Success: S_OK.
318 * Failure: E_INVALIDARG, if the source value is invalid
319 * DISP_E_OVERFLOW, if the value will not fit in the destination
321 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
323 return _VarI1FromI4(iIn, pcOut);
326 /************************************************************************
327 * VarI1FromR4 (OLEAUT32.247)
329 * Convert a VT_R4 to a VT_I1.
331 * PARAMS
332 * fltIn [I] Source
333 * pcOut [O] Destination
335 * RETURNS
336 * Success: S_OK.
337 * Failure: E_INVALIDARG, if the source value is invalid
338 * DISP_E_OVERFLOW, if the value will not fit in the destination
340 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
342 return VarI1FromR8(fltIn, pcOut);
345 /************************************************************************
346 * VarI1FromR8 (OLEAUT32.248)
348 * Convert a VT_R8 to a VT_I1.
350 * PARAMS
351 * dblIn [I] Source
352 * pcOut [O] Destination
354 * RETURNS
355 * Success: S_OK.
356 * Failure: E_INVALIDARG, if the source value is invalid
357 * DISP_E_OVERFLOW, if the value will not fit in the destination
359 * NOTES
360 * See VarI8FromR8() for details concerning rounding.
362 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
364 if (dblIn < (double)I1_MIN || dblIn > (double)I1_MAX)
365 return DISP_E_OVERFLOW;
366 VARIANT_DutchRound(CHAR, dblIn, *pcOut);
367 return S_OK;
370 /************************************************************************
371 * VarI1FromDate (OLEAUT32.249)
373 * Convert a VT_DATE to a VT_I1.
375 * PARAMS
376 * dateIn [I] Source
377 * pcOut [O] Destination
379 * RETURNS
380 * Success: S_OK.
381 * Failure: E_INVALIDARG, if the source value is invalid
382 * DISP_E_OVERFLOW, if the value will not fit in the destination
384 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
386 return VarI1FromR8(dateIn, pcOut);
389 /************************************************************************
390 * VarI1FromCy (OLEAUT32.250)
392 * Convert a VT_CY to a VT_I1.
394 * PARAMS
395 * cyIn [I] Source
396 * pcOut [O] Destination
398 * RETURNS
399 * Success: S_OK.
400 * Failure: E_INVALIDARG, if the source value is invalid
401 * DISP_E_OVERFLOW, if the value will not fit in the destination
403 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
405 LONG i = I1_MAX + 1;
407 VarI4FromCy(cyIn, &i);
408 return _VarI1FromI4(i, pcOut);
411 /************************************************************************
412 * VarI1FromStr (OLEAUT32.251)
414 * Convert a VT_BSTR to a VT_I1.
416 * PARAMS
417 * strIn [I] Source
418 * lcid [I] LCID for the conversion
419 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
420 * pcOut [O] Destination
422 * RETURNS
423 * Success: S_OK.
424 * Failure: E_INVALIDARG, if the source value is invalid
425 * DISP_E_OVERFLOW, if the value will not fit in the destination
426 * DISP_E_TYPEMISMATCH, if the type cannot be converted
428 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
430 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
433 /************************************************************************
434 * VarI1FromDisp (OLEAUT32.252)
436 * Convert a VT_DISPATCH to a VT_I1.
438 * PARAMS
439 * pdispIn [I] Source
440 * lcid [I] LCID for conversion
441 * pcOut [O] Destination
443 * RETURNS
444 * Success: S_OK.
445 * Failure: E_INVALIDARG, if the source value is invalid
446 * DISP_E_OVERFLOW, if the value will not fit in the destination
447 * DISP_E_TYPEMISMATCH, if the type cannot be converted
449 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
451 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0);
454 /************************************************************************
455 * VarI1FromBool (OLEAUT32.253)
457 * Convert a VT_BOOL to a VT_I1.
459 * PARAMS
460 * boolIn [I] Source
461 * pcOut [O] Destination
463 * RETURNS
464 * S_OK.
466 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
468 return _VarI1FromBool(boolIn, pcOut);
471 /************************************************************************
472 * VarI1FromUI2 (OLEAUT32.254)
474 * Convert a VT_UI2 to a VT_I1.
476 * PARAMS
477 * usIn [I] Source
478 * pcOut [O] Destination
480 * RETURNS
481 * Success: S_OK.
482 * Failure: E_INVALIDARG, if the source value is invalid
483 * DISP_E_OVERFLOW, if the value will not fit in the destination
485 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
487 return _VarI1FromUI2(usIn, pcOut);
490 /************************************************************************
491 * VarI1FromUI4 (OLEAUT32.255)
493 * Convert a VT_UI4 to a VT_I1.
495 * PARAMS
496 * ulIn [I] Source
497 * pcOut [O] Destination
499 * RETURNS
500 * Success: S_OK.
501 * Failure: E_INVALIDARG, if the source value is invalid
502 * DISP_E_OVERFLOW, if the value will not fit in the destination
503 * DISP_E_TYPEMISMATCH, if the type cannot be converted
505 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
507 return _VarI1FromUI4(ulIn, pcOut);
510 /************************************************************************
511 * VarI1FromDec (OLEAUT32.256)
513 * Convert a VT_DECIMAL to a VT_I1.
515 * PARAMS
516 * pDecIn [I] Source
517 * pcOut [O] Destination
519 * RETURNS
520 * Success: S_OK.
521 * Failure: E_INVALIDARG, if the source value is invalid
522 * DISP_E_OVERFLOW, if the value will not fit in the destination
524 HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut)
526 LONG64 i64;
527 HRESULT hRet;
529 hRet = VarI8FromDec(pdecIn, &i64);
531 if (SUCCEEDED(hRet))
532 hRet = _VarI1FromI8(i64, pcOut);
533 return hRet;
536 /************************************************************************
537 * VarI1FromI8 (OLEAUT32.376)
539 * Convert a VT_I8 to a VT_I1.
541 * PARAMS
542 * llIn [I] Source
543 * pcOut [O] Destination
545 * RETURNS
546 * Success: S_OK.
547 * Failure: E_INVALIDARG, if the source value is invalid
548 * DISP_E_OVERFLOW, if the value will not fit in the destination
550 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
552 return _VarI1FromI8(llIn, pcOut);
555 /************************************************************************
556 * VarI1FromUI8 (OLEAUT32.377)
558 * Convert a VT_UI8 to a VT_I1.
560 * PARAMS
561 * ullIn [I] Source
562 * pcOut [O] Destination
564 * RETURNS
565 * Success: S_OK.
566 * Failure: E_INVALIDARG, if the source value is invalid
567 * DISP_E_OVERFLOW, if the value will not fit in the destination
569 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
571 return _VarI1FromUI8(ullIn, pcOut);
574 /* UI1
577 /************************************************************************
578 * VarUI1FromI2 (OLEAUT32.130)
580 * Convert a VT_I2 to a VT_UI1.
582 * PARAMS
583 * sIn [I] Source
584 * pbOut [O] Destination
586 * RETURNS
587 * Success: S_OK.
588 * Failure: E_INVALIDARG, if the source value is invalid
589 * DISP_E_OVERFLOW, if the value will not fit in the destination
591 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
593 return _VarUI1FromI2(sIn, pbOut);
596 /************************************************************************
597 * VarUI1FromI4 (OLEAUT32.131)
599 * Convert a VT_I4 to a VT_UI1.
601 * PARAMS
602 * iIn [I] Source
603 * pbOut [O] Destination
605 * RETURNS
606 * Success: S_OK.
607 * Failure: E_INVALIDARG, if the source value is invalid
608 * DISP_E_OVERFLOW, if the value will not fit in the destination
610 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
612 return _VarUI1FromI4(iIn, pbOut);
615 /************************************************************************
616 * VarUI1FromR4 (OLEAUT32.132)
618 * Convert a VT_R4 to a VT_UI1.
620 * PARAMS
621 * fltIn [I] Source
622 * pbOut [O] Destination
624 * RETURNS
625 * Success: S_OK.
626 * Failure: E_INVALIDARG, if the source value is invalid
627 * DISP_E_OVERFLOW, if the value will not fit in the destination
628 * DISP_E_TYPEMISMATCH, if the type cannot be converted
630 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
632 return VarUI1FromR8(fltIn, pbOut);
635 /************************************************************************
636 * VarUI1FromR8 (OLEAUT32.133)
638 * Convert a VT_R8 to a VT_UI1.
640 * PARAMS
641 * dblIn [I] Source
642 * pbOut [O] Destination
644 * RETURNS
645 * Success: S_OK.
646 * Failure: E_INVALIDARG, if the source value is invalid
647 * DISP_E_OVERFLOW, if the value will not fit in the destination
649 * NOTES
650 * See VarI8FromR8() for details concerning rounding.
652 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
654 if (dblIn < -0.5 || dblIn > (double)UI1_MAX)
655 return DISP_E_OVERFLOW;
656 VARIANT_DutchRound(BYTE, dblIn, *pbOut);
657 return S_OK;
660 /************************************************************************
661 * VarUI1FromCy (OLEAUT32.134)
663 * Convert a VT_CY to a VT_UI1.
665 * PARAMS
666 * cyIn [I] Source
667 * pbOut [O] Destination
669 * RETURNS
670 * Success: S_OK.
671 * Failure: E_INVALIDARG, if the source value is invalid
672 * DISP_E_OVERFLOW, if the value will not fit in the destination
674 * NOTES
675 * Negative values >= -5000 will be converted to 0.
677 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
679 ULONG i = UI1_MAX + 1;
681 VarUI4FromCy(cyIn, &i);
682 return _VarUI1FromUI4(i, pbOut);
685 /************************************************************************
686 * VarUI1FromDate (OLEAUT32.135)
688 * Convert a VT_DATE to a VT_UI1.
690 * PARAMS
691 * dateIn [I] Source
692 * pbOut [O] Destination
694 * RETURNS
695 * Success: S_OK.
696 * Failure: E_INVALIDARG, if the source value is invalid
697 * DISP_E_OVERFLOW, if the value will not fit in the destination
699 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
701 return VarUI1FromR8(dateIn, pbOut);
704 /************************************************************************
705 * VarUI1FromStr (OLEAUT32.136)
707 * Convert a VT_BSTR to a VT_UI1.
709 * PARAMS
710 * strIn [I] Source
711 * lcid [I] LCID for the conversion
712 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
713 * pbOut [O] Destination
715 * RETURNS
716 * Success: S_OK.
717 * Failure: E_INVALIDARG, if the source value is invalid
718 * DISP_E_OVERFLOW, if the value will not fit in the destination
719 * DISP_E_TYPEMISMATCH, if the type cannot be converted
721 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
723 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
726 /************************************************************************
727 * VarUI1FromDisp (OLEAUT32.137)
729 * Convert a VT_DISPATCH to a VT_UI1.
731 * PARAMS
732 * pdispIn [I] Source
733 * lcid [I] LCID for conversion
734 * pbOut [O] Destination
736 * RETURNS
737 * Success: S_OK.
738 * Failure: E_INVALIDARG, if the source value is invalid
739 * DISP_E_OVERFLOW, if the value will not fit in the destination
740 * DISP_E_TYPEMISMATCH, if the type cannot be converted
742 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
744 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0);
747 /************************************************************************
748 * VarUI1FromBool (OLEAUT32.138)
750 * Convert a VT_BOOL to a VT_UI1.
752 * PARAMS
753 * boolIn [I] Source
754 * pbOut [O] Destination
756 * RETURNS
757 * S_OK.
759 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
761 return _VarUI1FromBool(boolIn, pbOut);
764 /************************************************************************
765 * VarUI1FromI1 (OLEAUT32.237)
767 * Convert a VT_I1 to a VT_UI1.
769 * PARAMS
770 * cIn [I] Source
771 * pbOut [O] Destination
773 * RETURNS
774 * Success: S_OK.
775 * Failure: E_INVALIDARG, if the source value is invalid
776 * DISP_E_OVERFLOW, if the value will not fit in the destination
778 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
780 return _VarUI1FromI1(cIn, pbOut);
783 /************************************************************************
784 * VarUI1FromUI2 (OLEAUT32.238)
786 * Convert a VT_UI2 to a VT_UI1.
788 * PARAMS
789 * usIn [I] Source
790 * pbOut [O] Destination
792 * RETURNS
793 * Success: S_OK.
794 * Failure: E_INVALIDARG, if the source value is invalid
795 * DISP_E_OVERFLOW, if the value will not fit in the destination
797 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
799 return _VarUI1FromUI2(usIn, pbOut);
802 /************************************************************************
803 * VarUI1FromUI4 (OLEAUT32.239)
805 * Convert a VT_UI4 to a VT_UI1.
807 * PARAMS
808 * ulIn [I] Source
809 * pbOut [O] Destination
811 * RETURNS
812 * Success: S_OK.
813 * Failure: E_INVALIDARG, if the source value is invalid
814 * DISP_E_OVERFLOW, if the value will not fit in the destination
816 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
818 return _VarUI1FromUI4(ulIn, pbOut);
821 /************************************************************************
822 * VarUI1FromDec (OLEAUT32.240)
824 * Convert a VT_DECIMAL to a VT_UI1.
826 * PARAMS
827 * pDecIn [I] Source
828 * pbOut [O] Destination
830 * RETURNS
831 * Success: S_OK.
832 * Failure: E_INVALIDARG, if the source value is invalid
833 * DISP_E_OVERFLOW, if the value will not fit in the destination
835 HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut)
837 LONG64 i64;
838 HRESULT hRet;
840 hRet = VarI8FromDec(pdecIn, &i64);
842 if (SUCCEEDED(hRet))
843 hRet = _VarUI1FromI8(i64, pbOut);
844 return hRet;
847 /************************************************************************
848 * VarUI1FromI8 (OLEAUT32.372)
850 * Convert a VT_I8 to a VT_UI1.
852 * PARAMS
853 * llIn [I] Source
854 * pbOut [O] Destination
856 * RETURNS
857 * Success: S_OK.
858 * Failure: E_INVALIDARG, if the source value is invalid
859 * DISP_E_OVERFLOW, if the value will not fit in the destination
861 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
863 return _VarUI1FromI8(llIn, pbOut);
866 /************************************************************************
867 * VarUI1FromUI8 (OLEAUT32.373)
869 * Convert a VT_UI8 to a VT_UI1.
871 * PARAMS
872 * ullIn [I] Source
873 * pbOut [O] Destination
875 * RETURNS
876 * Success: S_OK.
877 * Failure: E_INVALIDARG, if the source value is invalid
878 * DISP_E_OVERFLOW, if the value will not fit in the destination
880 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
882 return _VarUI1FromUI8(ullIn, pbOut);
886 /* I2
889 /************************************************************************
890 * VarI2FromUI1 (OLEAUT32.48)
892 * Convert a VT_UI2 to a VT_I2.
894 * PARAMS
895 * bIn [I] Source
896 * psOut [O] Destination
898 * RETURNS
899 * S_OK.
901 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
903 return _VarI2FromUI1(bIn, psOut);
906 /************************************************************************
907 * VarI2FromI4 (OLEAUT32.49)
909 * Convert a VT_I4 to a VT_I2.
911 * PARAMS
912 * iIn [I] Source
913 * psOut [O] Destination
915 * RETURNS
916 * Success: S_OK.
917 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
919 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
921 return _VarI2FromI4(iIn, psOut);
924 /************************************************************************
925 * VarI2FromR4 (OLEAUT32.50)
927 * Convert a VT_R4 to a VT_I2.
929 * PARAMS
930 * fltIn [I] Source
931 * psOut [O] Destination
933 * RETURNS
934 * Success: S_OK.
935 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
937 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
939 return VarI2FromR8(fltIn, psOut);
942 /************************************************************************
943 * VarI2FromR8 (OLEAUT32.51)
945 * Convert a VT_R8 to a VT_I2.
947 * PARAMS
948 * dblIn [I] Source
949 * psOut [O] Destination
951 * RETURNS
952 * Success: S_OK.
953 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
955 * NOTES
956 * See VarI8FromR8() for details concerning rounding.
958 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
960 if (dblIn < (double)I2_MIN || dblIn > (double)I2_MAX)
961 return DISP_E_OVERFLOW;
962 VARIANT_DutchRound(SHORT, dblIn, *psOut);
963 return S_OK;
966 /************************************************************************
967 * VarI2FromCy (OLEAUT32.52)
969 * Convert a VT_CY to a VT_I2.
971 * PARAMS
972 * cyIn [I] Source
973 * psOut [O] Destination
975 * RETURNS
976 * Success: S_OK.
977 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
979 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
981 LONG i = I2_MAX + 1;
983 VarI4FromCy(cyIn, &i);
984 return _VarI2FromI4(i, psOut);
987 /************************************************************************
988 * VarI2FromDate (OLEAUT32.53)
990 * Convert a VT_DATE to a VT_I2.
992 * PARAMS
993 * dateIn [I] Source
994 * psOut [O] Destination
996 * RETURNS
997 * Success: S_OK.
998 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1000 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
1002 return VarI2FromR8(dateIn, psOut);
1005 /************************************************************************
1006 * VarI2FromStr (OLEAUT32.54)
1008 * Convert a VT_BSTR to a VT_I2.
1010 * PARAMS
1011 * strIn [I] Source
1012 * lcid [I] LCID for the conversion
1013 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1014 * psOut [O] Destination
1016 * RETURNS
1017 * Success: S_OK.
1018 * Failure: E_INVALIDARG, if any parameter is invalid
1019 * DISP_E_OVERFLOW, if the value will not fit in the destination
1020 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1022 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
1024 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
1027 /************************************************************************
1028 * VarI2FromDisp (OLEAUT32.55)
1030 * Convert a VT_DISPATCH to a VT_I2.
1032 * PARAMS
1033 * pdispIn [I] Source
1034 * lcid [I] LCID for conversion
1035 * psOut [O] Destination
1037 * RETURNS
1038 * Success: S_OK.
1039 * Failure: E_INVALIDARG, if pdispIn is invalid,
1040 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1041 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1043 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
1045 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0);
1048 /************************************************************************
1049 * VarI2FromBool (OLEAUT32.56)
1051 * Convert a VT_BOOL to a VT_I2.
1053 * PARAMS
1054 * boolIn [I] Source
1055 * psOut [O] Destination
1057 * RETURNS
1058 * S_OK.
1060 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
1062 return _VarI2FromBool(boolIn, psOut);
1065 /************************************************************************
1066 * VarI2FromI1 (OLEAUT32.205)
1068 * Convert a VT_I1 to a VT_I2.
1070 * PARAMS
1071 * cIn [I] Source
1072 * psOut [O] Destination
1074 * RETURNS
1075 * S_OK.
1077 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
1079 return _VarI2FromI1(cIn, psOut);
1082 /************************************************************************
1083 * VarI2FromUI2 (OLEAUT32.206)
1085 * Convert a VT_UI2 to a VT_I2.
1087 * PARAMS
1088 * usIn [I] Source
1089 * psOut [O] Destination
1091 * RETURNS
1092 * Success: S_OK.
1093 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1095 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
1097 return _VarI2FromUI2(usIn, psOut);
1100 /************************************************************************
1101 * VarI2FromUI4 (OLEAUT32.207)
1103 * Convert a VT_UI4 to a VT_I2.
1105 * PARAMS
1106 * ulIn [I] Source
1107 * psOut [O] Destination
1109 * RETURNS
1110 * Success: S_OK.
1111 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1113 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
1115 return _VarI2FromUI4(ulIn, psOut);
1118 /************************************************************************
1119 * VarI2FromDec (OLEAUT32.208)
1121 * Convert a VT_DECIMAL to a VT_I2.
1123 * PARAMS
1124 * pDecIn [I] Source
1125 * psOut [O] Destination
1127 * RETURNS
1128 * Success: S_OK.
1129 * Failure: E_INVALIDARG, if the source value is invalid
1130 * DISP_E_OVERFLOW, if the value will not fit in the destination
1132 HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut)
1134 LONG64 i64;
1135 HRESULT hRet;
1137 hRet = VarI8FromDec(pdecIn, &i64);
1139 if (SUCCEEDED(hRet))
1140 hRet = _VarI2FromI8(i64, psOut);
1141 return hRet;
1144 /************************************************************************
1145 * VarI2FromI8 (OLEAUT32.346)
1147 * Convert a VT_I8 to a VT_I2.
1149 * PARAMS
1150 * llIn [I] Source
1151 * psOut [O] Destination
1153 * RETURNS
1154 * Success: S_OK.
1155 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1157 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
1159 return _VarI2FromI8(llIn, psOut);
1162 /************************************************************************
1163 * VarI2FromUI8 (OLEAUT32.347)
1165 * Convert a VT_UI8 to a VT_I2.
1167 * PARAMS
1168 * ullIn [I] Source
1169 * psOut [O] Destination
1171 * RETURNS
1172 * Success: S_OK.
1173 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1175 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
1177 return _VarI2FromUI8(ullIn, psOut);
1180 /* UI2
1183 /************************************************************************
1184 * VarUI2FromUI1 (OLEAUT32.257)
1186 * Convert a VT_UI1 to a VT_UI2.
1188 * PARAMS
1189 * bIn [I] Source
1190 * pusOut [O] Destination
1192 * RETURNS
1193 * S_OK.
1195 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
1197 return _VarUI2FromUI1(bIn, pusOut);
1200 /************************************************************************
1201 * VarUI2FromI2 (OLEAUT32.258)
1203 * Convert a VT_I2 to a VT_UI2.
1205 * PARAMS
1206 * sIn [I] Source
1207 * pusOut [O] Destination
1209 * RETURNS
1210 * Success: S_OK.
1211 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1213 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
1215 return _VarUI2FromI2(sIn, pusOut);
1218 /************************************************************************
1219 * VarUI2FromI4 (OLEAUT32.259)
1221 * Convert a VT_I4 to a VT_UI2.
1223 * PARAMS
1224 * iIn [I] Source
1225 * pusOut [O] Destination
1227 * RETURNS
1228 * Success: S_OK.
1229 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1231 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
1233 return _VarUI2FromI4(iIn, pusOut);
1236 /************************************************************************
1237 * VarUI2FromR4 (OLEAUT32.260)
1239 * Convert a VT_R4 to a VT_UI2.
1241 * PARAMS
1242 * fltIn [I] Source
1243 * pusOut [O] Destination
1245 * RETURNS
1246 * Success: S_OK.
1247 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1249 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
1251 return VarUI2FromR8(fltIn, pusOut);
1254 /************************************************************************
1255 * VarUI2FromR8 (OLEAUT32.261)
1257 * Convert a VT_R8 to a VT_UI2.
1259 * PARAMS
1260 * dblIn [I] Source
1261 * pusOut [O] Destination
1263 * RETURNS
1264 * Success: S_OK.
1265 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1267 * NOTES
1268 * See VarI8FromR8() for details concerning rounding.
1270 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
1272 if (dblIn < -0.5 || dblIn > (double)UI2_MAX)
1273 return DISP_E_OVERFLOW;
1274 VARIANT_DutchRound(USHORT, dblIn, *pusOut);
1275 return S_OK;
1278 /************************************************************************
1279 * VarUI2FromDate (OLEAUT32.262)
1281 * Convert a VT_DATE to a VT_UI2.
1283 * PARAMS
1284 * dateIn [I] Source
1285 * pusOut [O] Destination
1287 * RETURNS
1288 * Success: S_OK.
1289 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1291 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
1293 return VarUI2FromR8(dateIn, pusOut);
1296 /************************************************************************
1297 * VarUI2FromCy (OLEAUT32.263)
1299 * Convert a VT_CY to a VT_UI2.
1301 * PARAMS
1302 * cyIn [I] Source
1303 * pusOut [O] Destination
1305 * RETURNS
1306 * Success: S_OK.
1307 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1309 * NOTES
1310 * Negative values >= -5000 will be converted to 0.
1312 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
1314 ULONG i = UI2_MAX + 1;
1316 VarUI4FromCy(cyIn, &i);
1317 return _VarUI2FromUI4(i, pusOut);
1320 /************************************************************************
1321 * VarUI2FromStr (OLEAUT32.264)
1323 * Convert a VT_BSTR to a VT_UI2.
1325 * PARAMS
1326 * strIn [I] Source
1327 * lcid [I] LCID for the conversion
1328 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1329 * pusOut [O] Destination
1331 * RETURNS
1332 * Success: S_OK.
1333 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1334 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1336 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
1338 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
1341 /************************************************************************
1342 * VarUI2FromDisp (OLEAUT32.265)
1344 * Convert a VT_DISPATCH to a VT_UI2.
1346 * PARAMS
1347 * pdispIn [I] Source
1348 * lcid [I] LCID for conversion
1349 * pusOut [O] Destination
1351 * RETURNS
1352 * Success: S_OK.
1353 * Failure: E_INVALIDARG, if the source value is invalid
1354 * DISP_E_OVERFLOW, if the value will not fit in the destination
1355 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1357 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
1359 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0);
1362 /************************************************************************
1363 * VarUI2FromBool (OLEAUT32.266)
1365 * Convert a VT_BOOL to a VT_UI2.
1367 * PARAMS
1368 * boolIn [I] Source
1369 * pusOut [O] Destination
1371 * RETURNS
1372 * S_OK.
1374 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
1376 return _VarUI2FromBool(boolIn, pusOut);
1379 /************************************************************************
1380 * VarUI2FromI1 (OLEAUT32.267)
1382 * Convert a VT_I1 to a VT_UI2.
1384 * PARAMS
1385 * cIn [I] Source
1386 * pusOut [O] Destination
1388 * RETURNS
1389 * Success: S_OK.
1390 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1392 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
1394 return _VarUI2FromI1(cIn, pusOut);
1397 /************************************************************************
1398 * VarUI2FromUI4 (OLEAUT32.268)
1400 * Convert a VT_UI4 to a VT_UI2.
1402 * PARAMS
1403 * ulIn [I] Source
1404 * pusOut [O] Destination
1406 * RETURNS
1407 * Success: S_OK.
1408 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1410 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
1412 return _VarUI2FromUI4(ulIn, pusOut);
1415 /************************************************************************
1416 * VarUI2FromDec (OLEAUT32.269)
1418 * Convert a VT_DECIMAL to a VT_UI2.
1420 * PARAMS
1421 * pDecIn [I] Source
1422 * pusOut [O] Destination
1424 * RETURNS
1425 * Success: S_OK.
1426 * Failure: E_INVALIDARG, if the source value is invalid
1427 * DISP_E_OVERFLOW, if the value will not fit in the destination
1429 HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut)
1431 LONG64 i64;
1432 HRESULT hRet;
1434 hRet = VarI8FromDec(pdecIn, &i64);
1436 if (SUCCEEDED(hRet))
1437 hRet = _VarUI2FromI8(i64, pusOut);
1438 return hRet;
1441 /************************************************************************
1442 * VarUI2FromI8 (OLEAUT32.378)
1444 * Convert a VT_I8 to a VT_UI2.
1446 * PARAMS
1447 * llIn [I] Source
1448 * pusOut [O] Destination
1450 * RETURNS
1451 * Success: S_OK.
1452 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1454 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
1456 return _VarUI2FromI8(llIn, pusOut);
1459 /************************************************************************
1460 * VarUI2FromUI8 (OLEAUT32.379)
1462 * Convert a VT_UI8 to a VT_UI2.
1464 * PARAMS
1465 * ullIn [I] Source
1466 * pusOut [O] Destination
1468 * RETURNS
1469 * Success: S_OK.
1470 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1472 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
1474 return _VarUI2FromUI8(ullIn, pusOut);
1477 /* I4
1480 /************************************************************************
1481 * VarI4FromUI1 (OLEAUT32.58)
1483 * Convert a VT_UI1 to a VT_I4.
1485 * PARAMS
1486 * bIn [I] Source
1487 * piOut [O] Destination
1489 * RETURNS
1490 * S_OK.
1492 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
1494 return _VarI4FromUI1(bIn, piOut);
1497 /************************************************************************
1498 * VarI4FromI2 (OLEAUT32.59)
1500 * Convert a VT_I2 to a VT_I4.
1502 * PARAMS
1503 * sIn [I] Source
1504 * piOut [O] Destination
1506 * RETURNS
1507 * Success: S_OK.
1508 * Failure: E_INVALIDARG, if the source value is invalid
1509 * DISP_E_OVERFLOW, if the value will not fit in the destination
1511 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
1513 return _VarI4FromI2(sIn, piOut);
1516 /************************************************************************
1517 * VarI4FromR4 (OLEAUT32.60)
1519 * Convert a VT_R4 to a VT_I4.
1521 * PARAMS
1522 * fltIn [I] Source
1523 * piOut [O] Destination
1525 * RETURNS
1526 * Success: S_OK.
1527 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1529 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
1531 return VarI4FromR8(fltIn, piOut);
1534 /************************************************************************
1535 * VarI4FromR8 (OLEAUT32.61)
1537 * Convert a VT_R8 to a VT_I4.
1539 * PARAMS
1540 * dblIn [I] Source
1541 * piOut [O] Destination
1543 * RETURNS
1544 * Success: S_OK.
1545 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1547 * NOTES
1548 * See VarI8FromR8() for details concerning rounding.
1550 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
1552 if (dblIn < (double)I4_MIN || dblIn > (double)I4_MAX)
1553 return DISP_E_OVERFLOW;
1554 VARIANT_DutchRound(LONG, dblIn, *piOut);
1555 return S_OK;
1558 /************************************************************************
1559 * VarI4FromCy (OLEAUT32.62)
1561 * Convert a VT_CY to a VT_I4.
1563 * PARAMS
1564 * cyIn [I] Source
1565 * piOut [O] Destination
1567 * RETURNS
1568 * Success: S_OK.
1569 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1571 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
1573 double d = cyIn.int64 / CY_MULTIPLIER_F;
1574 return VarI4FromR8(d, piOut);
1577 /************************************************************************
1578 * VarI4FromDate (OLEAUT32.63)
1580 * Convert a VT_DATE to a VT_I4.
1582 * PARAMS
1583 * dateIn [I] Source
1584 * piOut [O] Destination
1586 * RETURNS
1587 * Success: S_OK.
1588 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1590 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
1592 return VarI4FromR8(dateIn, piOut);
1595 /************************************************************************
1596 * VarI4FromStr (OLEAUT32.64)
1598 * Convert a VT_BSTR to a VT_I4.
1600 * PARAMS
1601 * strIn [I] Source
1602 * lcid [I] LCID for the conversion
1603 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1604 * piOut [O] Destination
1606 * RETURNS
1607 * Success: S_OK.
1608 * Failure: E_INVALIDARG, if any parameter is invalid
1609 * DISP_E_OVERFLOW, if the value will not fit in the destination
1610 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1612 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
1614 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
1617 /************************************************************************
1618 * VarI4FromDisp (OLEAUT32.65)
1620 * Convert a VT_DISPATCH to a VT_I4.
1622 * PARAMS
1623 * pdispIn [I] Source
1624 * lcid [I] LCID for conversion
1625 * piOut [O] Destination
1627 * RETURNS
1628 * Success: S_OK.
1629 * Failure: E_INVALIDARG, if the source value is invalid
1630 * DISP_E_OVERFLOW, if the value will not fit in the destination
1631 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1633 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
1635 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0);
1638 /************************************************************************
1639 * VarI4FromBool (OLEAUT32.66)
1641 * Convert a VT_BOOL to a VT_I4.
1643 * PARAMS
1644 * boolIn [I] Source
1645 * piOut [O] Destination
1647 * RETURNS
1648 * S_OK.
1650 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
1652 return _VarI4FromBool(boolIn, piOut);
1655 /************************************************************************
1656 * VarI4FromI1 (OLEAUT32.209)
1658 * Convert a VT_I1 to a VT_I4.
1660 * PARAMS
1661 * cIn [I] Source
1662 * piOut [O] Destination
1664 * RETURNS
1665 * S_OK.
1667 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
1669 return _VarI4FromI1(cIn, piOut);
1672 /************************************************************************
1673 * VarI4FromUI2 (OLEAUT32.210)
1675 * Convert a VT_UI2 to a VT_I4.
1677 * PARAMS
1678 * usIn [I] Source
1679 * piOut [O] Destination
1681 * RETURNS
1682 * S_OK.
1684 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
1686 return _VarI4FromUI2(usIn, piOut);
1689 /************************************************************************
1690 * VarI4FromUI4 (OLEAUT32.211)
1692 * Convert a VT_UI4 to a VT_I4.
1694 * PARAMS
1695 * ulIn [I] Source
1696 * piOut [O] Destination
1698 * RETURNS
1699 * Success: S_OK.
1700 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1702 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
1704 return _VarI4FromUI4(ulIn, piOut);
1707 /************************************************************************
1708 * VarI4FromDec (OLEAUT32.212)
1710 * Convert a VT_DECIMAL to a VT_I4.
1712 * PARAMS
1713 * pDecIn [I] Source
1714 * piOut [O] Destination
1716 * RETURNS
1717 * Success: S_OK.
1718 * Failure: E_INVALIDARG, if pdecIn is invalid
1719 * DISP_E_OVERFLOW, if the value will not fit in the destination
1721 HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut)
1723 LONG64 i64;
1724 HRESULT hRet;
1726 hRet = VarI8FromDec(pdecIn, &i64);
1728 if (SUCCEEDED(hRet))
1729 hRet = _VarI4FromI8(i64, piOut);
1730 return hRet;
1733 /************************************************************************
1734 * VarI4FromI8 (OLEAUT32.348)
1736 * Convert a VT_I8 to a VT_I4.
1738 * PARAMS
1739 * llIn [I] Source
1740 * piOut [O] Destination
1742 * RETURNS
1743 * Success: S_OK.
1744 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1746 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
1748 return _VarI4FromI8(llIn, piOut);
1751 /************************************************************************
1752 * VarI4FromUI8 (OLEAUT32.349)
1754 * Convert a VT_UI8 to a VT_I4.
1756 * PARAMS
1757 * ullIn [I] Source
1758 * piOut [O] Destination
1760 * RETURNS
1761 * Success: S_OK.
1762 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1764 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
1766 return _VarI4FromUI8(ullIn, piOut);
1769 /* UI4
1772 /************************************************************************
1773 * VarUI4FromUI1 (OLEAUT32.270)
1775 * Convert a VT_UI1 to a VT_UI4.
1777 * PARAMS
1778 * bIn [I] Source
1779 * pulOut [O] Destination
1781 * RETURNS
1782 * S_OK.
1784 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
1786 return _VarUI4FromUI1(bIn, pulOut);
1789 /************************************************************************
1790 * VarUI4FromI2 (OLEAUT32.271)
1792 * Convert a VT_I2 to a VT_UI4.
1794 * PARAMS
1795 * sIn [I] Source
1796 * pulOut [O] Destination
1798 * RETURNS
1799 * Success: S_OK.
1800 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1802 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
1804 return _VarUI4FromI2(sIn, pulOut);
1807 /************************************************************************
1808 * VarUI4FromI4 (OLEAUT32.272)
1810 * Convert a VT_I4 to a VT_UI4.
1812 * PARAMS
1813 * iIn [I] Source
1814 * pulOut [O] Destination
1816 * RETURNS
1817 * Success: S_OK.
1818 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1820 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
1822 return _VarUI4FromI4(iIn, pulOut);
1825 /************************************************************************
1826 * VarUI4FromR4 (OLEAUT32.273)
1828 * Convert a VT_R4 to a VT_UI4.
1830 * PARAMS
1831 * fltIn [I] Source
1832 * pulOut [O] Destination
1834 * RETURNS
1835 * Success: S_OK.
1836 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1838 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
1840 return VarUI4FromR8(fltIn, pulOut);
1843 /************************************************************************
1844 * VarUI4FromR8 (OLEAUT32.274)
1846 * Convert a VT_R8 to a VT_UI4.
1848 * PARAMS
1849 * dblIn [I] Source
1850 * pulOut [O] Destination
1852 * RETURNS
1853 * Success: S_OK.
1854 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1856 * NOTES
1857 * See VarI8FromR8() for details concerning rounding.
1859 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
1861 if (dblIn < -0.5 || dblIn > (double)UI4_MAX)
1862 return DISP_E_OVERFLOW;
1863 VARIANT_DutchRound(ULONG, dblIn, *pulOut);
1864 return S_OK;
1867 /************************************************************************
1868 * VarUI4FromDate (OLEAUT32.275)
1870 * Convert a VT_DATE to a VT_UI4.
1872 * PARAMS
1873 * dateIn [I] Source
1874 * pulOut [O] Destination
1876 * RETURNS
1877 * Success: S_OK.
1878 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1880 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
1882 return VarUI4FromR8(dateIn, pulOut);
1885 /************************************************************************
1886 * VarUI4FromCy (OLEAUT32.276)
1888 * Convert a VT_CY to a VT_UI4.
1890 * PARAMS
1891 * cyIn [I] Source
1892 * pulOut [O] Destination
1894 * RETURNS
1895 * Success: S_OK.
1896 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1898 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
1900 double d = cyIn.int64 / CY_MULTIPLIER_F;
1901 return VarUI4FromR8(d, pulOut);
1904 /************************************************************************
1905 * VarUI4FromStr (OLEAUT32.277)
1907 * Convert a VT_BSTR to a VT_UI4.
1909 * PARAMS
1910 * strIn [I] Source
1911 * lcid [I] LCID for the conversion
1912 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1913 * pulOut [O] Destination
1915 * RETURNS
1916 * Success: S_OK.
1917 * Failure: E_INVALIDARG, if any parameter is invalid
1918 * DISP_E_OVERFLOW, if the value will not fit in the destination
1919 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1921 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
1923 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
1926 /************************************************************************
1927 * VarUI4FromDisp (OLEAUT32.278)
1929 * Convert a VT_DISPATCH to a VT_UI4.
1931 * PARAMS
1932 * pdispIn [I] Source
1933 * lcid [I] LCID for conversion
1934 * pulOut [O] Destination
1936 * RETURNS
1937 * Success: S_OK.
1938 * Failure: E_INVALIDARG, if the source value is invalid
1939 * DISP_E_OVERFLOW, if the value will not fit in the destination
1940 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1942 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
1944 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0);
1947 /************************************************************************
1948 * VarUI4FromBool (OLEAUT32.279)
1950 * Convert a VT_BOOL to a VT_UI4.
1952 * PARAMS
1953 * boolIn [I] Source
1954 * pulOut [O] Destination
1956 * RETURNS
1957 * S_OK.
1959 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
1961 return _VarUI4FromBool(boolIn, pulOut);
1964 /************************************************************************
1965 * VarUI4FromI1 (OLEAUT32.280)
1967 * Convert a VT_I1 to a VT_UI4.
1969 * PARAMS
1970 * cIn [I] Source
1971 * pulOut [O] Destination
1973 * RETURNS
1974 * Success: S_OK.
1975 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1977 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
1979 return _VarUI4FromI1(cIn, pulOut);
1982 /************************************************************************
1983 * VarUI4FromUI2 (OLEAUT32.281)
1985 * Convert a VT_UI2 to a VT_UI4.
1987 * PARAMS
1988 * usIn [I] Source
1989 * pulOut [O] Destination
1991 * RETURNS
1992 * S_OK.
1994 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
1996 return _VarUI4FromUI2(usIn, pulOut);
1999 /************************************************************************
2000 * VarUI4FromDec (OLEAUT32.282)
2002 * Convert a VT_DECIMAL to a VT_UI4.
2004 * PARAMS
2005 * pDecIn [I] Source
2006 * pulOut [O] Destination
2008 * RETURNS
2009 * Success: S_OK.
2010 * Failure: E_INVALIDARG, if pdecIn is invalid
2011 * DISP_E_OVERFLOW, if the value will not fit in the destination
2013 HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut)
2015 LONG64 i64;
2016 HRESULT hRet;
2018 hRet = VarI8FromDec(pdecIn, &i64);
2020 if (SUCCEEDED(hRet))
2021 hRet = _VarUI4FromI8(i64, pulOut);
2022 return hRet;
2025 /************************************************************************
2026 * VarUI4FromI8 (OLEAUT32.425)
2028 * Convert a VT_I8 to a VT_UI4.
2030 * PARAMS
2031 * llIn [I] Source
2032 * pulOut [O] Destination
2034 * RETURNS
2035 * Success: S_OK.
2036 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2038 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
2040 return _VarUI4FromI8(llIn, pulOut);
2043 /************************************************************************
2044 * VarUI4FromUI8 (OLEAUT32.426)
2046 * Convert a VT_UI8 to a VT_UI4.
2048 * PARAMS
2049 * ullIn [I] Source
2050 * pulOut [O] Destination
2052 * RETURNS
2053 * Success: S_OK.
2054 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2056 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
2058 return _VarUI4FromUI8(ullIn, pulOut);
2061 /* I8
2064 /************************************************************************
2065 * VarI8FromUI1 (OLEAUT32.333)
2067 * Convert a VT_UI1 to a VT_I8.
2069 * PARAMS
2070 * bIn [I] Source
2071 * pi64Out [O] Destination
2073 * RETURNS
2074 * S_OK.
2076 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
2078 return _VarI8FromUI1(bIn, pi64Out);
2082 /************************************************************************
2083 * VarI8FromI2 (OLEAUT32.334)
2085 * Convert a VT_I2 to a VT_I8.
2087 * PARAMS
2088 * sIn [I] Source
2089 * pi64Out [O] Destination
2091 * RETURNS
2092 * S_OK.
2094 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
2096 return _VarI8FromI2(sIn, pi64Out);
2099 /************************************************************************
2100 * VarI8FromR4 (OLEAUT32.335)
2102 * Convert a VT_R4 to a VT_I8.
2104 * PARAMS
2105 * fltIn [I] Source
2106 * pi64Out [O] Destination
2108 * RETURNS
2109 * Success: S_OK.
2110 * Failure: E_INVALIDARG, if the source value is invalid
2111 * DISP_E_OVERFLOW, if the value will not fit in the destination
2113 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
2115 return VarI8FromR8(fltIn, pi64Out);
2118 /************************************************************************
2119 * VarI8FromR8 (OLEAUT32.336)
2121 * Convert a VT_R8 to a VT_I8.
2123 * PARAMS
2124 * dblIn [I] Source
2125 * pi64Out [O] Destination
2127 * RETURNS
2128 * Success: S_OK.
2129 * Failure: E_INVALIDARG, if the source value is invalid
2130 * DISP_E_OVERFLOW, if the value will not fit in the destination
2132 * NOTES
2133 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2134 * very high or low values will not be accurately converted.
2136 * Numbers are rounded using Dutch rounding, as follows:
2138 *| Fractional Part Sign Direction Example
2139 *| --------------- ---- --------- -------
2140 *| < 0.5 + Down 0.4 -> 0.0
2141 *| < 0.5 - Up -0.4 -> 0.0
2142 *| > 0.5 + Up 0.6 -> 1.0
2143 *| < 0.5 - Up -0.6 -> -1.0
2144 *| = 0.5 + Up/Down Down if even, Up if odd
2145 *| = 0.5 - Up/Down Up if even, Down if odd
2147 * This system is often used in supermarkets.
2149 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
2151 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
2152 return DISP_E_OVERFLOW;
2153 VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
2154 return S_OK;
2157 /************************************************************************
2158 * VarI8FromCy (OLEAUT32.337)
2160 * Convert a VT_CY to a VT_I8.
2162 * PARAMS
2163 * cyIn [I] Source
2164 * pi64Out [O] Destination
2166 * RETURNS
2167 * S_OK.
2169 * NOTES
2170 * All negative numbers are rounded down by 1, including those that are
2171 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2172 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2173 * for details.
2175 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
2177 *pi64Out = cyIn.int64 / CY_MULTIPLIER;
2179 if (cyIn.int64 < 0)
2180 (*pi64Out)--; /* Mimic Win32 bug */
2181 else
2183 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2185 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1)))
2186 (*pi64Out)++;
2188 return S_OK;
2191 /************************************************************************
2192 * VarI8FromDate (OLEAUT32.338)
2194 * Convert a VT_DATE to a VT_I8.
2196 * PARAMS
2197 * dateIn [I] Source
2198 * pi64Out [O] Destination
2200 * RETURNS
2201 * Success: S_OK.
2202 * Failure: E_INVALIDARG, if the source value is invalid
2203 * DISP_E_OVERFLOW, if the value will not fit in the destination
2204 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2206 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
2208 return VarI8FromR8(dateIn, pi64Out);
2211 /************************************************************************
2212 * VarI8FromStr (OLEAUT32.339)
2214 * Convert a VT_BSTR to a VT_I8.
2216 * PARAMS
2217 * strIn [I] Source
2218 * lcid [I] LCID for the conversion
2219 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2220 * pi64Out [O] Destination
2222 * RETURNS
2223 * Success: S_OK.
2224 * Failure: E_INVALIDARG, if the source value is invalid
2225 * DISP_E_OVERFLOW, if the value will not fit in the destination
2226 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2228 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
2230 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
2233 /************************************************************************
2234 * VarI8FromDisp (OLEAUT32.340)
2236 * Convert a VT_DISPATCH to a VT_I8.
2238 * PARAMS
2239 * pdispIn [I] Source
2240 * lcid [I] LCID for conversion
2241 * pi64Out [O] Destination
2243 * RETURNS
2244 * Success: S_OK.
2245 * Failure: E_INVALIDARG, if the source value is invalid
2246 * DISP_E_OVERFLOW, if the value will not fit in the destination
2247 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2249 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
2251 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0);
2254 /************************************************************************
2255 * VarI8FromBool (OLEAUT32.341)
2257 * Convert a VT_BOOL to a VT_I8.
2259 * PARAMS
2260 * boolIn [I] Source
2261 * pi64Out [O] Destination
2263 * RETURNS
2264 * S_OK.
2266 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
2268 return VarI8FromI2(boolIn, pi64Out);
2271 /************************************************************************
2272 * VarI8FromI1 (OLEAUT32.342)
2274 * Convert a VT_I1 to a VT_I8.
2276 * PARAMS
2277 * cIn [I] Source
2278 * pi64Out [O] Destination
2280 * RETURNS
2281 * S_OK.
2283 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
2285 return _VarI8FromI1(cIn, pi64Out);
2288 /************************************************************************
2289 * VarI8FromUI2 (OLEAUT32.343)
2291 * Convert a VT_UI2 to a VT_I8.
2293 * PARAMS
2294 * usIn [I] Source
2295 * pi64Out [O] Destination
2297 * RETURNS
2298 * S_OK.
2300 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
2302 return _VarI8FromUI2(usIn, pi64Out);
2305 /************************************************************************
2306 * VarI8FromUI4 (OLEAUT32.344)
2308 * Convert a VT_UI4 to a VT_I8.
2310 * PARAMS
2311 * ulIn [I] Source
2312 * pi64Out [O] Destination
2314 * RETURNS
2315 * S_OK.
2317 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
2319 return _VarI8FromUI4(ulIn, pi64Out);
2322 /************************************************************************
2323 * VarI8FromDec (OLEAUT32.345)
2325 * Convert a VT_DECIMAL to a VT_I8.
2327 * PARAMS
2328 * pDecIn [I] Source
2329 * pi64Out [O] Destination
2331 * RETURNS
2332 * Success: S_OK.
2333 * Failure: E_INVALIDARG, if the source value is invalid
2334 * DISP_E_OVERFLOW, if the value will not fit in the destination
2336 HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out)
2338 if (!DEC_SCALE(pdecIn))
2340 /* This decimal is just a 96 bit integer */
2341 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2342 return E_INVALIDARG;
2344 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000)
2345 return DISP_E_OVERFLOW;
2347 if (DEC_SIGN(pdecIn))
2348 *pi64Out = -DEC_LO64(pdecIn);
2349 else
2350 *pi64Out = DEC_LO64(pdecIn);
2351 return S_OK;
2353 else
2355 /* Decimal contains a floating point number */
2356 HRESULT hRet;
2357 double dbl;
2359 hRet = VarR8FromDec(pdecIn, &dbl);
2360 if (SUCCEEDED(hRet))
2361 hRet = VarI8FromR8(dbl, pi64Out);
2362 return hRet;
2366 /************************************************************************
2367 * VarI8FromUI8 (OLEAUT32.427)
2369 * Convert a VT_UI8 to a VT_I8.
2371 * PARAMS
2372 * ullIn [I] Source
2373 * pi64Out [O] Destination
2375 * RETURNS
2376 * Success: S_OK.
2377 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2379 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
2381 return _VarI8FromUI8(ullIn, pi64Out);
2384 /* UI8
2387 /************************************************************************
2388 * VarUI8FromI8 (OLEAUT32.428)
2390 * Convert a VT_I8 to a VT_UI8.
2392 * PARAMS
2393 * ulIn [I] Source
2394 * pui64Out [O] Destination
2396 * RETURNS
2397 * Success: S_OK.
2398 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2400 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
2402 return _VarUI8FromI8(llIn, pui64Out);
2405 /************************************************************************
2406 * VarUI8FromUI1 (OLEAUT32.429)
2408 * Convert a VT_UI1 to a VT_UI8.
2410 * PARAMS
2411 * bIn [I] Source
2412 * pui64Out [O] Destination
2414 * RETURNS
2415 * S_OK.
2417 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
2419 return _VarUI8FromUI1(bIn, pui64Out);
2422 /************************************************************************
2423 * VarUI8FromI2 (OLEAUT32.430)
2425 * Convert a VT_I2 to a VT_UI8.
2427 * PARAMS
2428 * sIn [I] Source
2429 * pui64Out [O] Destination
2431 * RETURNS
2432 * S_OK.
2434 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
2436 return _VarUI8FromI2(sIn, pui64Out);
2439 /************************************************************************
2440 * VarUI8FromR4 (OLEAUT32.431)
2442 * Convert a VT_R4 to a VT_UI8.
2444 * PARAMS
2445 * fltIn [I] Source
2446 * pui64Out [O] Destination
2448 * RETURNS
2449 * Success: S_OK.
2450 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2452 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
2454 return VarUI8FromR8(fltIn, pui64Out);
2457 /************************************************************************
2458 * VarUI8FromR8 (OLEAUT32.432)
2460 * Convert a VT_R8 to a VT_UI8.
2462 * PARAMS
2463 * dblIn [I] Source
2464 * pui64Out [O] Destination
2466 * RETURNS
2467 * Success: S_OK.
2468 * Failure: E_INVALIDARG, if the source value is invalid
2469 * DISP_E_OVERFLOW, if the value will not fit in the destination
2471 * NOTES
2472 * See VarI8FromR8() for details concerning rounding.
2474 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
2476 if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
2477 return DISP_E_OVERFLOW;
2478 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
2479 return S_OK;
2482 /************************************************************************
2483 * VarUI8FromCy (OLEAUT32.433)
2485 * Convert a VT_CY to a VT_UI8.
2487 * PARAMS
2488 * cyIn [I] Source
2489 * pui64Out [O] Destination
2491 * RETURNS
2492 * Success: S_OK.
2493 * Failure: E_INVALIDARG, if the source value is invalid
2494 * DISP_E_OVERFLOW, if the value will not fit in the destination
2496 * NOTES
2497 * Negative values >= -5000 will be converted to 0.
2499 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
2501 if (cyIn.int64 < 0)
2503 if (cyIn.int64 < -CY_HALF)
2504 return DISP_E_OVERFLOW;
2505 *pui64Out = 0;
2507 else
2509 *pui64Out = cyIn.int64 / CY_MULTIPLIER;
2511 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2513 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1)))
2514 (*pui64Out)++;
2516 return S_OK;
2519 /************************************************************************
2520 * VarUI8FromDate (OLEAUT32.434)
2522 * Convert a VT_DATE to a VT_UI8.
2524 * PARAMS
2525 * dateIn [I] Source
2526 * pui64Out [O] Destination
2528 * RETURNS
2529 * Success: S_OK.
2530 * Failure: E_INVALIDARG, if the source value is invalid
2531 * DISP_E_OVERFLOW, if the value will not fit in the destination
2532 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2534 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
2536 return VarUI8FromR8(dateIn, pui64Out);
2539 /************************************************************************
2540 * VarUI8FromStr (OLEAUT32.435)
2542 * Convert a VT_BSTR to a VT_UI8.
2544 * PARAMS
2545 * strIn [I] Source
2546 * lcid [I] LCID for the conversion
2547 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2548 * pui64Out [O] Destination
2550 * RETURNS
2551 * Success: S_OK.
2552 * Failure: E_INVALIDARG, if the source value is invalid
2553 * DISP_E_OVERFLOW, if the value will not fit in the destination
2554 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2556 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
2558 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
2561 /************************************************************************
2562 * VarUI8FromDisp (OLEAUT32.436)
2564 * Convert a VT_DISPATCH to a VT_UI8.
2566 * PARAMS
2567 * pdispIn [I] Source
2568 * lcid [I] LCID for conversion
2569 * pui64Out [O] Destination
2571 * RETURNS
2572 * Success: S_OK.
2573 * Failure: E_INVALIDARG, if the source value is invalid
2574 * DISP_E_OVERFLOW, if the value will not fit in the destination
2575 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2577 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
2579 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0);
2582 /************************************************************************
2583 * VarUI8FromBool (OLEAUT32.437)
2585 * Convert a VT_BOOL to a VT_UI8.
2587 * PARAMS
2588 * boolIn [I] Source
2589 * pui64Out [O] Destination
2591 * RETURNS
2592 * Success: S_OK.
2593 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2595 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
2597 return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
2599 /************************************************************************
2600 * VarUI8FromI1 (OLEAUT32.438)
2602 * Convert a VT_I1 to a VT_UI8.
2604 * PARAMS
2605 * cIn [I] Source
2606 * pui64Out [O] Destination
2608 * RETURNS
2609 * Success: S_OK.
2610 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2612 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
2614 return _VarUI8FromI1(cIn, pui64Out);
2617 /************************************************************************
2618 * VarUI8FromUI2 (OLEAUT32.439)
2620 * Convert a VT_UI2 to a VT_UI8.
2622 * PARAMS
2623 * usIn [I] Source
2624 * pui64Out [O] Destination
2626 * RETURNS
2627 * S_OK.
2629 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
2631 return _VarUI8FromUI2(usIn, pui64Out);
2634 /************************************************************************
2635 * VarUI8FromUI4 (OLEAUT32.440)
2637 * Convert a VT_UI4 to a VT_UI8.
2639 * PARAMS
2640 * ulIn [I] Source
2641 * pui64Out [O] Destination
2643 * RETURNS
2644 * S_OK.
2646 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
2648 return _VarUI8FromUI4(ulIn, pui64Out);
2651 /************************************************************************
2652 * VarUI8FromDec (OLEAUT32.441)
2654 * Convert a VT_DECIMAL to a VT_UI8.
2656 * PARAMS
2657 * pDecIn [I] Source
2658 * pui64Out [O] Destination
2660 * RETURNS
2661 * Success: S_OK.
2662 * Failure: E_INVALIDARG, if the source value is invalid
2663 * DISP_E_OVERFLOW, if the value will not fit in the destination
2665 * NOTES
2666 * Under native Win32, if the source value has a scale of 0, its sign is
2667 * ignored, i.e. this function takes the absolute value rather than fail
2668 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2669 * (use VarAbs() on pDecIn first if you really want this behaviour).
2671 HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out)
2673 if (!DEC_SCALE(pdecIn))
2675 /* This decimal is just a 96 bit integer */
2676 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2677 return E_INVALIDARG;
2679 if (DEC_HI32(pdecIn))
2680 return DISP_E_OVERFLOW;
2682 if (DEC_SIGN(pdecIn))
2684 WARN("Sign would be ignored under Win32!\n");
2685 return DISP_E_OVERFLOW;
2688 *pui64Out = DEC_LO64(pdecIn);
2689 return S_OK;
2691 else
2693 /* Decimal contains a floating point number */
2694 HRESULT hRet;
2695 double dbl;
2697 hRet = VarR8FromDec(pdecIn, &dbl);
2698 if (SUCCEEDED(hRet))
2699 hRet = VarUI8FromR8(dbl, pui64Out);
2700 return hRet;
2704 /* R4
2707 /************************************************************************
2708 * VarR4FromUI1 (OLEAUT32.68)
2710 * Convert a VT_UI1 to a VT_R4.
2712 * PARAMS
2713 * bIn [I] Source
2714 * pFltOut [O] Destination
2716 * RETURNS
2717 * S_OK.
2719 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
2721 return _VarR4FromUI1(bIn, pFltOut);
2724 /************************************************************************
2725 * VarR4FromI2 (OLEAUT32.69)
2727 * Convert a VT_I2 to a VT_R4.
2729 * PARAMS
2730 * sIn [I] Source
2731 * pFltOut [O] Destination
2733 * RETURNS
2734 * S_OK.
2736 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
2738 return _VarR4FromI2(sIn, pFltOut);
2741 /************************************************************************
2742 * VarR4FromI4 (OLEAUT32.70)
2744 * Convert a VT_I4 to a VT_R4.
2746 * PARAMS
2747 * sIn [I] Source
2748 * pFltOut [O] Destination
2750 * RETURNS
2751 * S_OK.
2753 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
2755 return _VarR4FromI4(lIn, pFltOut);
2758 /************************************************************************
2759 * VarR4FromR8 (OLEAUT32.71)
2761 * Convert a VT_R8 to a VT_R4.
2763 * PARAMS
2764 * dblIn [I] Source
2765 * pFltOut [O] Destination
2767 * RETURNS
2768 * Success: S_OK.
2769 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2771 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
2773 double d = dblIn < 0.0 ? -dblIn : dblIn;
2774 if (d > R4_MAX) return DISP_E_OVERFLOW;
2775 *pFltOut = dblIn;
2776 return S_OK;
2779 /************************************************************************
2780 * VarR4FromCy (OLEAUT32.72)
2782 * Convert a VT_CY to a VT_R4.
2784 * PARAMS
2785 * cyIn [I] Source
2786 * pFltOut [O] Destination
2788 * RETURNS
2789 * S_OK.
2791 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
2793 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
2794 return S_OK;
2797 /************************************************************************
2798 * VarR4FromDate (OLEAUT32.73)
2800 * Convert a VT_DATE to a VT_R4.
2802 * PARAMS
2803 * dateIn [I] Source
2804 * pFltOut [O] Destination
2806 * RETURNS
2807 * Success: S_OK.
2808 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2810 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
2812 return VarR4FromR8(dateIn, pFltOut);
2815 /************************************************************************
2816 * VarR4FromStr (OLEAUT32.74)
2818 * Convert a VT_BSTR to a VT_R4.
2820 * PARAMS
2821 * strIn [I] Source
2822 * lcid [I] LCID for the conversion
2823 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2824 * pFltOut [O] Destination
2826 * RETURNS
2827 * Success: S_OK.
2828 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2829 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2831 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
2833 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
2836 /************************************************************************
2837 * VarR4FromDisp (OLEAUT32.75)
2839 * Convert a VT_DISPATCH to a VT_R4.
2841 * PARAMS
2842 * pdispIn [I] Source
2843 * lcid [I] LCID for conversion
2844 * pFltOut [O] Destination
2846 * RETURNS
2847 * Success: S_OK.
2848 * Failure: E_INVALIDARG, if the source value is invalid
2849 * DISP_E_OVERFLOW, if the value will not fit in the destination
2850 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2852 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
2854 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0);
2857 /************************************************************************
2858 * VarR4FromBool (OLEAUT32.76)
2860 * Convert a VT_BOOL to a VT_R4.
2862 * PARAMS
2863 * boolIn [I] Source
2864 * pFltOut [O] Destination
2866 * RETURNS
2867 * S_OK.
2869 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2871 return VarR4FromI2(boolIn, pFltOut);
2874 /************************************************************************
2875 * VarR4FromI1 (OLEAUT32.213)
2877 * Convert a VT_I1 to a VT_R4.
2879 * PARAMS
2880 * cIn [I] Source
2881 * pFltOut [O] Destination
2883 * RETURNS
2884 * Success: S_OK.
2885 * Failure: E_INVALIDARG, if the source value is invalid
2886 * DISP_E_OVERFLOW, if the value will not fit in the destination
2887 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2889 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2891 return _VarR4FromI1(cIn, pFltOut);
2894 /************************************************************************
2895 * VarR4FromUI2 (OLEAUT32.214)
2897 * Convert a VT_UI2 to a VT_R4.
2899 * PARAMS
2900 * usIn [I] Source
2901 * pFltOut [O] Destination
2903 * RETURNS
2904 * Success: S_OK.
2905 * Failure: E_INVALIDARG, if the source value is invalid
2906 * DISP_E_OVERFLOW, if the value will not fit in the destination
2907 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2909 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2911 return _VarR4FromUI2(usIn, pFltOut);
2914 /************************************************************************
2915 * VarR4FromUI4 (OLEAUT32.215)
2917 * Convert a VT_UI4 to a VT_R4.
2919 * PARAMS
2920 * ulIn [I] Source
2921 * pFltOut [O] Destination
2923 * RETURNS
2924 * Success: S_OK.
2925 * Failure: E_INVALIDARG, if the source value is invalid
2926 * DISP_E_OVERFLOW, if the value will not fit in the destination
2927 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2929 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2931 return _VarR4FromUI4(ulIn, pFltOut);
2934 /************************************************************************
2935 * VarR4FromDec (OLEAUT32.216)
2937 * Convert a VT_DECIMAL to a VT_R4.
2939 * PARAMS
2940 * pDecIn [I] Source
2941 * pFltOut [O] Destination
2943 * RETURNS
2944 * Success: S_OK.
2945 * Failure: E_INVALIDARG, if the source value is invalid.
2947 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
2949 BYTE scale = DEC_SCALE(pDecIn);
2950 int divisor = 1;
2951 double highPart;
2953 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2954 return E_INVALIDARG;
2956 while (scale--)
2957 divisor *= 10;
2959 if (DEC_SIGN(pDecIn))
2960 divisor = -divisor;
2962 if (DEC_HI32(pDecIn))
2964 highPart = (double)DEC_HI32(pDecIn) / (double)divisor;
2965 highPart *= 4294967296.0F;
2966 highPart *= 4294967296.0F;
2968 else
2969 highPart = 0.0;
2971 *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart;
2972 return S_OK;
2975 /************************************************************************
2976 * VarR4FromI8 (OLEAUT32.360)
2978 * Convert a VT_I8 to a VT_R4.
2980 * PARAMS
2981 * ullIn [I] Source
2982 * pFltOut [O] Destination
2984 * RETURNS
2985 * S_OK.
2987 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2989 return _VarR4FromI8(llIn, pFltOut);
2992 /************************************************************************
2993 * VarR4FromUI8 (OLEAUT32.361)
2995 * Convert a VT_UI8 to a VT_R4.
2997 * PARAMS
2998 * ullIn [I] Source
2999 * pFltOut [O] Destination
3001 * RETURNS
3002 * S_OK.
3004 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
3006 return _VarR4FromUI8(ullIn, pFltOut);
3009 /************************************************************************
3010 * VarR4CmpR8 (OLEAUT32.316)
3012 * Compare a VT_R4 to a VT_R8.
3014 * PARAMS
3015 * fltLeft [I] Source
3016 * dblRight [I] Value to compare
3018 * RETURNS
3019 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3020 * equal to or greater than dblRight respectively.
3022 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3024 if (fltLeft < dblRight)
3025 return VARCMP_LT;
3026 else if (fltLeft > dblRight)
3027 return VARCMP_GT;
3028 return VARCMP_EQ;
3031 /* R8
3034 /************************************************************************
3035 * VarR8FromUI1 (OLEAUT32.78)
3037 * Convert a VT_UI1 to a VT_R8.
3039 * PARAMS
3040 * bIn [I] Source
3041 * pDblOut [O] Destination
3043 * RETURNS
3044 * S_OK.
3046 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3048 return _VarR8FromUI1(bIn, pDblOut);
3051 /************************************************************************
3052 * VarR8FromI2 (OLEAUT32.79)
3054 * Convert a VT_I2 to a VT_R8.
3056 * PARAMS
3057 * sIn [I] Source
3058 * pDblOut [O] Destination
3060 * RETURNS
3061 * S_OK.
3063 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3065 return _VarR8FromI2(sIn, pDblOut);
3068 /************************************************************************
3069 * VarR8FromI4 (OLEAUT32.80)
3071 * Convert a VT_I4 to a VT_R8.
3073 * PARAMS
3074 * sIn [I] Source
3075 * pDblOut [O] Destination
3077 * RETURNS
3078 * S_OK.
3080 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3082 return _VarR8FromI4(lIn, pDblOut);
3085 /************************************************************************
3086 * VarR8FromR4 (OLEAUT32.81)
3088 * Convert a VT_R4 to a VT_R8.
3090 * PARAMS
3091 * fltIn [I] Source
3092 * pDblOut [O] Destination
3094 * RETURNS
3095 * S_OK.
3097 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3099 return _VarR8FromR4(fltIn, pDblOut);
3102 /************************************************************************
3103 * VarR8FromCy (OLEAUT32.82)
3105 * Convert a VT_CY to a VT_R8.
3107 * PARAMS
3108 * cyIn [I] Source
3109 * pDblOut [O] Destination
3111 * RETURNS
3112 * S_OK.
3114 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3116 return _VarR8FromCy(cyIn, pDblOut);
3119 /************************************************************************
3120 * VarR8FromDate (OLEAUT32.83)
3122 * Convert a VT_DATE to a VT_R8.
3124 * PARAMS
3125 * dateIn [I] Source
3126 * pDblOut [O] Destination
3128 * RETURNS
3129 * S_OK.
3131 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3133 return _VarR8FromDate(dateIn, pDblOut);
3136 /************************************************************************
3137 * VarR8FromStr (OLEAUT32.84)
3139 * Convert a VT_BSTR to a VT_R8.
3141 * PARAMS
3142 * strIn [I] Source
3143 * lcid [I] LCID for the conversion
3144 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3145 * pDblOut [O] Destination
3147 * RETURNS
3148 * Success: S_OK.
3149 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3150 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3152 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3154 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3157 /************************************************************************
3158 * VarR8FromDisp (OLEAUT32.85)
3160 * Convert a VT_DISPATCH to a VT_R8.
3162 * PARAMS
3163 * pdispIn [I] Source
3164 * lcid [I] LCID for conversion
3165 * pDblOut [O] Destination
3167 * RETURNS
3168 * Success: S_OK.
3169 * Failure: E_INVALIDARG, if the source value is invalid
3170 * DISP_E_OVERFLOW, if the value will not fit in the destination
3171 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3173 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3175 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0);
3178 /************************************************************************
3179 * VarR8FromBool (OLEAUT32.86)
3181 * Convert a VT_BOOL to a VT_R8.
3183 * PARAMS
3184 * boolIn [I] Source
3185 * pDblOut [O] Destination
3187 * RETURNS
3188 * S_OK.
3190 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3192 return VarR8FromI2(boolIn, pDblOut);
3195 /************************************************************************
3196 * VarR8FromI1 (OLEAUT32.217)
3198 * Convert a VT_I1 to a VT_R8.
3200 * PARAMS
3201 * cIn [I] Source
3202 * pDblOut [O] Destination
3204 * RETURNS
3205 * Success: S_OK.
3206 * Failure: E_INVALIDARG, if the source value is invalid
3207 * DISP_E_OVERFLOW, if the value will not fit in the destination
3208 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3210 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3212 return _VarR8FromI1(cIn, pDblOut);
3215 /************************************************************************
3216 * VarR8FromUI2 (OLEAUT32.218)
3218 * Convert a VT_UI2 to a VT_R8.
3220 * PARAMS
3221 * usIn [I] Source
3222 * pDblOut [O] Destination
3224 * RETURNS
3225 * Success: S_OK.
3226 * Failure: E_INVALIDARG, if the source value is invalid
3227 * DISP_E_OVERFLOW, if the value will not fit in the destination
3228 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3230 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3232 return _VarR8FromUI2(usIn, pDblOut);
3235 /************************************************************************
3236 * VarR8FromUI4 (OLEAUT32.219)
3238 * Convert a VT_UI4 to a VT_R8.
3240 * PARAMS
3241 * ulIn [I] Source
3242 * pDblOut [O] Destination
3244 * RETURNS
3245 * Success: S_OK.
3246 * Failure: E_INVALIDARG, if the source value is invalid
3247 * DISP_E_OVERFLOW, if the value will not fit in the destination
3248 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3250 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3252 return _VarR8FromUI4(ulIn, pDblOut);
3255 /************************************************************************
3256 * VarR8FromDec (OLEAUT32.220)
3258 * Convert a VT_DECIMAL to a VT_R8.
3260 * PARAMS
3261 * pDecIn [I] Source
3262 * pDblOut [O] Destination
3264 * RETURNS
3265 * Success: S_OK.
3266 * Failure: E_INVALIDARG, if the source value is invalid.
3268 HRESULT WINAPI VarR8FromDec(const DECIMAL* pDecIn, double *pDblOut)
3270 BYTE scale = DEC_SCALE(pDecIn);
3271 double divisor = 1.0, highPart;
3273 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3274 return E_INVALIDARG;
3276 while (scale--)
3277 divisor *= 10;
3279 if (DEC_SIGN(pDecIn))
3280 divisor = -divisor;
3282 if (DEC_HI32(pDecIn))
3284 highPart = (double)DEC_HI32(pDecIn) / divisor;
3285 highPart *= 4294967296.0F;
3286 highPart *= 4294967296.0F;
3288 else
3289 highPart = 0.0;
3291 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3292 return S_OK;
3295 /************************************************************************
3296 * VarR8FromI8 (OLEAUT32.362)
3298 * Convert a VT_I8 to a VT_R8.
3300 * PARAMS
3301 * ullIn [I] Source
3302 * pDblOut [O] Destination
3304 * RETURNS
3305 * S_OK.
3307 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3309 return _VarR8FromI8(llIn, pDblOut);
3312 /************************************************************************
3313 * VarR8FromUI8 (OLEAUT32.363)
3315 * Convert a VT_UI8 to a VT_R8.
3317 * PARAMS
3318 * ullIn [I] Source
3319 * pDblOut [O] Destination
3321 * RETURNS
3322 * S_OK.
3324 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3326 return _VarR8FromUI8(ullIn, pDblOut);
3329 /************************************************************************
3330 * VarR8Pow (OLEAUT32.315)
3332 * Raise a VT_R8 to a power.
3334 * PARAMS
3335 * dblLeft [I] Source
3336 * dblPow [I] Power to raise dblLeft by
3337 * pDblOut [O] Destination
3339 * RETURNS
3340 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3342 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3344 *pDblOut = pow(dblLeft, dblPow);
3345 return S_OK;
3348 /************************************************************************
3349 * VarR8Round (OLEAUT32.317)
3351 * Round a VT_R8 to a given number of decimal points.
3353 * PARAMS
3354 * dblIn [I] Source
3355 * nDig [I] Number of decimal points to round to
3356 * pDblOut [O] Destination for rounded number
3358 * RETURNS
3359 * Success: S_OK. pDblOut is rounded to nDig digits.
3360 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3362 * NOTES
3363 * The native version of this function rounds using the internal
3364 * binary representation of the number. Wine uses the dutch rounding
3365 * convention, so therefore small differences can occur in the value returned.
3366 * MSDN says that you should use your own rounding function if you want
3367 * rounding to be predictable in your application.
3369 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3371 double scale, whole, fract;
3373 if (nDig < 0)
3374 return E_INVALIDARG;
3376 scale = pow(10.0, nDig);
3378 dblIn *= scale;
3379 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3380 fract = dblIn - whole;
3382 if (fract > 0.5)
3383 dblIn = whole + 1.0;
3384 else if (fract == 0.5)
3385 dblIn = whole + fmod(whole, 2.0);
3386 else if (fract >= 0.0)
3387 dblIn = whole;
3388 else if (fract == -0.5)
3389 dblIn = whole - fmod(whole, 2.0);
3390 else if (fract > -0.5)
3391 dblIn = whole;
3392 else
3393 dblIn = whole - 1.0;
3395 *pDblOut = dblIn / scale;
3396 return S_OK;
3399 /* CY
3402 /* Powers of 10 from 0..4 D.P. */
3403 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3404 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3406 /************************************************************************
3407 * VarCyFromUI1 (OLEAUT32.98)
3409 * Convert a VT_UI1 to a VT_CY.
3411 * PARAMS
3412 * bIn [I] Source
3413 * pCyOut [O] Destination
3415 * RETURNS
3416 * Success: S_OK.
3417 * Failure: E_INVALIDARG, if the source value is invalid
3418 * DISP_E_OVERFLOW, if the value will not fit in the destination
3419 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3421 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3423 pCyOut->int64 = (ULONG64)bIn * CY_MULTIPLIER;
3424 return S_OK;
3427 /************************************************************************
3428 * VarCyFromI2 (OLEAUT32.99)
3430 * Convert a VT_I2 to a VT_CY.
3432 * PARAMS
3433 * sIn [I] Source
3434 * pCyOut [O] Destination
3436 * RETURNS
3437 * Success: S_OK.
3438 * Failure: E_INVALIDARG, if the source value is invalid
3439 * DISP_E_OVERFLOW, if the value will not fit in the destination
3440 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3442 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3444 pCyOut->int64 = (LONG64)sIn * CY_MULTIPLIER;
3445 return S_OK;
3448 /************************************************************************
3449 * VarCyFromI4 (OLEAUT32.100)
3451 * Convert a VT_I4 to a VT_CY.
3453 * PARAMS
3454 * sIn [I] Source
3455 * pCyOut [O] Destination
3457 * RETURNS
3458 * Success: S_OK.
3459 * Failure: E_INVALIDARG, if the source value is invalid
3460 * DISP_E_OVERFLOW, if the value will not fit in the destination
3461 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3463 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3465 pCyOut->int64 = (LONG64)lIn * CY_MULTIPLIER;
3466 return S_OK;
3469 /************************************************************************
3470 * VarCyFromR4 (OLEAUT32.101)
3472 * Convert a VT_R4 to a VT_CY.
3474 * PARAMS
3475 * fltIn [I] Source
3476 * pCyOut [O] Destination
3478 * RETURNS
3479 * Success: S_OK.
3480 * Failure: E_INVALIDARG, if the source value is invalid
3481 * DISP_E_OVERFLOW, if the value will not fit in the destination
3482 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3484 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3486 return VarCyFromR8(fltIn, pCyOut);
3489 /************************************************************************
3490 * VarCyFromR8 (OLEAUT32.102)
3492 * Convert a VT_R8 to a VT_CY.
3494 * PARAMS
3495 * dblIn [I] Source
3496 * pCyOut [O] Destination
3498 * RETURNS
3499 * Success: S_OK.
3500 * Failure: E_INVALIDARG, if the source value is invalid
3501 * DISP_E_OVERFLOW, if the value will not fit in the destination
3502 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3504 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3506 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3507 /* This code gives identical results to Win32 on Intel.
3508 * Here we use fp exceptions to catch overflows when storing the value.
3510 static const unsigned short r8_fpcontrol = 0x137f;
3511 static const double r8_multiplier = CY_MULTIPLIER_F;
3512 unsigned short old_fpcontrol, result_fpstatus;
3514 /* Clear exceptions, save the old fp state and load the new state */
3515 __asm__ __volatile__( "fnclex" );
3516 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3517 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3518 /* Perform the conversion. */
3519 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3520 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3521 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3522 /* Save the resulting fp state, load the old state and clear exceptions */
3523 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3524 __asm__ __volatile__( "fnclex" );
3525 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3527 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3528 return DISP_E_OVERFLOW;
3529 #else
3530 /* This version produces slightly different results for boundary cases */
3531 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3532 return DISP_E_OVERFLOW;
3533 dblIn *= CY_MULTIPLIER_F;
3534 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3535 #endif
3536 return S_OK;
3539 /************************************************************************
3540 * VarCyFromDate (OLEAUT32.103)
3542 * Convert a VT_DATE to a VT_CY.
3544 * PARAMS
3545 * dateIn [I] Source
3546 * pCyOut [O] Destination
3548 * RETURNS
3549 * Success: S_OK.
3550 * Failure: E_INVALIDARG, if the source value is invalid
3551 * DISP_E_OVERFLOW, if the value will not fit in the destination
3552 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3554 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3556 return VarCyFromR8(dateIn, pCyOut);
3559 /************************************************************************
3560 * VarCyFromStr (OLEAUT32.104)
3562 * Convert a VT_BSTR to a VT_CY.
3564 * PARAMS
3565 * strIn [I] Source
3566 * lcid [I] LCID for the conversion
3567 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3568 * pCyOut [O] Destination
3570 * RETURNS
3571 * Success: S_OK.
3572 * Failure: E_INVALIDARG, if the source value is invalid
3573 * DISP_E_OVERFLOW, if the value will not fit in the destination
3574 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3576 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3578 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3581 /************************************************************************
3582 * VarCyFromDisp (OLEAUT32.105)
3584 * Convert a VT_DISPATCH to a VT_CY.
3586 * PARAMS
3587 * pdispIn [I] Source
3588 * lcid [I] LCID for conversion
3589 * pCyOut [O] Destination
3591 * RETURNS
3592 * Success: S_OK.
3593 * Failure: E_INVALIDARG, if the source value is invalid
3594 * DISP_E_OVERFLOW, if the value will not fit in the destination
3595 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3597 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3599 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0);
3602 /************************************************************************
3603 * VarCyFromBool (OLEAUT32.106)
3605 * Convert a VT_BOOL to a VT_CY.
3607 * PARAMS
3608 * boolIn [I] Source
3609 * pCyOut [O] Destination
3611 * RETURNS
3612 * Success: S_OK.
3613 * Failure: E_INVALIDARG, if the source value is invalid
3614 * DISP_E_OVERFLOW, if the value will not fit in the destination
3615 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3617 * NOTES
3618 * While the sign of the boolean is stored in the currency, the value is
3619 * converted to either 0 or 1.
3621 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3623 pCyOut->int64 = (LONG64)boolIn * CY_MULTIPLIER;
3624 return S_OK;
3627 /************************************************************************
3628 * VarCyFromI1 (OLEAUT32.225)
3630 * Convert a VT_I1 to a VT_CY.
3632 * PARAMS
3633 * cIn [I] Source
3634 * pCyOut [O] Destination
3636 * RETURNS
3637 * Success: S_OK.
3638 * Failure: E_INVALIDARG, if the source value is invalid
3639 * DISP_E_OVERFLOW, if the value will not fit in the destination
3640 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3642 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3644 pCyOut->int64 = (LONG64)cIn * CY_MULTIPLIER;
3645 return S_OK;
3648 /************************************************************************
3649 * VarCyFromUI2 (OLEAUT32.226)
3651 * Convert a VT_UI2 to a VT_CY.
3653 * PARAMS
3654 * usIn [I] Source
3655 * pCyOut [O] Destination
3657 * RETURNS
3658 * Success: S_OK.
3659 * Failure: E_INVALIDARG, if the source value is invalid
3660 * DISP_E_OVERFLOW, if the value will not fit in the destination
3661 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3663 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3665 pCyOut->int64 = (ULONG64)usIn * CY_MULTIPLIER;
3666 return S_OK;
3669 /************************************************************************
3670 * VarCyFromUI4 (OLEAUT32.227)
3672 * Convert a VT_UI4 to a VT_CY.
3674 * PARAMS
3675 * ulIn [I] Source
3676 * pCyOut [O] Destination
3678 * RETURNS
3679 * Success: S_OK.
3680 * Failure: E_INVALIDARG, if the source value is invalid
3681 * DISP_E_OVERFLOW, if the value will not fit in the destination
3682 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3684 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3686 pCyOut->int64 = (ULONG64)ulIn * CY_MULTIPLIER;
3687 return S_OK;
3690 /************************************************************************
3691 * VarCyFromDec (OLEAUT32.228)
3693 * Convert a VT_DECIMAL to a VT_CY.
3695 * PARAMS
3696 * pdecIn [I] Source
3697 * pCyOut [O] Destination
3699 * RETURNS
3700 * Success: S_OK.
3701 * Failure: E_INVALIDARG, if the source value is invalid
3702 * DISP_E_OVERFLOW, if the value will not fit in the destination
3703 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3705 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
3707 DECIMAL rounded;
3708 HRESULT hRet;
3710 hRet = VarDecRound(pdecIn, 4, &rounded);
3712 if (SUCCEEDED(hRet))
3714 double d;
3716 if (DEC_HI32(&rounded))
3717 return DISP_E_OVERFLOW;
3719 /* Note: Without the casts this promotes to int64 which loses precision */
3720 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3721 if (DEC_SIGN(&rounded))
3722 d = -d;
3723 return VarCyFromR8(d, pCyOut);
3725 return hRet;
3728 /************************************************************************
3729 * VarCyFromI8 (OLEAUT32.366)
3731 * Convert a VT_I8 to a VT_CY.
3733 * PARAMS
3734 * ullIn [I] Source
3735 * pCyOut [O] Destination
3737 * RETURNS
3738 * Success: S_OK.
3739 * Failure: E_INVALIDARG, if the source value is invalid
3740 * DISP_E_OVERFLOW, if the value will not fit in the destination
3741 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3743 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3745 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3746 pCyOut->int64 = llIn * CY_MULTIPLIER;
3747 return S_OK;
3750 /************************************************************************
3751 * VarCyFromUI8 (OLEAUT32.375)
3753 * Convert a VT_UI8 to a VT_CY.
3755 * PARAMS
3756 * ullIn [I] Source
3757 * pCyOut [O] Destination
3759 * RETURNS
3760 * Success: S_OK.
3761 * Failure: E_INVALIDARG, if the source value is invalid
3762 * DISP_E_OVERFLOW, if the value will not fit in the destination
3763 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3765 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3767 if (ullIn > (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3768 pCyOut->int64 = ullIn * CY_MULTIPLIER;
3769 return S_OK;
3772 /************************************************************************
3773 * VarCyAdd (OLEAUT32.299)
3775 * Add one CY to another.
3777 * PARAMS
3778 * cyLeft [I] Source
3779 * cyRight [I] Value to add
3780 * pCyOut [O] Destination
3782 * RETURNS
3783 * Success: S_OK.
3784 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3786 HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut)
3788 double l,r;
3789 _VarR8FromCy(cyLeft, &l);
3790 _VarR8FromCy(cyRight, &r);
3791 l = l + r;
3792 return VarCyFromR8(l, pCyOut);
3795 /************************************************************************
3796 * VarCyMul (OLEAUT32.303)
3798 * Multiply one CY by another.
3800 * PARAMS
3801 * cyLeft [I] Source
3802 * cyRight [I] Value to multiply by
3803 * pCyOut [O] Destination
3805 * RETURNS
3806 * Success: S_OK.
3807 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3809 HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut)
3811 double l,r;
3812 _VarR8FromCy(cyLeft, &l);
3813 _VarR8FromCy(cyRight, &r);
3814 l = l * r;
3815 return VarCyFromR8(l, pCyOut);
3818 /************************************************************************
3819 * VarCyMulI4 (OLEAUT32.304)
3821 * Multiply one CY by a VT_I4.
3823 * PARAMS
3824 * cyLeft [I] Source
3825 * lRight [I] Value to multiply by
3826 * pCyOut [O] Destination
3828 * RETURNS
3829 * Success: S_OK.
3830 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3832 HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut)
3834 double d;
3836 _VarR8FromCy(cyLeft, &d);
3837 d = d * lRight;
3838 return VarCyFromR8(d, pCyOut);
3841 /************************************************************************
3842 * VarCySub (OLEAUT32.305)
3844 * Subtract one CY from another.
3846 * PARAMS
3847 * cyLeft [I] Source
3848 * cyRight [I] Value to subtract
3849 * pCyOut [O] Destination
3851 * RETURNS
3852 * Success: S_OK.
3853 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3855 HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut)
3857 double l,r;
3858 _VarR8FromCy(cyLeft, &l);
3859 _VarR8FromCy(cyRight, &r);
3860 l = l - r;
3861 return VarCyFromR8(l, pCyOut);
3864 /************************************************************************
3865 * VarCyAbs (OLEAUT32.306)
3867 * Convert a VT_CY into its absolute value.
3869 * PARAMS
3870 * cyIn [I] Source
3871 * pCyOut [O] Destination
3873 * RETURNS
3874 * Success: S_OK. pCyOut contains the absolute value.
3875 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3877 HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut)
3879 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3880 return DISP_E_OVERFLOW;
3882 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3883 return S_OK;
3886 /************************************************************************
3887 * VarCyFix (OLEAUT32.307)
3889 * Return the integer part of a VT_CY.
3891 * PARAMS
3892 * cyIn [I] Source
3893 * pCyOut [O] Destination
3895 * RETURNS
3896 * Success: S_OK.
3897 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3899 * NOTES
3900 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3901 * negative numbers away from 0, while this function rounds them towards zero.
3903 HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut)
3905 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3906 pCyOut->int64 *= CY_MULTIPLIER;
3907 return S_OK;
3910 /************************************************************************
3911 * VarCyInt (OLEAUT32.308)
3913 * Return the integer part of a VT_CY.
3915 * PARAMS
3916 * cyIn [I] Source
3917 * pCyOut [O] Destination
3919 * RETURNS
3920 * Success: S_OK.
3921 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3923 * NOTES
3924 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3925 * negative numbers towards 0, while this function rounds them away from zero.
3927 HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut)
3929 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3930 pCyOut->int64 *= CY_MULTIPLIER;
3932 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3934 pCyOut->int64 -= CY_MULTIPLIER;
3936 return S_OK;
3939 /************************************************************************
3940 * VarCyNeg (OLEAUT32.309)
3942 * Change the sign of a VT_CY.
3944 * PARAMS
3945 * cyIn [I] Source
3946 * pCyOut [O] Destination
3948 * RETURNS
3949 * Success: S_OK.
3950 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3952 HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut)
3954 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3955 return DISP_E_OVERFLOW;
3957 pCyOut->int64 = -cyIn.int64;
3958 return S_OK;
3961 /************************************************************************
3962 * VarCyRound (OLEAUT32.310)
3964 * Change the precision of a VT_CY.
3966 * PARAMS
3967 * cyIn [I] Source
3968 * cDecimals [I] New number of decimals to keep
3969 * pCyOut [O] Destination
3971 * RETURNS
3972 * Success: S_OK.
3973 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3975 HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
3977 if (cDecimals < 0)
3978 return E_INVALIDARG;
3980 if (cDecimals > 3)
3982 /* Rounding to more precision than we have */
3983 *pCyOut = cyIn;
3984 return S_OK;
3986 else
3988 double d, div = CY_Divisors[cDecimals];
3990 _VarR8FromCy(cyIn, &d);
3991 d = d * div;
3992 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3993 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3994 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3995 return S_OK;
3999 /************************************************************************
4000 * VarCyCmp (OLEAUT32.311)
4002 * Compare two VT_CY values.
4004 * PARAMS
4005 * cyLeft [I] Source
4006 * cyRight [I] Value to compare
4008 * RETURNS
4009 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4010 * compare is less, equal or greater than source respectively.
4011 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4013 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
4015 HRESULT hRet;
4016 CY result;
4018 /* Subtract right from left, and compare the result to 0 */
4019 hRet = VarCySub(cyLeft, cyRight, &result);
4021 if (SUCCEEDED(hRet))
4023 if (result.int64 < 0)
4024 hRet = (HRESULT)VARCMP_LT;
4025 else if (result.int64 > 0)
4026 hRet = (HRESULT)VARCMP_GT;
4027 else
4028 hRet = (HRESULT)VARCMP_EQ;
4030 return hRet;
4033 /************************************************************************
4034 * VarCyCmpR8 (OLEAUT32.312)
4036 * Compare a VT_CY to a double
4038 * PARAMS
4039 * cyLeft [I] Currency Source
4040 * dblRight [I] double to compare to cyLeft
4042 * RETURNS
4043 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4044 * less than, equal to or greater than cyLeft respectively.
4045 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4047 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight)
4049 HRESULT hRet;
4050 CY cyRight;
4052 hRet = VarCyFromR8(dblRight, &cyRight);
4054 if (SUCCEEDED(hRet))
4055 hRet = VarCyCmp(cyLeft, cyRight);
4057 return hRet;
4060 /************************************************************************
4061 * VarCyMulI8 (OLEAUT32.329)
4063 * Multiply a VT_CY by a VT_I8.
4065 * PARAMS
4066 * cyLeft [I] Source
4067 * llRight [I] Value to multiply by
4068 * pCyOut [O] Destination
4070 * RETURNS
4071 * Success: S_OK.
4072 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4074 HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
4076 double d;
4078 _VarR8FromCy(cyLeft, &d);
4079 d = d * (double)llRight;
4080 return VarCyFromR8(d, pCyOut);
4083 /* DECIMAL
4086 /************************************************************************
4087 * VarDecFromUI1 (OLEAUT32.190)
4089 * Convert a VT_UI1 to a DECIMAL.
4091 * PARAMS
4092 * bIn [I] Source
4093 * pDecOut [O] Destination
4095 * RETURNS
4096 * S_OK.
4098 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4100 return VarDecFromUI4(bIn, pDecOut);
4103 /************************************************************************
4104 * VarDecFromI2 (OLEAUT32.191)
4106 * Convert a VT_I2 to a DECIMAL.
4108 * PARAMS
4109 * sIn [I] Source
4110 * pDecOut [O] Destination
4112 * RETURNS
4113 * S_OK.
4115 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4117 return VarDecFromI4(sIn, pDecOut);
4120 /************************************************************************
4121 * VarDecFromI4 (OLEAUT32.192)
4123 * Convert a VT_I4 to a DECIMAL.
4125 * PARAMS
4126 * sIn [I] Source
4127 * pDecOut [O] Destination
4129 * RETURNS
4130 * S_OK.
4132 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4134 DEC_HI32(pDecOut) = 0;
4135 DEC_MID32(pDecOut) = 0;
4137 if (lIn < 0)
4139 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4140 DEC_LO32(pDecOut) = -lIn;
4142 else
4144 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4145 DEC_LO32(pDecOut) = lIn;
4147 return S_OK;
4150 #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT))
4152 /* internal representation of the value stored in a DECIMAL. The bytes are
4153 stored from LSB at index 0 to MSB at index 11
4155 typedef struct DECIMAL_internal
4157 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4158 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4159 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4160 } VARIANT_DI;
4162 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest);
4163 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest);
4164 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to);
4165 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to);
4167 /************************************************************************
4168 * VarDecFromR4 (OLEAUT32.193)
4170 * Convert a VT_R4 to a DECIMAL.
4172 * PARAMS
4173 * fltIn [I] Source
4174 * pDecOut [O] Destination
4176 * RETURNS
4177 * S_OK.
4179 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4181 VARIANT_DI di;
4182 HRESULT hres;
4184 hres = VARIANT_DI_FromR4(fltIn, &di);
4185 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4186 return hres;
4189 /************************************************************************
4190 * VarDecFromR8 (OLEAUT32.194)
4192 * Convert a VT_R8 to a DECIMAL.
4194 * PARAMS
4195 * dblIn [I] Source
4196 * pDecOut [O] Destination
4198 * RETURNS
4199 * S_OK.
4201 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4203 VARIANT_DI di;
4204 HRESULT hres;
4206 hres = VARIANT_DI_FromR8(dblIn, &di);
4207 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4208 return hres;
4211 /************************************************************************
4212 * VarDecFromDate (OLEAUT32.195)
4214 * Convert a VT_DATE to a DECIMAL.
4216 * PARAMS
4217 * dateIn [I] Source
4218 * pDecOut [O] Destination
4220 * RETURNS
4221 * S_OK.
4223 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4225 return VarDecFromR8(dateIn, pDecOut);
4228 /************************************************************************
4229 * VarDecFromCy (OLEAUT32.196)
4231 * Convert a VT_CY to a DECIMAL.
4233 * PARAMS
4234 * cyIn [I] Source
4235 * pDecOut [O] Destination
4237 * RETURNS
4238 * S_OK.
4240 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4242 DEC_HI32(pDecOut) = 0;
4244 /* Note: This assumes 2s complement integer representation */
4245 if (cyIn.s.Hi & 0x80000000)
4247 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4248 DEC_LO64(pDecOut) = -cyIn.int64;
4250 else
4252 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4253 DEC_MID32(pDecOut) = cyIn.s.Hi;
4254 DEC_LO32(pDecOut) = cyIn.s.Lo;
4256 return S_OK;
4259 /************************************************************************
4260 * VarDecFromStr (OLEAUT32.197)
4262 * Convert a VT_BSTR to a DECIMAL.
4264 * PARAMS
4265 * strIn [I] Source
4266 * lcid [I] LCID for the conversion
4267 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4268 * pDecOut [O] Destination
4270 * RETURNS
4271 * Success: S_OK.
4272 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4274 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4276 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4279 /************************************************************************
4280 * VarDecFromDisp (OLEAUT32.198)
4282 * Convert a VT_DISPATCH to a DECIMAL.
4284 * PARAMS
4285 * pdispIn [I] Source
4286 * lcid [I] LCID for conversion
4287 * pDecOut [O] Destination
4289 * RETURNS
4290 * Success: S_OK.
4291 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4293 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4295 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0);
4298 /************************************************************************
4299 * VarDecFromBool (OLEAUT32.199)
4301 * Convert a VT_BOOL to a DECIMAL.
4303 * PARAMS
4304 * bIn [I] Source
4305 * pDecOut [O] Destination
4307 * RETURNS
4308 * S_OK.
4310 * NOTES
4311 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4313 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4315 DEC_HI32(pDecOut) = 0;
4316 DEC_MID32(pDecOut) = 0;
4317 if (bIn)
4319 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4320 DEC_LO32(pDecOut) = 1;
4322 else
4324 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4325 DEC_LO32(pDecOut) = 0;
4327 return S_OK;
4330 /************************************************************************
4331 * VarDecFromI1 (OLEAUT32.241)
4333 * Convert a VT_I1 to a DECIMAL.
4335 * PARAMS
4336 * cIn [I] Source
4337 * pDecOut [O] Destination
4339 * RETURNS
4340 * S_OK.
4342 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4344 return VarDecFromI4(cIn, pDecOut);
4347 /************************************************************************
4348 * VarDecFromUI2 (OLEAUT32.242)
4350 * Convert a VT_UI2 to a DECIMAL.
4352 * PARAMS
4353 * usIn [I] Source
4354 * pDecOut [O] Destination
4356 * RETURNS
4357 * S_OK.
4359 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4361 return VarDecFromUI4(usIn, pDecOut);
4364 /************************************************************************
4365 * VarDecFromUI4 (OLEAUT32.243)
4367 * Convert a VT_UI4 to a DECIMAL.
4369 * PARAMS
4370 * ulIn [I] Source
4371 * pDecOut [O] Destination
4373 * RETURNS
4374 * S_OK.
4376 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4378 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4379 DEC_HI32(pDecOut) = 0;
4380 DEC_MID32(pDecOut) = 0;
4381 DEC_LO32(pDecOut) = ulIn;
4382 return S_OK;
4385 /************************************************************************
4386 * VarDecFromI8 (OLEAUT32.374)
4388 * Convert a VT_I8 to a DECIMAL.
4390 * PARAMS
4391 * llIn [I] Source
4392 * pDecOut [O] Destination
4394 * RETURNS
4395 * S_OK.
4397 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4399 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4401 DEC_HI32(pDecOut) = 0;
4403 /* Note: This assumes 2s complement integer representation */
4404 if (pLi->u.HighPart & 0x80000000)
4406 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4407 DEC_LO64(pDecOut) = -pLi->QuadPart;
4409 else
4411 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4412 DEC_MID32(pDecOut) = pLi->u.HighPart;
4413 DEC_LO32(pDecOut) = pLi->u.LowPart;
4415 return S_OK;
4418 /************************************************************************
4419 * VarDecFromUI8 (OLEAUT32.375)
4421 * Convert a VT_UI8 to a DECIMAL.
4423 * PARAMS
4424 * ullIn [I] Source
4425 * pDecOut [O] Destination
4427 * RETURNS
4428 * S_OK.
4430 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4432 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4433 DEC_HI32(pDecOut) = 0;
4434 DEC_LO64(pDecOut) = ullIn;
4435 return S_OK;
4438 /* Make two DECIMALS the same scale; used by math functions below */
4439 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4440 const DECIMAL** ppDecRight,
4441 DECIMAL* pDecOut)
4443 static DECIMAL scaleFactor;
4444 DECIMAL decTemp;
4445 int scaleAmount, i;
4446 HRESULT hRet = S_OK;
4448 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4449 return E_INVALIDARG;
4451 DEC_LO32(&scaleFactor) = 10;
4453 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4455 if (!scaleAmount)
4456 return S_OK; /* Same scale */
4458 if (scaleAmount > 0)
4460 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4461 *ppDecRight = pDecOut;
4463 else
4465 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4466 *ppDecLeft = pDecOut;
4467 i = scaleAmount = -scaleAmount;
4470 if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE)
4471 return DISP_E_OVERFLOW; /* Can't scale up */
4473 /* Multiply up the value to be scaled by the correct amount */
4474 while (SUCCEEDED(hRet) && i--)
4476 /* Note we are multiplying by a value with a scale of 0, so we don't recurse */
4477 hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut);
4478 decTemp = *pDecOut;
4480 DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */
4481 return hRet;
4484 /* Add two unsigned 32 bit values with overflow */
4485 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4487 ULARGE_INTEGER ul64;
4489 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4490 *pulHigh = ul64.u.HighPart;
4491 return ul64.u.LowPart;
4494 /* Subtract two unsigned 32 bit values with underflow */
4495 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4497 int invert = 0;
4498 ULARGE_INTEGER ul64;
4500 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4501 if (ulLeft < ulRight)
4502 invert = 1;
4504 if (ul64.QuadPart > (ULONG64)*pulHigh)
4505 ul64.QuadPart -= (ULONG64)*pulHigh;
4506 else
4508 ul64.QuadPart -= (ULONG64)*pulHigh;
4509 invert = 1;
4511 if (invert)
4512 ul64.u.HighPart = -ul64.u.HighPart ;
4514 *pulHigh = ul64.u.HighPart;
4515 return ul64.u.LowPart;
4518 /* Multiply two unsigned 32 bit values with overflow */
4519 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4521 ULARGE_INTEGER ul64;
4523 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4524 *pulHigh = ul64.u.HighPart;
4525 return ul64.u.LowPart;
4528 /* Compare two decimals that have the same scale */
4529 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4531 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4532 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4533 return -1;
4534 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4535 return 0;
4536 return 1;
4539 /************************************************************************
4540 * VarDecAdd (OLEAUT32.177)
4542 * Add one DECIMAL to another.
4544 * PARAMS
4545 * pDecLeft [I] Source
4546 * pDecRight [I] Value to add
4547 * pDecOut [O] Destination
4549 * RETURNS
4550 * Success: S_OK.
4551 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4553 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4555 HRESULT hRet;
4556 DECIMAL scaled;
4558 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled);
4560 if (SUCCEEDED(hRet))
4562 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4563 ULONG overflow = 0;
4564 BYTE sign = DECIMAL_POS;
4565 int cmp;
4567 /* Correct for the sign of the result */
4568 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4570 /* -x + -y : Negative */
4571 sign = DECIMAL_NEG;
4572 goto VarDecAdd_AsPositive;
4574 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4576 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4578 /* -x + y : Negative if x > y */
4579 if (cmp > 0)
4581 sign = DECIMAL_NEG;
4582 VarDecAdd_AsNegative:
4583 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4584 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4585 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4587 else
4589 VarDecAdd_AsInvertedNegative:
4590 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4591 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4592 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4595 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4597 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4599 /* x + -y : Negative if x <= y */
4600 if (cmp <= 0)
4602 sign = DECIMAL_NEG;
4603 goto VarDecAdd_AsInvertedNegative;
4605 goto VarDecAdd_AsNegative;
4607 else
4609 /* x + y : Positive */
4610 VarDecAdd_AsPositive:
4611 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4612 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4613 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4616 if (overflow)
4617 return DISP_E_OVERFLOW; /* overflowed */
4619 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4620 DEC_SIGN(pDecOut) = sign;
4622 return hRet;
4625 /* translate from external DECIMAL format into an internal representation */
4626 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4628 to->scale = DEC_SCALE(from);
4629 to->sign = DEC_SIGN(from) ? 1 : 0;
4631 to->bitsnum[0] = DEC_LO32(from);
4632 to->bitsnum[1] = DEC_MID32(from);
4633 to->bitsnum[2] = DEC_HI32(from);
4636 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to)
4638 if (from->sign) {
4639 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4640 } else {
4641 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4644 DEC_LO32(to) = from->bitsnum[0];
4645 DEC_MID32(to) = from->bitsnum[1];
4646 DEC_HI32(to) = from->bitsnum[2];
4649 /* clear an internal representation of a DECIMAL */
4650 static void VARIANT_DI_clear(VARIANT_DI * i)
4652 memset(i, 0, sizeof(VARIANT_DI));
4655 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4656 size is supported. The value in p is replaced by the quotient of the division, and
4657 the remainder is returned as a result. This routine is most often used with a divisor
4658 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4660 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4662 if (divisor == 0) {
4663 /* division by 0 */
4664 return 0xFF;
4665 } else if (divisor == 1) {
4666 /* dividend remains unchanged */
4667 return 0;
4668 } else {
4669 unsigned char remainder = 0;
4670 ULONGLONG iTempDividend;
4671 signed int i;
4673 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4674 for (; i >= 0; i--) {
4675 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4676 remainder = iTempDividend % divisor;
4677 p[i] = iTempDividend / divisor;
4680 return remainder;
4684 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4685 static int VARIANT_int_iszero(const DWORD * p, unsigned int n)
4687 for (; n > 0; n--) if (*p++ != 0) return 0;
4688 return 1;
4691 /* multiply two DECIMALS, without changing either one, and place result in third
4692 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4693 digits when scale > 0 in order to fit an overflowing result. Final overflow
4694 flag is returned.
4696 static int VARIANT_DI_mul(const VARIANT_DI * a, const VARIANT_DI * b, VARIANT_DI * result)
4698 int r_overflow = 0;
4699 DWORD running[6];
4700 signed int mulstart;
4702 VARIANT_DI_clear(result);
4703 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4705 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4706 of the result is formed by adding the scales of the operands.
4708 result->scale = a->scale + b->scale;
4709 memset(running, 0, sizeof(running));
4711 /* count number of leading zero-bytes in operand A */
4712 for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4713 if (mulstart < 0) {
4714 /* result is 0, because operand A is 0 */
4715 result->scale = 0;
4716 result->sign = 0;
4717 } else {
4718 unsigned char remainder = 0;
4719 int iA;
4721 /* perform actual multiplication */
4722 for (iA = 0; iA <= mulstart; iA++) {
4723 ULONG iOverflowMul;
4724 int iB;
4726 for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
4727 ULONG iRV;
4728 int iR;
4730 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4731 iR = iA + iB;
4732 do {
4733 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4734 iR++;
4735 } while (iRV);
4739 /* Too bad - native oleaut does not do this, so we should not either */
4740 #if 0
4741 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4742 This operation should not lose significant digits, and gives an
4743 opportunity to reduce the possibility of overflows in future
4744 operations issued by the application.
4746 while (result->scale > 0) {
4747 memcpy(quotient, running, sizeof(quotient));
4748 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4749 if (remainder > 0) break;
4750 memcpy(running, quotient, sizeof(quotient));
4751 result->scale--;
4753 #endif
4754 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4755 This operation *will* lose significant digits of the result because
4756 all the factors of 10 were consumed by the previous operation.
4758 while (result->scale > 0 && !VARIANT_int_iszero(
4759 running + sizeof(result->bitsnum) / sizeof(DWORD),
4760 (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
4762 remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
4763 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4764 result->scale--;
4767 /* round up the result - native oleaut32 does this */
4768 if (remainder >= 5) {
4769 unsigned int i;
4770 for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
4771 ULONGLONG digit = running[i] + 1;
4772 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4773 running[i] = digit & 0xFFFFFFFF;
4777 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4778 and copy result bits into result structure
4780 r_overflow = !VARIANT_int_iszero(
4781 running + sizeof(result->bitsnum)/sizeof(DWORD),
4782 (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
4783 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4785 return r_overflow;
4788 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4789 hardcoded (period for decimal separator, dash as negative sign). Returns 0 for
4790 success, nonzero if insufficient space in output buffer.
4792 static int VARIANT_DI_tostringW(const VARIANT_DI * a, WCHAR * s, unsigned int n)
4794 int overflow = 0;
4795 DWORD quotient[3];
4796 unsigned char remainder;
4797 unsigned int i;
4799 /* place negative sign */
4800 if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
4801 if (n > 0) {
4802 *s++ = '-';
4803 n--;
4805 else overflow = 1;
4808 /* prepare initial 0 */
4809 if (!overflow) {
4810 if (n >= 2) {
4811 s[0] = '0';
4812 s[1] = '\0';
4813 } else overflow = 1;
4816 i = 0;
4817 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4818 while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
4819 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4820 if (i + 2 > n) {
4821 overflow = 1;
4822 } else {
4823 s[i++] = '0' + remainder;
4824 s[i] = '\0';
4828 if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
4830 /* reverse order of digits */
4831 WCHAR * x = s; WCHAR * y = s + i - 1;
4832 while (x < y) {
4833 *x ^= *y;
4834 *y ^= *x;
4835 *x++ ^= *y--;
4838 /* check for decimal point. "i" now has string length */
4839 if (i <= a->scale) {
4840 unsigned int numzeroes = a->scale + 1 - i;
4841 if (i + 1 + numzeroes >= n) {
4842 overflow = 1;
4843 } else {
4844 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4845 i += numzeroes;
4846 while (numzeroes > 0) {
4847 s[--numzeroes] = '0';
4852 /* place decimal point */
4853 if (a->scale > 0) {
4854 unsigned int periodpos = i - a->scale;
4855 if (i + 2 >= n) {
4856 overflow = 1;
4857 } else {
4858 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4859 s[periodpos] = '.'; i++;
4861 /* remove extra zeros at the end, if any */
4862 while (s[i - 1] == '0') s[--i] = '\0';
4863 if (s[i - 1] == '.') s[--i] = '\0';
4868 return overflow;
4871 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4872 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4874 DWORD shifted;
4875 unsigned int i;
4877 /* shift whole DWORDs to the left */
4878 while (shift >= 32)
4880 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4881 *p = 0; shift -= 32;
4884 /* shift remainder (1..31 bits) */
4885 shifted = 0;
4886 if (shift > 0) for (i = 0; i < n; i++)
4888 DWORD b;
4889 b = p[i] >> (32 - shift);
4890 p[i] = (p[i] << shift) | shifted;
4891 shifted = b;
4895 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4896 Value at v is incremented by the value at p. Any size is supported, provided
4897 that v is not shorter than p. Any unapplied carry is returned as a result.
4899 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, const DWORD * p,
4900 unsigned int np)
4902 unsigned char carry = 0;
4904 if (nv >= np) {
4905 ULONGLONG sum;
4906 unsigned int i;
4908 for (i = 0; i < np; i++) {
4909 sum = (ULONGLONG)v[i]
4910 + (ULONGLONG)p[i]
4911 + (ULONGLONG)carry;
4912 v[i] = sum & 0xffffffff;
4913 carry = sum >> 32;
4915 for (; i < nv && carry; i++) {
4916 sum = (ULONGLONG)v[i]
4917 + (ULONGLONG)carry;
4918 v[i] = sum & 0xffffffff;
4919 carry = sum >> 32;
4922 return carry;
4925 /* perform integral division with operand p as dividend. Parameter n indicates
4926 number of available DWORDs in divisor p, but available space in p must be
4927 actually at least 2 * n DWORDs, because the remainder of the integral
4928 division is built in the next n DWORDs past the start of the quotient. This
4929 routine replaces the dividend in p with the quotient, and appends n
4930 additional DWORDs for the remainder.
4932 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4933 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4934 source code to the VLI (Very Large Integer) division operator. This algorithm
4935 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4936 variably-scaled integers such as the MS DECIMAL representation.
4938 static void VARIANT_int_div(DWORD * p, unsigned int n, const DWORD * divisor,
4939 unsigned int dn)
4941 unsigned int i;
4942 DWORD tempsub[8];
4943 DWORD * negdivisor = tempsub + n;
4945 /* build 2s-complement of divisor */
4946 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
4947 p[n] = 1;
4948 VARIANT_int_add(negdivisor, n, p + n, 1);
4949 memset(p + n, 0, n * sizeof(DWORD));
4951 /* skip all leading zero DWORDs in quotient */
4952 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
4953 /* i is now number of DWORDs left to process */
4954 for (i <<= 5; i < (n << 5); i++) {
4955 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
4957 /* trial subtraction */
4958 memcpy(tempsub, p + n, n * sizeof(DWORD));
4959 VARIANT_int_add(tempsub, n, negdivisor, n);
4961 /* check whether result of subtraction was negative */
4962 if ((tempsub[n - 1] & 0x80000000) == 0) {
4963 memcpy(p + n, tempsub, n * sizeof(DWORD));
4964 p[0] |= 1;
4969 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4970 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
4972 unsigned int i;
4973 ULONG iOverflowMul;
4975 for (iOverflowMul = 0, i = 0; i < n; i++)
4976 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
4977 return (unsigned char)iOverflowMul;
4980 /* increment value in A by the value indicated in B, with scale adjusting.
4981 Modifies parameters by adjusting scales. Returns 0 if addition was
4982 successful, nonzero if a parameter underflowed before it could be
4983 successfully used in the addition.
4985 static int VARIANT_int_addlossy(
4986 DWORD * a, int * ascale, unsigned int an,
4987 DWORD * b, int * bscale, unsigned int bn)
4989 int underflow = 0;
4991 if (VARIANT_int_iszero(a, an)) {
4992 /* if A is zero, copy B into A, after removing digits */
4993 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
4994 VARIANT_int_divbychar(b, bn, 10);
4995 (*bscale)--;
4997 memcpy(a, b, an * sizeof(DWORD));
4998 *ascale = *bscale;
4999 } else if (!VARIANT_int_iszero(b, bn)) {
5000 unsigned int tn = an + 1;
5001 DWORD t[5];
5003 if (bn + 1 > tn) tn = bn + 1;
5004 if (*ascale != *bscale) {
5005 /* first (optimistic) try - try to scale down the one with the bigger
5006 scale, while this number is divisible by 10 */
5007 DWORD * digitchosen;
5008 unsigned int nchosen;
5009 int * scalechosen;
5010 int targetscale;
5012 if (*ascale < *bscale) {
5013 targetscale = *ascale;
5014 scalechosen = bscale;
5015 digitchosen = b;
5016 nchosen = bn;
5017 } else {
5018 targetscale = *bscale;
5019 scalechosen = ascale;
5020 digitchosen = a;
5021 nchosen = an;
5023 memset(t, 0, tn * sizeof(DWORD));
5024 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5026 /* divide by 10 until target scale is reached */
5027 while (*scalechosen > targetscale) {
5028 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5029 if (!remainder) {
5030 (*scalechosen)--;
5031 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5032 } else break;
5036 if (*ascale != *bscale) {
5037 DWORD * digitchosen;
5038 unsigned int nchosen;
5039 int * scalechosen;
5040 int targetscale;
5042 /* try to scale up the one with the smaller scale */
5043 if (*ascale > *bscale) {
5044 targetscale = *ascale;
5045 scalechosen = bscale;
5046 digitchosen = b;
5047 nchosen = bn;
5048 } else {
5049 targetscale = *bscale;
5050 scalechosen = ascale;
5051 digitchosen = a;
5052 nchosen = an;
5054 memset(t, 0, tn * sizeof(DWORD));
5055 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5057 /* multiply by 10 until target scale is reached, or
5058 significant bytes overflow the number
5060 while (*scalechosen < targetscale && t[nchosen] == 0) {
5061 VARIANT_int_mulbychar(t, tn, 10);
5062 if (t[nchosen] == 0) {
5063 /* still does not overflow */
5064 (*scalechosen)++;
5065 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5070 if (*ascale != *bscale) {
5071 /* still different? try to scale down the one with the bigger scale
5072 (this *will* lose significant digits) */
5073 DWORD * digitchosen;
5074 unsigned int nchosen;
5075 int * scalechosen;
5076 int targetscale;
5078 if (*ascale < *bscale) {
5079 targetscale = *ascale;
5080 scalechosen = bscale;
5081 digitchosen = b;
5082 nchosen = bn;
5083 } else {
5084 targetscale = *bscale;
5085 scalechosen = ascale;
5086 digitchosen = a;
5087 nchosen = an;
5089 memset(t, 0, tn * sizeof(DWORD));
5090 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5092 /* divide by 10 until target scale is reached */
5093 while (*scalechosen > targetscale) {
5094 VARIANT_int_divbychar(t, tn, 10);
5095 (*scalechosen)--;
5096 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5100 /* check whether any of the operands still has significant digits
5101 (underflow case 1)
5103 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5104 underflow = 1;
5105 } else {
5106 /* at this step, both numbers have the same scale and can be added
5107 as integers. However, the result might not fit in A, so further
5108 scaling down might be necessary.
5110 while (!underflow) {
5111 memset(t, 0, tn * sizeof(DWORD));
5112 memcpy(t, a, an * sizeof(DWORD));
5114 VARIANT_int_add(t, tn, b, bn);
5115 if (VARIANT_int_iszero(t + an, tn - an)) {
5116 /* addition was successful */
5117 memcpy(a, t, an * sizeof(DWORD));
5118 break;
5119 } else {
5120 /* addition overflowed - remove significant digits
5121 from both operands and try again */
5122 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5123 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5124 /* check whether any operand keeps significant digits after
5125 scaledown (underflow case 2)
5127 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5132 return underflow;
5135 /* perform complete DECIMAL division in the internal representation. Returns
5136 0 if the division was completed (even if quotient is set to 0), or nonzero
5137 in case of quotient overflow.
5139 static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * divisor,
5140 VARIANT_DI * quotient, BOOL round_remainder)
5142 HRESULT r_overflow = S_OK;
5144 if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
5145 /* division by 0 */
5146 r_overflow = DISP_E_DIVBYZERO;
5147 } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
5148 VARIANT_DI_clear(quotient);
5149 } else {
5150 int quotientscale, remainderscale, tempquotientscale;
5151 DWORD remainderplusquotient[8];
5152 int underflow;
5154 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5155 tempquotientscale = quotientscale;
5156 VARIANT_DI_clear(quotient);
5157 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5159 /* The following strategy is used for division
5160 1) if there was a nonzero remainder from previous iteration, use it as
5161 dividend for this iteration, else (for first iteration) use intended
5162 dividend
5163 2) perform integer division in temporary buffer, develop quotient in
5164 low-order part, remainder in high-order part
5165 3) add quotient from step 2 to final result, with possible loss of
5166 significant digits
5167 4) multiply integer part of remainder by 10, while incrementing the
5168 scale of the remainder. This operation preserves the intended value
5169 of the remainder.
5170 5) loop to step 1 until one of the following is true:
5171 a) remainder is zero (exact division achieved)
5172 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5174 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5175 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5176 do {
5177 VARIANT_int_div(
5178 remainderplusquotient, 4,
5179 divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
5180 underflow = VARIANT_int_addlossy(
5181 quotient->bitsnum, &quotientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
5182 remainderplusquotient, &tempquotientscale, 4);
5183 if (round_remainder) {
5184 if(remainderplusquotient[4] >= 5){
5185 unsigned int i;
5186 unsigned char remainder = 1;
5187 for (i = 0; i < sizeof(quotient->bitsnum) / sizeof(DWORD) && remainder; i++) {
5188 ULONGLONG digit = quotient->bitsnum[i] + 1;
5189 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5190 quotient->bitsnum[i] = digit & 0xFFFFFFFF;
5193 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5194 } else {
5195 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5196 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5198 tempquotientscale = ++remainderscale;
5199 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5201 /* quotient scale might now be negative (extremely big number). If, so, try
5202 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5203 until scale is 0. If this cannot be done, it is a real overflow.
5205 while (r_overflow == S_OK && quotientscale < 0) {
5206 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5207 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5208 VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
5209 if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
5210 (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
5211 quotientscale++;
5212 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5213 } else r_overflow = DISP_E_OVERFLOW;
5215 if (r_overflow == S_OK) {
5216 if (quotientscale <= 255) quotient->scale = quotientscale;
5217 else VARIANT_DI_clear(quotient);
5220 return r_overflow;
5223 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5224 with an undefined scale, which will be assigned to (if possible). It also
5225 receives an exponent of 2. This procedure will then manipulate the mantissa
5226 and calculate a corresponding scale, so that the exponent2 value is assimilated
5227 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5228 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5229 a DECIMAL. */
5230 static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, int isDouble)
5232 HRESULT hres = S_OK;
5233 int exponent5, exponent10;
5235 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5236 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5237 exponent10 might be used to set the VARIANT_DI scale directly. However,
5238 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5239 exponent5 = -exponent2;
5240 exponent10 = exponent2;
5242 /* Handle exponent5 > 0 */
5243 while (exponent5 > 0) {
5244 char bPrevCarryBit;
5245 char bCurrCarryBit;
5247 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5248 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5249 somehow the mantissa should be divided by 2. */
5250 if ((val->bitsnum[0] & 1) == 0) {
5251 /* The mantissa is divisible by 2. Therefore the division can be done
5252 without losing significant digits. */
5253 exponent10++; exponent5--;
5255 /* Shift right */
5256 bPrevCarryBit = val->bitsnum[2] & 1;
5257 val->bitsnum[2] >>= 1;
5258 bCurrCarryBit = val->bitsnum[1] & 1;
5259 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5260 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5261 } else {
5262 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5263 be multiplied by 5, unless the multiplication overflows. */
5264 DWORD temp_bitsnum[3];
5266 exponent5--;
5268 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5269 if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) {
5270 /* Multiplication succeeded without overflow, so copy result back
5271 into VARIANT_DI */
5272 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5274 /* Mask out 3 extraneous bits introduced by the multiply */
5275 } else {
5276 /* Multiplication by 5 overflows. The mantissa should be divided
5277 by 2, and therefore will lose significant digits. */
5278 exponent10++;
5280 /* Shift right */
5281 bPrevCarryBit = val->bitsnum[2] & 1;
5282 val->bitsnum[2] >>= 1;
5283 bCurrCarryBit = val->bitsnum[1] & 1;
5284 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5285 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5290 /* Handle exponent5 < 0 */
5291 while (exponent5 < 0) {
5292 /* In order to divide the value represented by the VARIANT_DI by 5, it
5293 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5294 and the mantissa should be multiplied by 2 */
5295 if ((val->bitsnum[2] & 0x80000000) == 0) {
5296 /* The mantissa can withstand a shift-left without overflowing */
5297 exponent10--; exponent5++;
5298 VARIANT_int_shiftleft(val->bitsnum, 3, 1);
5299 } else {
5300 /* The mantissa would overflow if shifted. Therefore it should be
5301 directly divided by 5. This will lose significant digits, unless
5302 by chance the mantissa happens to be divisible by 5 */
5303 exponent5++;
5304 VARIANT_int_divbychar(val->bitsnum, 3, 5);
5308 /* At this point, the mantissa has assimilated the exponent5, but the
5309 exponent10 might not be suitable for assignment. The exponent10 must be
5310 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5311 down appropriately. */
5312 while (hres == S_OK && exponent10 > 0) {
5313 /* In order to bring exponent10 down to 0, the mantissa should be
5314 multiplied by 10 to compensate. If the exponent10 is too big, this
5315 will cause the mantissa to overflow. */
5316 if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) {
5317 exponent10--;
5318 } else {
5319 hres = DISP_E_OVERFLOW;
5322 while (exponent10 < -DEC_MAX_SCALE) {
5323 int rem10;
5324 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5325 be divided by 10 to compensate. If the exponent10 is too small, this
5326 will cause the mantissa to underflow and become 0 */
5327 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5328 exponent10++;
5329 if (VARIANT_int_iszero(val->bitsnum, 3)) {
5330 /* Underflow, unable to keep dividing */
5331 exponent10 = 0;
5332 } else if (rem10 >= 5) {
5333 DWORD x = 1;
5334 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5337 /* This step is required in order to remove excess bits of precision from the
5338 end of the bit representation, down to the precision guaranteed by the
5339 floating point number. */
5340 if (isDouble) {
5341 while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[2] == 0 && (val->bitsnum[1] & 0xFFE00000) != 0))) {
5342 int rem10;
5344 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5345 exponent10++;
5346 if (rem10 >= 5) {
5347 DWORD x = 1;
5348 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5351 } else {
5352 while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 ||
5353 (val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) {
5354 int rem10;
5356 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5357 exponent10++;
5358 if (rem10 >= 5) {
5359 DWORD x = 1;
5360 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5364 /* Remove multiples of 10 from the representation */
5365 while (exponent10 < 0) {
5366 DWORD temp_bitsnum[3];
5368 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5369 if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) {
5370 exponent10++;
5371 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5372 } else break;
5375 /* Scale assignment */
5376 if (hres == S_OK) val->scale = -exponent10;
5378 return hres;
5381 typedef union
5383 struct
5385 unsigned int m : 23;
5386 unsigned int exp_bias : 8;
5387 unsigned int sign : 1;
5388 } i;
5389 float f;
5390 } R4_FIELDS;
5392 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5393 intermediate string step. */
5394 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest)
5396 HRESULT hres = S_OK;
5397 R4_FIELDS fx;
5399 fx.f = source;
5401 /* Detect special cases */
5402 if (fx.i.m == 0 && fx.i.exp_bias == 0) {
5403 /* Floating-point zero */
5404 VARIANT_DI_clear(dest);
5405 } else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) {
5406 /* Floating-point infinity */
5407 hres = DISP_E_OVERFLOW;
5408 } else if (fx.i.exp_bias == 0xFF) {
5409 /* Floating-point NaN */
5410 hres = DISP_E_BADVARTYPE;
5411 } else {
5412 int exponent2;
5413 VARIANT_DI_clear(dest);
5415 exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */
5416 dest->sign = fx.i.sign; /* Sign is simply copied */
5418 /* Copy significant bits to VARIANT_DI mantissa */
5419 dest->bitsnum[0] = fx.i.m;
5420 dest->bitsnum[0] &= 0x007FFFFF;
5421 if (fx.i.exp_bias == 0) {
5422 /* Denormalized number - correct exponent */
5423 exponent2++;
5424 } else {
5425 /* Add hidden bit to mantissa */
5426 dest->bitsnum[0] |= 0x00800000;
5429 /* The act of copying a FP mantissa as integer bits is equivalent to
5430 shifting left the mantissa 23 bits. The exponent2 is reduced to
5431 compensate. */
5432 exponent2 -= 23;
5434 hres = VARIANT_DI_normalize(dest, exponent2, 0);
5437 return hres;
5440 typedef union
5442 struct
5444 unsigned int m_lo : 32; /* 52 bits of precision */
5445 unsigned int m_hi : 20;
5446 unsigned int exp_bias : 11; /* bias == 1023 */
5447 unsigned int sign : 1;
5448 } i;
5449 double d;
5450 } R8_FIELDS;
5452 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5453 intermediate string step. */
5454 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest)
5456 HRESULT hres = S_OK;
5457 R8_FIELDS fx;
5459 fx.d = source;
5461 /* Detect special cases */
5462 if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) {
5463 /* Floating-point zero */
5464 VARIANT_DI_clear(dest);
5465 } else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) {
5466 /* Floating-point infinity */
5467 hres = DISP_E_OVERFLOW;
5468 } else if (fx.i.exp_bias == 0x7FF) {
5469 /* Floating-point NaN */
5470 hres = DISP_E_BADVARTYPE;
5471 } else {
5472 int exponent2;
5473 VARIANT_DI_clear(dest);
5475 exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */
5476 dest->sign = fx.i.sign; /* Sign is simply copied */
5478 /* Copy significant bits to VARIANT_DI mantissa */
5479 dest->bitsnum[0] = fx.i.m_lo;
5480 dest->bitsnum[1] = fx.i.m_hi;
5481 dest->bitsnum[1] &= 0x000FFFFF;
5482 if (fx.i.exp_bias == 0) {
5483 /* Denormalized number - correct exponent */
5484 exponent2++;
5485 } else {
5486 /* Add hidden bit to mantissa */
5487 dest->bitsnum[1] |= 0x00100000;
5490 /* The act of copying a FP mantissa as integer bits is equivalent to
5491 shifting left the mantissa 52 bits. The exponent2 is reduced to
5492 compensate. */
5493 exponent2 -= 52;
5495 hres = VARIANT_DI_normalize(dest, exponent2, 1);
5498 return hres;
5501 static HRESULT VARIANT_do_division(const DECIMAL *pDecLeft, const DECIMAL *pDecRight, DECIMAL *pDecOut,
5502 BOOL round)
5504 HRESULT hRet = S_OK;
5505 VARIANT_DI di_left, di_right, di_result;
5506 HRESULT divresult;
5508 VARIANT_DIFromDec(pDecLeft, &di_left);
5509 VARIANT_DIFromDec(pDecRight, &di_right);
5510 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result, round);
5511 if (divresult != S_OK)
5513 /* division actually overflowed */
5514 hRet = divresult;
5516 else
5518 hRet = S_OK;
5520 if (di_result.scale > DEC_MAX_SCALE)
5522 unsigned char remainder = 0;
5524 /* division underflowed. In order to comply with the MSDN
5525 specifications for DECIMAL ranges, some significant digits
5526 must be removed
5528 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5529 di_result.scale);
5530 while (di_result.scale > DEC_MAX_SCALE &&
5531 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
5533 remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
5534 di_result.scale--;
5536 if (di_result.scale > DEC_MAX_SCALE)
5538 WARN("result underflowed, setting to 0\n");
5539 di_result.scale = 0;
5540 di_result.sign = 0;
5542 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5544 unsigned int i;
5545 for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
5546 ULONGLONG digit = di_result.bitsnum[i] + 1;
5547 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5548 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5552 VARIANT_DecFromDI(&di_result, pDecOut);
5554 return hRet;
5557 /************************************************************************
5558 * VarDecDiv (OLEAUT32.178)
5560 * Divide one DECIMAL by another.
5562 * PARAMS
5563 * pDecLeft [I] Source
5564 * pDecRight [I] Value to divide by
5565 * pDecOut [O] Destination
5567 * RETURNS
5568 * Success: S_OK.
5569 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5571 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5573 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5575 return VARIANT_do_division(pDecLeft, pDecRight, pDecOut, FALSE);
5578 /************************************************************************
5579 * VarDecMul (OLEAUT32.179)
5581 * Multiply one DECIMAL by another.
5583 * PARAMS
5584 * pDecLeft [I] Source
5585 * pDecRight [I] Value to multiply by
5586 * pDecOut [O] Destination
5588 * RETURNS
5589 * Success: S_OK.
5590 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5592 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5594 HRESULT hRet = S_OK;
5595 VARIANT_DI di_left, di_right, di_result;
5596 int mulresult;
5598 VARIANT_DIFromDec(pDecLeft, &di_left);
5599 VARIANT_DIFromDec(pDecRight, &di_right);
5600 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5601 if (mulresult)
5603 /* multiplication actually overflowed */
5604 hRet = DISP_E_OVERFLOW;
5606 else
5608 if (di_result.scale > DEC_MAX_SCALE)
5610 /* multiplication underflowed. In order to comply with the MSDN
5611 specifications for DECIMAL ranges, some significant digits
5612 must be removed
5614 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5615 di_result.scale);
5616 while (di_result.scale > DEC_MAX_SCALE &&
5617 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
5619 VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
5620 di_result.scale--;
5622 if (di_result.scale > DEC_MAX_SCALE)
5624 WARN("result underflowed, setting to 0\n");
5625 di_result.scale = 0;
5626 di_result.sign = 0;
5629 VARIANT_DecFromDI(&di_result, pDecOut);
5631 return hRet;
5634 /************************************************************************
5635 * VarDecSub (OLEAUT32.181)
5637 * Subtract one DECIMAL from another.
5639 * PARAMS
5640 * pDecLeft [I] Source
5641 * pDecRight [I] DECIMAL to subtract from pDecLeft
5642 * pDecOut [O] Destination
5644 * RETURNS
5645 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5647 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5649 DECIMAL decRight;
5651 /* Implement as addition of the negative */
5652 VarDecNeg(pDecRight, &decRight);
5653 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5656 /************************************************************************
5657 * VarDecAbs (OLEAUT32.182)
5659 * Convert a DECIMAL into its absolute value.
5661 * PARAMS
5662 * pDecIn [I] Source
5663 * pDecOut [O] Destination
5665 * RETURNS
5666 * S_OK. This function does not fail.
5668 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5670 *pDecOut = *pDecIn;
5671 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5672 return S_OK;
5675 /************************************************************************
5676 * VarDecFix (OLEAUT32.187)
5678 * Return the integer portion of a DECIMAL.
5680 * PARAMS
5681 * pDecIn [I] Source
5682 * pDecOut [O] Destination
5684 * RETURNS
5685 * Success: S_OK.
5686 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5688 * NOTES
5689 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5690 * negative numbers away from 0, while this function rounds them towards zero.
5692 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5694 double dbl;
5695 HRESULT hr;
5697 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5698 return E_INVALIDARG;
5700 if (!DEC_SCALE(pDecIn))
5702 *pDecOut = *pDecIn; /* Already an integer */
5703 return S_OK;
5706 hr = VarR8FromDec(pDecIn, &dbl);
5707 if (SUCCEEDED(hr)) {
5708 LONGLONG rounded = dbl;
5710 hr = VarDecFromI8(rounded, pDecOut);
5712 return hr;
5715 /************************************************************************
5716 * VarDecInt (OLEAUT32.188)
5718 * Return the integer portion of a DECIMAL.
5720 * PARAMS
5721 * pDecIn [I] Source
5722 * pDecOut [O] Destination
5724 * RETURNS
5725 * Success: S_OK.
5726 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5728 * NOTES
5729 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5730 * negative numbers towards 0, while this function rounds them away from zero.
5732 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5734 double dbl;
5735 HRESULT hr;
5737 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5738 return E_INVALIDARG;
5740 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5741 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5743 hr = VarR8FromDec(pDecIn, &dbl);
5744 if (SUCCEEDED(hr)) {
5745 LONGLONG rounded = dbl >= 0.0 ? dbl + 0.5 : dbl - 0.5;
5747 hr = VarDecFromI8(rounded, pDecOut);
5749 return hr;
5752 /************************************************************************
5753 * VarDecNeg (OLEAUT32.189)
5755 * Change the sign of a DECIMAL.
5757 * PARAMS
5758 * pDecIn [I] Source
5759 * pDecOut [O] Destination
5761 * RETURNS
5762 * S_OK. This function does not fail.
5764 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5766 *pDecOut = *pDecIn;
5767 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5768 return S_OK;
5771 /************************************************************************
5772 * VarDecRound (OLEAUT32.203)
5774 * Change the precision of a DECIMAL.
5776 * PARAMS
5777 * pDecIn [I] Source
5778 * cDecimals [I] New number of decimals to keep
5779 * pDecOut [O] Destination
5781 * RETURNS
5782 * Success: S_OK. pDecOut contains the rounded value.
5783 * Failure: E_INVALIDARG if any argument is invalid.
5785 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5787 DECIMAL divisor, tmp;
5788 HRESULT hr;
5789 unsigned int i;
5791 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5792 return E_INVALIDARG;
5794 if (cDecimals >= DEC_SCALE(pDecIn))
5796 *pDecOut = *pDecIn; /* More precision than we have */
5797 return S_OK;
5800 /* truncate significant digits and rescale */
5801 memset(&divisor, 0, sizeof(divisor));
5802 DEC_LO64(&divisor) = 1;
5804 memset(&tmp, 0, sizeof(tmp));
5805 DEC_LO64(&tmp) = 10;
5806 for (i = 0; i < DEC_SCALE(pDecIn) - cDecimals; ++i)
5808 hr = VarDecMul(&divisor, &tmp, &divisor);
5809 if (FAILED(hr))
5810 return hr;
5813 hr = VARIANT_do_division(pDecIn, &divisor, pDecOut, TRUE);
5814 if (FAILED(hr))
5815 return hr;
5817 DEC_SCALE(pDecOut) = cDecimals;
5819 return S_OK;
5822 /************************************************************************
5823 * VarDecCmp (OLEAUT32.204)
5825 * Compare two DECIMAL values.
5827 * PARAMS
5828 * pDecLeft [I] Source
5829 * pDecRight [I] Value to compare
5831 * RETURNS
5832 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5833 * is less than, equal to or greater than pDecRight respectively.
5834 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5836 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5838 HRESULT hRet;
5839 DECIMAL result;
5841 if (!pDecLeft || !pDecRight)
5842 return VARCMP_NULL;
5844 if ((!(DEC_SIGN(pDecLeft) & DECIMAL_NEG)) && (DEC_SIGN(pDecRight) & DECIMAL_NEG) &&
5845 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5846 return VARCMP_GT;
5847 else if ((DEC_SIGN(pDecLeft) & DECIMAL_NEG) && (!(DEC_SIGN(pDecRight) & DECIMAL_NEG)) &&
5848 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5849 return VARCMP_LT;
5851 /* Subtract right from left, and compare the result to 0 */
5852 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5854 if (SUCCEEDED(hRet))
5856 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5858 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5859 hRet = (HRESULT)VARCMP_LT;
5860 else if (non_zero)
5861 hRet = (HRESULT)VARCMP_GT;
5862 else
5863 hRet = (HRESULT)VARCMP_EQ;
5865 return hRet;
5868 /************************************************************************
5869 * VarDecCmpR8 (OLEAUT32.298)
5871 * Compare a DECIMAL to a double
5873 * PARAMS
5874 * pDecLeft [I] DECIMAL Source
5875 * dblRight [I] double to compare to pDecLeft
5877 * RETURNS
5878 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5879 * is less than, equal to or greater than pDecLeft respectively.
5880 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5882 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5884 HRESULT hRet;
5885 DECIMAL decRight;
5887 hRet = VarDecFromR8(dblRight, &decRight);
5889 if (SUCCEEDED(hRet))
5890 hRet = VarDecCmp(pDecLeft, &decRight);
5892 return hRet;
5895 /* BOOL
5898 /************************************************************************
5899 * VarBoolFromUI1 (OLEAUT32.118)
5901 * Convert a VT_UI1 to a VT_BOOL.
5903 * PARAMS
5904 * bIn [I] Source
5905 * pBoolOut [O] Destination
5907 * RETURNS
5908 * S_OK.
5910 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5912 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5913 return S_OK;
5916 /************************************************************************
5917 * VarBoolFromI2 (OLEAUT32.119)
5919 * Convert a VT_I2 to a VT_BOOL.
5921 * PARAMS
5922 * sIn [I] Source
5923 * pBoolOut [O] Destination
5925 * RETURNS
5926 * S_OK.
5928 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5930 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5931 return S_OK;
5934 /************************************************************************
5935 * VarBoolFromI4 (OLEAUT32.120)
5937 * Convert a VT_I4 to a VT_BOOL.
5939 * PARAMS
5940 * sIn [I] Source
5941 * pBoolOut [O] Destination
5943 * RETURNS
5944 * S_OK.
5946 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
5948 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
5949 return S_OK;
5952 /************************************************************************
5953 * VarBoolFromR4 (OLEAUT32.121)
5955 * Convert a VT_R4 to a VT_BOOL.
5957 * PARAMS
5958 * fltIn [I] Source
5959 * pBoolOut [O] Destination
5961 * RETURNS
5962 * S_OK.
5964 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
5966 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
5967 return S_OK;
5970 /************************************************************************
5971 * VarBoolFromR8 (OLEAUT32.122)
5973 * Convert a VT_R8 to a VT_BOOL.
5975 * PARAMS
5976 * dblIn [I] Source
5977 * pBoolOut [O] Destination
5979 * RETURNS
5980 * S_OK.
5982 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
5984 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
5985 return S_OK;
5988 /************************************************************************
5989 * VarBoolFromDate (OLEAUT32.123)
5991 * Convert a VT_DATE to a VT_BOOL.
5993 * PARAMS
5994 * dateIn [I] Source
5995 * pBoolOut [O] Destination
5997 * RETURNS
5998 * S_OK.
6000 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
6002 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
6003 return S_OK;
6006 /************************************************************************
6007 * VarBoolFromCy (OLEAUT32.124)
6009 * Convert a VT_CY to a VT_BOOL.
6011 * PARAMS
6012 * cyIn [I] Source
6013 * pBoolOut [O] Destination
6015 * RETURNS
6016 * S_OK.
6018 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
6020 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
6021 return S_OK;
6024 /************************************************************************
6025 * VARIANT_GetLocalisedText [internal]
6027 * Get a localized string from the resources
6030 BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
6032 HRSRC hrsrc;
6034 hrsrc = FindResourceExW( hProxyDll, (LPWSTR)RT_STRING,
6035 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
6036 if (hrsrc)
6038 HGLOBAL hmem = LoadResource( hProxyDll, hrsrc );
6040 if (hmem)
6042 const WCHAR *p;
6043 unsigned int i;
6045 p = LockResource( hmem );
6046 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
6048 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
6049 lpszDest[*p] = '\0';
6050 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
6051 return TRUE;
6054 return FALSE;
6057 /************************************************************************
6058 * VarBoolFromStr (OLEAUT32.125)
6060 * Convert a VT_BSTR to a VT_BOOL.
6062 * PARAMS
6063 * strIn [I] Source
6064 * lcid [I] LCID for the conversion
6065 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6066 * pBoolOut [O] Destination
6068 * RETURNS
6069 * Success: S_OK.
6070 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6071 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6073 * NOTES
6074 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6075 * it may contain (in any case mapping) the text "true" or "false".
6076 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6077 * localised text of "True" or "False" in the language specified by lcid.
6078 * - If none of these matches occur, the string is treated as a numeric string
6079 * and the boolean pBoolOut will be set according to whether the number is zero
6080 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6081 * - If the text is not numeric and does not match any of the above, then
6082 * DISP_E_TYPEMISMATCH is returned.
6084 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
6086 /* Any VB/VBA programmers out there should recognise these strings... */
6087 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
6088 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
6089 WCHAR szBuff[64];
6090 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6091 HRESULT hRes = S_OK;
6093 if (!strIn || !pBoolOut)
6094 return DISP_E_TYPEMISMATCH;
6096 /* Check if we should be comparing against localised text */
6097 if (dwFlags & VAR_LOCALBOOL)
6099 /* Convert our LCID into a usable value */
6100 lcid = ConvertDefaultLocale(lcid);
6102 langId = LANGIDFROMLCID(lcid);
6104 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6105 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6107 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6108 * I don't think this is needed unless any of the localised text strings
6109 * contain characters that can be so mapped. In the event that this is
6110 * true for a given language (possibly some Asian languages), then strIn
6111 * should be mapped here _only_ if langId is an Id for which this can occur.
6115 /* Note that if we are not comparing against localised strings, langId
6116 * will have its default value of LANG_ENGLISH. This allows us to mimic
6117 * the native behaviour of always checking against English strings even
6118 * after we've checked for localised ones.
6120 VarBoolFromStr_CheckLocalised:
6121 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
6123 /* Compare against localised strings, ignoring case */
6124 if (!strcmpiW(strIn, szBuff))
6126 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
6127 return hRes;
6129 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
6130 if (!strcmpiW(strIn, szBuff))
6132 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
6133 return hRes;
6137 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6139 /* We have checked the localised text, now check English */
6140 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6141 goto VarBoolFromStr_CheckLocalised;
6144 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6145 if (!strcmpW(strIn, szFalse))
6146 *pBoolOut = VARIANT_FALSE;
6147 else if (!strcmpW(strIn, szTrue))
6148 *pBoolOut = VARIANT_TRUE;
6149 else
6151 double d;
6153 /* If this string is a number, convert it as one */
6154 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
6155 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
6157 return hRes;
6160 /************************************************************************
6161 * VarBoolFromDisp (OLEAUT32.126)
6163 * Convert a VT_DISPATCH to a VT_BOOL.
6165 * PARAMS
6166 * pdispIn [I] Source
6167 * lcid [I] LCID for conversion
6168 * pBoolOut [O] Destination
6170 * RETURNS
6171 * Success: S_OK.
6172 * Failure: E_INVALIDARG, if the source value is invalid
6173 * DISP_E_OVERFLOW, if the value will not fit in the destination
6174 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6176 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
6178 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
6181 /************************************************************************
6182 * VarBoolFromI1 (OLEAUT32.233)
6184 * Convert a VT_I1 to a VT_BOOL.
6186 * PARAMS
6187 * cIn [I] Source
6188 * pBoolOut [O] Destination
6190 * RETURNS
6191 * S_OK.
6193 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
6195 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
6196 return S_OK;
6199 /************************************************************************
6200 * VarBoolFromUI2 (OLEAUT32.234)
6202 * Convert a VT_UI2 to a VT_BOOL.
6204 * PARAMS
6205 * usIn [I] Source
6206 * pBoolOut [O] Destination
6208 * RETURNS
6209 * S_OK.
6211 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
6213 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
6214 return S_OK;
6217 /************************************************************************
6218 * VarBoolFromUI4 (OLEAUT32.235)
6220 * Convert a VT_UI4 to a VT_BOOL.
6222 * PARAMS
6223 * ulIn [I] Source
6224 * pBoolOut [O] Destination
6226 * RETURNS
6227 * S_OK.
6229 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
6231 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
6232 return S_OK;
6235 /************************************************************************
6236 * VarBoolFromDec (OLEAUT32.236)
6238 * Convert a VT_DECIMAL to a VT_BOOL.
6240 * PARAMS
6241 * pDecIn [I] Source
6242 * pBoolOut [O] Destination
6244 * RETURNS
6245 * Success: S_OK.
6246 * Failure: E_INVALIDARG, if pDecIn is invalid.
6248 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
6250 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
6251 return E_INVALIDARG;
6253 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
6254 *pBoolOut = VARIANT_TRUE;
6255 else
6256 *pBoolOut = VARIANT_FALSE;
6257 return S_OK;
6260 /************************************************************************
6261 * VarBoolFromI8 (OLEAUT32.370)
6263 * Convert a VT_I8 to a VT_BOOL.
6265 * PARAMS
6266 * ullIn [I] Source
6267 * pBoolOut [O] Destination
6269 * RETURNS
6270 * S_OK.
6272 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
6274 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
6275 return S_OK;
6278 /************************************************************************
6279 * VarBoolFromUI8 (OLEAUT32.371)
6281 * Convert a VT_UI8 to a VT_BOOL.
6283 * PARAMS
6284 * ullIn [I] Source
6285 * pBoolOut [O] Destination
6287 * RETURNS
6288 * S_OK.
6290 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
6292 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
6293 return S_OK;
6296 /* BSTR
6299 /* Write a number from a UI8 and sign */
6300 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
6304 WCHAR ulNextDigit = ulVal % 10;
6306 *szOut-- = '0' + ulNextDigit;
6307 ulVal = (ulVal - ulNextDigit) / 10;
6308 } while (ulVal);
6310 szOut++;
6311 return szOut;
6314 /* Create a (possibly localised) BSTR from a UI8 and sign */
6315 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
6317 WCHAR szConverted[256];
6319 if (dwFlags & VAR_NEGATIVE)
6320 *--szOut = '-';
6322 if (dwFlags & LOCALE_USE_NLS)
6324 /* Format the number for the locale */
6325 szConverted[0] = '\0';
6326 GetNumberFormatW(lcid,
6327 dwFlags & LOCALE_NOUSEROVERRIDE,
6328 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
6329 szOut = szConverted;
6331 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
6334 /* Create a (possibly localised) BSTR from a UI8 and sign */
6335 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
6337 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
6339 if (!pbstrOut)
6340 return E_INVALIDARG;
6342 /* Create the basic number string */
6343 *szOut-- = '\0';
6344 szOut = VARIANT_WriteNumber(ulVal, szOut);
6346 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
6347 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6348 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6351 /******************************************************************************
6352 * VarBstrFromUI1 (OLEAUT32.108)
6354 * Convert a VT_UI1 to a VT_BSTR.
6356 * PARAMS
6357 * bIn [I] Source
6358 * lcid [I] LCID for the conversion
6359 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6360 * pbstrOut [O] Destination
6362 * RETURNS
6363 * Success: S_OK.
6364 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6365 * E_OUTOFMEMORY, if memory allocation fails.
6367 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6369 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6372 /******************************************************************************
6373 * VarBstrFromI2 (OLEAUT32.109)
6375 * Convert a VT_I2 to a VT_BSTR.
6377 * PARAMS
6378 * sIn [I] Source
6379 * lcid [I] LCID for the conversion
6380 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6381 * pbstrOut [O] Destination
6383 * RETURNS
6384 * Success: S_OK.
6385 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6386 * E_OUTOFMEMORY, if memory allocation fails.
6388 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6390 ULONG64 ul64 = sIn;
6392 if (sIn < 0)
6394 ul64 = -sIn;
6395 dwFlags |= VAR_NEGATIVE;
6397 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6400 /******************************************************************************
6401 * VarBstrFromI4 (OLEAUT32.110)
6403 * Convert a VT_I4 to a VT_BSTR.
6405 * PARAMS
6406 * lIn [I] Source
6407 * lcid [I] LCID for the conversion
6408 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6409 * pbstrOut [O] Destination
6411 * RETURNS
6412 * Success: S_OK.
6413 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6414 * E_OUTOFMEMORY, if memory allocation fails.
6416 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6418 ULONG64 ul64 = lIn;
6420 if (lIn < 0)
6422 ul64 = (ULONG)-lIn;
6423 dwFlags |= VAR_NEGATIVE;
6425 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6428 static BSTR VARIANT_BstrReplaceDecimal(const WCHAR * buff, LCID lcid, ULONG dwFlags)
6430 BSTR bstrOut;
6431 WCHAR lpDecimalSep[16];
6433 /* Native oleaut32 uses the locale-specific decimal separator even in the
6434 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6435 American locales will see "one thousand and one tenth" as "1000,1"
6436 instead of "1000.1" (notice the comma). The following code checks for
6437 the need to replace the decimal separator, and if so, will prepare an
6438 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6440 GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE),
6441 lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
6442 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6444 /* locale is compatible with English - return original string */
6445 bstrOut = SysAllocString(buff);
6447 else
6449 WCHAR *p;
6450 WCHAR numbuff[256];
6451 WCHAR empty[] = {'\0'};
6452 NUMBERFMTW minFormat;
6454 minFormat.NumDigits = 0;
6455 minFormat.LeadingZero = 0;
6456 minFormat.Grouping = 0;
6457 minFormat.lpDecimalSep = lpDecimalSep;
6458 minFormat.lpThousandSep = empty;
6459 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6461 /* count number of decimal digits in string */
6462 p = strchrW( buff, '.' );
6463 if (p) minFormat.NumDigits = strlenW(p + 1);
6465 numbuff[0] = '\0';
6466 if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
6468 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6469 bstrOut = SysAllocString(buff);
6471 else
6473 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6474 bstrOut = SysAllocString(numbuff);
6477 return bstrOut;
6480 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6481 BSTR* pbstrOut, LPCWSTR lpszFormat)
6483 WCHAR buff[256];
6485 if (!pbstrOut)
6486 return E_INVALIDARG;
6488 sprintfW( buff, lpszFormat, dblIn );
6490 /* Negative zeroes are disallowed (some applications depend on this).
6491 If buff starts with a minus, and then nothing follows but zeroes
6492 and/or a period, it is a negative zero and is replaced with a
6493 canonical zero. This duplicates native oleaut32 behavior.
6495 if (buff[0] == '-')
6497 const WCHAR szAccept[] = {'0', '.', '\0'};
6498 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
6499 { buff[0] = '0'; buff[1] = '\0'; }
6502 TRACE("created string %s\n", debugstr_w(buff));
6503 if (dwFlags & LOCALE_USE_NLS)
6505 WCHAR numbuff[256];
6507 /* Format the number for the locale */
6508 numbuff[0] = '\0';
6509 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6510 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6511 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6512 *pbstrOut = SysAllocString(numbuff);
6514 else
6516 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6518 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6521 /******************************************************************************
6522 * VarBstrFromR4 (OLEAUT32.111)
6524 * Convert a VT_R4 to a VT_BSTR.
6526 * PARAMS
6527 * fltIn [I] Source
6528 * lcid [I] LCID for the conversion
6529 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6530 * pbstrOut [O] Destination
6532 * RETURNS
6533 * Success: S_OK.
6534 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6535 * E_OUTOFMEMORY, if memory allocation fails.
6537 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6539 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
6542 /******************************************************************************
6543 * VarBstrFromR8 (OLEAUT32.112)
6545 * Convert a VT_R8 to a VT_BSTR.
6547 * PARAMS
6548 * dblIn [I] Source
6549 * lcid [I] LCID for the conversion
6550 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6551 * pbstrOut [O] Destination
6553 * RETURNS
6554 * Success: S_OK.
6555 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6556 * E_OUTOFMEMORY, if memory allocation fails.
6558 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6560 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
6563 /******************************************************************************
6564 * VarBstrFromCy [OLEAUT32.113]
6566 * Convert a VT_CY to a VT_BSTR.
6568 * PARAMS
6569 * cyIn [I] Source
6570 * lcid [I] LCID for the conversion
6571 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6572 * pbstrOut [O] Destination
6574 * RETURNS
6575 * Success: S_OK.
6576 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6577 * E_OUTOFMEMORY, if memory allocation fails.
6579 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6581 WCHAR buff[256];
6582 VARIANT_DI decVal;
6584 if (!pbstrOut)
6585 return E_INVALIDARG;
6587 decVal.scale = 4;
6588 decVal.sign = 0;
6589 decVal.bitsnum[0] = cyIn.s.Lo;
6590 decVal.bitsnum[1] = cyIn.s.Hi;
6591 if (cyIn.s.Hi & 0x80000000UL) {
6592 DWORD one = 1;
6594 /* Negative number! */
6595 decVal.sign = 1;
6596 decVal.bitsnum[0] = ~decVal.bitsnum[0];
6597 decVal.bitsnum[1] = ~decVal.bitsnum[1];
6598 VARIANT_int_add(decVal.bitsnum, 3, &one, 1);
6600 decVal.bitsnum[2] = 0;
6601 VARIANT_DI_tostringW(&decVal, buff, sizeof(buff)/sizeof(buff[0]));
6603 if (dwFlags & LOCALE_USE_NLS)
6605 WCHAR cybuff[256];
6607 /* Format the currency for the locale */
6608 cybuff[0] = '\0';
6609 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6610 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR));
6611 *pbstrOut = SysAllocString(cybuff);
6613 else
6614 *pbstrOut = VARIANT_BstrReplaceDecimal(buff,lcid,dwFlags);
6616 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6619 static inline int output_int_len(int o, int min_len, WCHAR *date, int date_len)
6621 int len, tmp;
6623 if(min_len >= date_len)
6624 return -1;
6626 for(len=0, tmp=o; tmp; tmp/=10) len++;
6627 if(!len) len++;
6628 if(len >= date_len)
6629 return -1;
6631 for(tmp=min_len-len; tmp>0; tmp--)
6632 *date++ = '0';
6633 for(tmp=len; tmp>0; tmp--, o/=10)
6634 date[tmp-1] = '0' + o%10;
6635 return min_len>len ? min_len : len;
6638 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6639 BOOL get_date_format(LCID lcid, DWORD flags, const SYSTEMTIME *st,
6640 const WCHAR *fmt, WCHAR *date, int date_len)
6642 static const LCTYPE dayname[] = {
6643 LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
6644 LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6
6646 static const LCTYPE sdayname[] = {
6647 LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
6648 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
6649 LOCALE_SABBREVDAYNAME6
6651 static const LCTYPE monthname[] = {
6652 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
6653 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
6654 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12
6656 static const LCTYPE smonthname[] = {
6657 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
6658 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
6659 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
6660 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12
6663 if(flags & ~(LOCALE_NOUSEROVERRIDE|VAR_DATEVALUEONLY))
6664 FIXME("ignoring flags %x\n", flags);
6665 flags &= LOCALE_NOUSEROVERRIDE;
6667 while(*fmt && date_len) {
6668 int count = 1;
6670 switch(*fmt) {
6671 case 'd':
6672 case 'M':
6673 case 'y':
6674 case 'g':
6675 while(*fmt == *(fmt+count))
6676 count++;
6677 fmt += count-1;
6680 switch(*fmt) {
6681 case 'd':
6682 if(count >= 4)
6683 count = GetLocaleInfoW(lcid, dayname[st->wDayOfWeek] | flags, date, date_len)-1;
6684 else if(count == 3)
6685 count = GetLocaleInfoW(lcid, sdayname[st->wDayOfWeek] | flags, date, date_len)-1;
6686 else
6687 count = output_int_len(st->wDay, count, date, date_len);
6688 break;
6689 case 'M':
6690 if(count >= 4)
6691 count = GetLocaleInfoW(lcid, monthname[st->wMonth-1] | flags, date, date_len)-1;
6692 else if(count == 3)
6693 count = GetLocaleInfoW(lcid, smonthname[st->wMonth-1] | flags, date, date_len)-1;
6694 else
6695 count = output_int_len(st->wMonth, count, date, date_len);
6696 break;
6697 case 'y':
6698 if(count >= 3)
6699 count = output_int_len(st->wYear, 0, date, date_len);
6700 else
6701 count = output_int_len(st->wYear%100, count, date, date_len);
6702 break;
6703 case 'g':
6704 if(count == 2) {
6705 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6707 *date++ = 'A';
6708 date_len--;
6709 if(date_len)
6710 *date = 'D';
6711 else
6712 count = -1;
6713 break;
6715 /* fall through */
6716 default:
6717 *date = *fmt;
6720 if(count < 0)
6721 break;
6722 fmt++;
6723 date += count;
6724 date_len -= count;
6727 if(!date_len)
6728 return FALSE;
6729 *date++ = 0;
6730 return TRUE;
6733 /******************************************************************************
6734 * VarBstrFromDate [OLEAUT32.114]
6736 * Convert a VT_DATE to a VT_BSTR.
6738 * PARAMS
6739 * dateIn [I] Source
6740 * lcid [I] LCID for the conversion
6741 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6742 * pbstrOut [O] Destination
6744 * RETURNS
6745 * Success: S_OK.
6746 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6747 * E_OUTOFMEMORY, if memory allocation fails.
6749 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6751 SYSTEMTIME st;
6752 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6753 WCHAR date[128], fmt_buff[80], *time;
6755 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
6757 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6758 return E_INVALIDARG;
6760 *pbstrOut = NULL;
6762 if (dwFlags & VAR_CALENDAR_THAI)
6763 st.wYear += 553; /* Use the Thai buddhist calendar year */
6764 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6765 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6767 if (dwFlags & LOCALE_USE_NLS)
6768 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6769 else
6771 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6772 double partial = dateIn - whole;
6774 if (whole == 0.0)
6775 dwFlags |= VAR_TIMEVALUEONLY;
6776 else if (partial > -1e-12 && partial < 1e-12)
6777 dwFlags |= VAR_DATEVALUEONLY;
6780 if (dwFlags & VAR_TIMEVALUEONLY)
6781 date[0] = '\0';
6782 else
6783 if (!GetLocaleInfoW(lcid, LOCALE_SSHORTDATE, fmt_buff, sizeof(fmt_buff)/sizeof(WCHAR)) ||
6784 !get_date_format(lcid, dwFlags, &st, fmt_buff, date, sizeof(date)/sizeof(WCHAR)))
6785 return E_INVALIDARG;
6787 if (!(dwFlags & VAR_DATEVALUEONLY))
6789 time = date + strlenW(date);
6790 if (time != date)
6791 *time++ = ' ';
6792 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
6793 sizeof(date)/sizeof(WCHAR)-(time-date)))
6794 return E_INVALIDARG;
6797 *pbstrOut = SysAllocString(date);
6798 if (*pbstrOut)
6799 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6800 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6803 /******************************************************************************
6804 * VarBstrFromBool (OLEAUT32.116)
6806 * Convert a VT_BOOL to a VT_BSTR.
6808 * PARAMS
6809 * boolIn [I] Source
6810 * lcid [I] LCID for the conversion
6811 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6812 * pbstrOut [O] Destination
6814 * RETURNS
6815 * Success: S_OK.
6816 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6817 * E_OUTOFMEMORY, if memory allocation fails.
6819 * NOTES
6820 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6821 * localised text of "True" or "False". To convert a bool into a
6822 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6824 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6826 WCHAR szBuff[64];
6827 DWORD dwResId = IDS_TRUE;
6828 LANGID langId;
6830 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn, lcid, dwFlags, pbstrOut);
6832 if (!pbstrOut)
6833 return E_INVALIDARG;
6835 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6836 * for variant formatting */
6837 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6839 case VAR_BOOLONOFF:
6840 dwResId = IDS_ON;
6841 break;
6842 case VAR_BOOLYESNO:
6843 dwResId = IDS_YES;
6844 break;
6845 case VAR_LOCALBOOL:
6846 break;
6847 default:
6848 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6851 lcid = ConvertDefaultLocale(lcid);
6852 langId = LANGIDFROMLCID(lcid);
6853 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6854 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6856 if (boolIn == VARIANT_FALSE)
6857 dwResId++; /* Use negative form */
6859 VarBstrFromBool_GetLocalised:
6860 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6862 *pbstrOut = SysAllocString(szBuff);
6863 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6866 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6868 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6869 goto VarBstrFromBool_GetLocalised;
6872 /* Should never get here */
6873 WARN("Failed to load bool text!\n");
6874 return E_OUTOFMEMORY;
6877 /******************************************************************************
6878 * VarBstrFromI1 (OLEAUT32.229)
6880 * Convert a VT_I1 to a VT_BSTR.
6882 * PARAMS
6883 * cIn [I] Source
6884 * lcid [I] LCID for the conversion
6885 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6886 * pbstrOut [O] Destination
6888 * RETURNS
6889 * Success: S_OK.
6890 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6891 * E_OUTOFMEMORY, if memory allocation fails.
6893 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6895 ULONG64 ul64 = cIn;
6897 if (cIn < 0)
6899 ul64 = -cIn;
6900 dwFlags |= VAR_NEGATIVE;
6902 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6905 /******************************************************************************
6906 * VarBstrFromUI2 (OLEAUT32.230)
6908 * Convert a VT_UI2 to a VT_BSTR.
6910 * PARAMS
6911 * usIn [I] Source
6912 * lcid [I] LCID for the conversion
6913 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6914 * pbstrOut [O] Destination
6916 * RETURNS
6917 * Success: S_OK.
6918 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6919 * E_OUTOFMEMORY, if memory allocation fails.
6921 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6923 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6926 /******************************************************************************
6927 * VarBstrFromUI4 (OLEAUT32.231)
6929 * Convert a VT_UI4 to a VT_BSTR.
6931 * PARAMS
6932 * ulIn [I] Source
6933 * lcid [I] LCID for the conversion
6934 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6935 * pbstrOut [O] Destination
6937 * RETURNS
6938 * Success: S_OK.
6939 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6940 * E_OUTOFMEMORY, if memory allocation fails.
6942 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6944 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
6947 /******************************************************************************
6948 * VarBstrFromDec (OLEAUT32.232)
6950 * Convert a VT_DECIMAL to a VT_BSTR.
6952 * PARAMS
6953 * pDecIn [I] Source
6954 * lcid [I] LCID for the conversion
6955 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6956 * pbstrOut [O] Destination
6958 * RETURNS
6959 * Success: S_OK.
6960 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6961 * E_OUTOFMEMORY, if memory allocation fails.
6963 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6965 WCHAR buff[256];
6966 VARIANT_DI temp;
6968 if (!pbstrOut)
6969 return E_INVALIDARG;
6971 VARIANT_DIFromDec(pDecIn, &temp);
6972 VARIANT_DI_tostringW(&temp, buff, 256);
6974 if (dwFlags & LOCALE_USE_NLS)
6976 WCHAR numbuff[256];
6978 /* Format the number for the locale */
6979 numbuff[0] = '\0';
6980 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6981 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6982 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6983 *pbstrOut = SysAllocString(numbuff);
6985 else
6987 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6990 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6991 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6994 /************************************************************************
6995 * VarBstrFromI8 (OLEAUT32.370)
6997 * Convert a VT_I8 to a VT_BSTR.
6999 * PARAMS
7000 * llIn [I] Source
7001 * lcid [I] LCID for the conversion
7002 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7003 * pbstrOut [O] Destination
7005 * RETURNS
7006 * Success: S_OK.
7007 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7008 * E_OUTOFMEMORY, if memory allocation fails.
7010 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7012 ULONG64 ul64 = llIn;
7014 if (llIn < 0)
7016 ul64 = -llIn;
7017 dwFlags |= VAR_NEGATIVE;
7019 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
7022 /************************************************************************
7023 * VarBstrFromUI8 (OLEAUT32.371)
7025 * Convert a VT_UI8 to a VT_BSTR.
7027 * PARAMS
7028 * ullIn [I] Source
7029 * lcid [I] LCID for the conversion
7030 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7031 * pbstrOut [O] Destination
7033 * RETURNS
7034 * Success: S_OK.
7035 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7036 * E_OUTOFMEMORY, if memory allocation fails.
7038 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7040 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
7043 /************************************************************************
7044 * VarBstrFromDisp (OLEAUT32.115)
7046 * Convert a VT_DISPATCH to a BSTR.
7048 * PARAMS
7049 * pdispIn [I] Source
7050 * lcid [I] LCID for conversion
7051 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7052 * pbstrOut [O] Destination
7054 * RETURNS
7055 * Success: S_OK.
7056 * Failure: E_INVALIDARG, if the source value is invalid
7057 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7059 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7061 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
7064 /**********************************************************************
7065 * VarBstrCat (OLEAUT32.313)
7067 * Concatenate two BSTR values.
7069 * PARAMS
7070 * pbstrLeft [I] Source
7071 * pbstrRight [I] Value to concatenate
7072 * pbstrOut [O] Destination
7074 * RETURNS
7075 * Success: S_OK.
7076 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7077 * E_OUTOFMEMORY, if memory allocation fails.
7079 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
7081 unsigned int lenLeft, lenRight;
7083 TRACE("%s,%s,%p\n",
7084 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7085 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
7087 if (!pbstrOut)
7088 return E_INVALIDARG;
7090 /* use byte length here to properly handle ansi-allocated BSTRs */
7091 lenLeft = pbstrLeft ? SysStringByteLen(pbstrLeft) : 0;
7092 lenRight = pbstrRight ? SysStringByteLen(pbstrRight) : 0;
7094 *pbstrOut = SysAllocStringByteLen(NULL, lenLeft + lenRight);
7095 if (!*pbstrOut)
7096 return E_OUTOFMEMORY;
7098 (*pbstrOut)[0] = '\0';
7100 if (pbstrLeft)
7101 memcpy(*pbstrOut, pbstrLeft, lenLeft);
7103 if (pbstrRight)
7104 memcpy((CHAR*)*pbstrOut + lenLeft, pbstrRight, lenRight);
7106 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
7107 return S_OK;
7110 /**********************************************************************
7111 * VarBstrCmp (OLEAUT32.314)
7113 * Compare two BSTR values.
7115 * PARAMS
7116 * pbstrLeft [I] Source
7117 * pbstrRight [I] Value to compare
7118 * lcid [I] LCID for the comparison
7119 * dwFlags [I] Flags to pass directly to CompareStringW().
7121 * RETURNS
7122 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7123 * than, equal to or greater than pbstrRight respectively.
7125 * NOTES
7126 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7127 * states. A NULL BSTR pointer is equivalent to an empty string.
7128 * If LCID is equal to 0, a byte by byte comparison is performed.
7130 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
7132 HRESULT hres;
7133 int ret;
7135 TRACE("%s,%s,%d,%08x\n",
7136 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7137 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
7139 if (!pbstrLeft || !*pbstrLeft)
7141 if (pbstrRight && *pbstrRight)
7142 return VARCMP_LT;
7144 else if (!pbstrRight || !*pbstrRight)
7145 return VARCMP_GT;
7147 if (lcid == 0)
7149 unsigned int lenLeft = SysStringByteLen(pbstrLeft);
7150 unsigned int lenRight = SysStringByteLen(pbstrRight);
7151 ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight));
7152 if (ret < 0)
7153 return VARCMP_LT;
7154 if (ret > 0)
7155 return VARCMP_GT;
7156 if (lenLeft < lenRight)
7157 return VARCMP_LT;
7158 if (lenLeft > lenRight)
7159 return VARCMP_GT;
7160 return VARCMP_EQ;
7162 else
7164 unsigned int lenLeft = SysStringLen(pbstrLeft);
7165 unsigned int lenRight = SysStringLen(pbstrRight);
7167 if (lenLeft == 0 || lenRight == 0)
7169 if (lenLeft == 0 && lenRight == 0) return VARCMP_EQ;
7170 return lenLeft < lenRight ? VARCMP_LT : VARCMP_GT;
7173 hres = CompareStringW(lcid, dwFlags, pbstrLeft, lenLeft,
7174 pbstrRight, lenRight) - CSTR_LESS_THAN;
7175 TRACE("%d\n", hres);
7176 return hres;
7181 * DATE
7184 /******************************************************************************
7185 * VarDateFromUI1 (OLEAUT32.88)
7187 * Convert a VT_UI1 to a VT_DATE.
7189 * PARAMS
7190 * bIn [I] Source
7191 * pdateOut [O] Destination
7193 * RETURNS
7194 * S_OK.
7196 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
7198 return VarR8FromUI1(bIn, pdateOut);
7201 /******************************************************************************
7202 * VarDateFromI2 (OLEAUT32.89)
7204 * Convert a VT_I2 to a VT_DATE.
7206 * PARAMS
7207 * sIn [I] Source
7208 * pdateOut [O] Destination
7210 * RETURNS
7211 * S_OK.
7213 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
7215 return VarR8FromI2(sIn, pdateOut);
7218 /******************************************************************************
7219 * VarDateFromI4 (OLEAUT32.90)
7221 * Convert a VT_I4 to a VT_DATE.
7223 * PARAMS
7224 * lIn [I] Source
7225 * pdateOut [O] Destination
7227 * RETURNS
7228 * S_OK.
7230 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
7232 return VarDateFromR8(lIn, pdateOut);
7235 /******************************************************************************
7236 * VarDateFromR4 (OLEAUT32.91)
7238 * Convert a VT_R4 to a VT_DATE.
7240 * PARAMS
7241 * fltIn [I] Source
7242 * pdateOut [O] Destination
7244 * RETURNS
7245 * S_OK.
7247 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
7249 return VarR8FromR4(fltIn, pdateOut);
7252 /******************************************************************************
7253 * VarDateFromR8 (OLEAUT32.92)
7255 * Convert a VT_R8 to a VT_DATE.
7257 * PARAMS
7258 * dblIn [I] Source
7259 * pdateOut [O] Destination
7261 * RETURNS
7262 * S_OK.
7264 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
7266 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
7267 *pdateOut = (DATE)dblIn;
7268 return S_OK;
7271 /**********************************************************************
7272 * VarDateFromDisp (OLEAUT32.95)
7274 * Convert a VT_DISPATCH to a VT_DATE.
7276 * PARAMS
7277 * pdispIn [I] Source
7278 * lcid [I] LCID for conversion
7279 * pdateOut [O] Destination
7281 * RETURNS
7282 * Success: S_OK.
7283 * Failure: E_INVALIDARG, if the source value is invalid
7284 * DISP_E_OVERFLOW, if the value will not fit in the destination
7285 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7287 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
7289 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
7292 /******************************************************************************
7293 * VarDateFromBool (OLEAUT32.96)
7295 * Convert a VT_BOOL to a VT_DATE.
7297 * PARAMS
7298 * boolIn [I] Source
7299 * pdateOut [O] Destination
7301 * RETURNS
7302 * S_OK.
7304 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
7306 return VarR8FromBool(boolIn, pdateOut);
7309 /**********************************************************************
7310 * VarDateFromCy (OLEAUT32.93)
7312 * Convert a VT_CY to a VT_DATE.
7314 * PARAMS
7315 * lIn [I] Source
7316 * pdateOut [O] Destination
7318 * RETURNS
7319 * S_OK.
7321 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
7323 return VarR8FromCy(cyIn, pdateOut);
7326 /* Date string parsing */
7327 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7328 #define DP_DATESEP 0x02 /* Date separator */
7329 #define DP_MONTH 0x04 /* Month name */
7330 #define DP_AM 0x08 /* AM */
7331 #define DP_PM 0x10 /* PM */
7333 typedef struct tagDATEPARSE
7335 DWORD dwCount; /* Number of fields found so far (maximum 6) */
7336 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
7337 DWORD dwFlags[6]; /* Flags for each field */
7338 DWORD dwValues[6]; /* Value of each field */
7339 } DATEPARSE;
7341 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7343 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7345 /* Determine if a day is valid in a given month of a given year */
7346 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
7348 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7350 if (day && month && month < 13)
7352 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
7353 return TRUE;
7355 return FALSE;
7358 /* Possible orders for 3 numbers making up a date */
7359 #define ORDER_MDY 0x01
7360 #define ORDER_YMD 0x02
7361 #define ORDER_YDM 0x04
7362 #define ORDER_DMY 0x08
7363 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7365 /* Determine a date for a particular locale, from 3 numbers */
7366 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
7367 DWORD offset, SYSTEMTIME *st)
7369 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
7371 if (!dp->dwCount)
7373 v1 = 30; /* Default to (Variant) 0 date part */
7374 v2 = 12;
7375 v3 = 1899;
7376 goto VARIANT_MakeDate_OK;
7379 v1 = dp->dwValues[offset + 0];
7380 v2 = dp->dwValues[offset + 1];
7381 if (dp->dwCount == 2)
7383 SYSTEMTIME current;
7384 GetSystemTime(&current);
7385 v3 = current.wYear;
7387 else
7388 v3 = dp->dwValues[offset + 2];
7390 TRACE("(%d,%d,%d,%d,%d)\n", v1, v2, v3, iDate, offset);
7392 /* If one number must be a month (Because a month name was given), then only
7393 * consider orders with the month in that position.
7394 * If we took the current year as 'v3', then only allow a year in that position.
7396 if (dp->dwFlags[offset + 0] & DP_MONTH)
7398 dwAllOrders = ORDER_MDY;
7400 else if (dp->dwFlags[offset + 1] & DP_MONTH)
7402 dwAllOrders = ORDER_DMY;
7403 if (dp->dwCount > 2)
7404 dwAllOrders |= ORDER_YMD;
7406 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
7408 dwAllOrders = ORDER_YDM;
7410 else
7412 dwAllOrders = ORDER_MDY|ORDER_DMY;
7413 if (dp->dwCount > 2)
7414 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
7417 VARIANT_MakeDate_Start:
7418 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders);
7420 while (dwAllOrders)
7422 DWORD dwTemp;
7424 if (dwCount == 0)
7426 /* First: Try the order given by iDate */
7427 switch (iDate)
7429 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
7430 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
7431 default: dwTry = dwAllOrders & ORDER_YMD; break;
7434 else if (dwCount == 1)
7436 /* Second: Try all the orders compatible with iDate */
7437 switch (iDate)
7439 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7440 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YDM|ORDER_MYD); break;
7441 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7444 else
7446 /* Finally: Try any remaining orders */
7447 dwTry = dwAllOrders;
7450 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount, dwTry);
7452 dwCount++;
7453 if (!dwTry)
7454 continue;
7456 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7458 if (dwTry & ORDER_MDY)
7460 if (VARIANT_IsValidMonthDay(v2,v1,v3))
7462 DATE_SWAP(v1,v2);
7463 goto VARIANT_MakeDate_OK;
7465 dwAllOrders &= ~ORDER_MDY;
7467 if (dwTry & ORDER_YMD)
7469 if (VARIANT_IsValidMonthDay(v3,v2,v1))
7471 DATE_SWAP(v1,v3);
7472 goto VARIANT_MakeDate_OK;
7474 dwAllOrders &= ~ORDER_YMD;
7476 if (dwTry & ORDER_YDM)
7478 if (VARIANT_IsValidMonthDay(v2,v3,v1))
7480 DATE_SWAP(v1,v2);
7481 DATE_SWAP(v2,v3);
7482 goto VARIANT_MakeDate_OK;
7484 dwAllOrders &= ~ORDER_YDM;
7486 if (dwTry & ORDER_DMY)
7488 if (VARIANT_IsValidMonthDay(v1,v2,v3))
7489 goto VARIANT_MakeDate_OK;
7490 dwAllOrders &= ~ORDER_DMY;
7492 if (dwTry & ORDER_MYD)
7494 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7495 if (VARIANT_IsValidMonthDay(v3,v1,v2))
7497 DATE_SWAP(v1,v3);
7498 DATE_SWAP(v2,v3);
7499 goto VARIANT_MakeDate_OK;
7501 dwAllOrders &= ~ORDER_MYD;
7505 if (dp->dwCount == 2)
7507 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7508 v3 = 1; /* 1st of the month */
7509 dwAllOrders = ORDER_YMD|ORDER_MYD;
7510 dp->dwCount = 0; /* Don't return to this code path again */
7511 dwCount = 0;
7512 goto VARIANT_MakeDate_Start;
7515 /* No valid dates were able to be constructed */
7516 return DISP_E_TYPEMISMATCH;
7518 VARIANT_MakeDate_OK:
7520 /* Check that the time part is ok */
7521 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
7522 return DISP_E_TYPEMISMATCH;
7524 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7525 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
7526 st->wHour += 12;
7527 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
7528 st->wHour = 0;
7529 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7531 st->wDay = v1;
7532 st->wMonth = v2;
7533 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7534 * be retrieved from:
7535 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7536 * But Wine doesn't have/use that key as at the time of writing.
7538 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
7539 TRACE("Returning date %d/%d/%d\n", v1, v2, st->wYear);
7540 return S_OK;
7543 /******************************************************************************
7544 * VarDateFromStr [OLEAUT32.94]
7546 * Convert a VT_BSTR to at VT_DATE.
7548 * PARAMS
7549 * strIn [I] String to convert
7550 * lcid [I] Locale identifier for the conversion
7551 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7552 * pdateOut [O] Destination for the converted value
7554 * RETURNS
7555 * Success: S_OK. pdateOut contains the converted value.
7556 * FAILURE: An HRESULT error code indicating the problem.
7558 * NOTES
7559 * Any date format that can be created using the date formats from lcid
7560 * (Either from kernel Nls functions, variant conversion or formatting) is a
7561 * valid input to this function. In addition, a few more esoteric formats are
7562 * also supported for compatibility with the native version. The date is
7563 * interpreted according to the date settings in the control panel, unless
7564 * the date is invalid in that format, in which the most compatible format
7565 * that produces a valid date will be used.
7567 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7569 static const USHORT ParseDateTokens[] =
7571 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7572 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7573 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7574 LOCALE_SMONTHNAME13,
7575 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7576 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7577 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7578 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7579 LOCALE_SABBREVMONTHNAME13,
7580 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7581 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7582 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7583 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7584 LOCALE_SABBREVDAYNAME7,
7585 LOCALE_S1159, LOCALE_S2359,
7586 LOCALE_SDATE
7588 static const BYTE ParseDateMonths[] =
7590 1,2,3,4,5,6,7,8,9,10,11,12,13,
7591 1,2,3,4,5,6,7,8,9,10,11,12,13
7593 unsigned int i;
7594 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
7595 DATEPARSE dp;
7596 DWORD dwDateSeps = 0, iDate = 0;
7597 HRESULT hRet = S_OK;
7599 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7600 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7601 return E_INVALIDARG;
7603 if (!strIn)
7604 return DISP_E_TYPEMISMATCH;
7606 *pdateOut = 0.0;
7608 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7610 memset(&dp, 0, sizeof(dp));
7612 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7613 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7614 TRACE("iDate is %d\n", iDate);
7616 /* Get the month/day/am/pm tokens for this locale */
7617 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7619 WCHAR buff[128];
7620 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7622 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7623 * GetAltMonthNames(). We should really cache these strings too.
7625 buff[0] = '\0';
7626 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
7627 tokens[i] = SysAllocString(buff);
7628 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7631 /* Parse the string into our structure */
7632 while (*strIn)
7634 if (dp.dwCount >= 6)
7635 break;
7637 if (isdigitW(*strIn))
7639 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
7640 dp.dwCount++;
7641 strIn--;
7643 else if (isalpha(*strIn))
7645 BOOL bFound = FALSE;
7647 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7649 DWORD dwLen = strlenW(tokens[i]);
7650 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
7652 if (i <= 25)
7654 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7655 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7656 dp.dwCount++;
7658 else if (i > 39 && i < 42)
7660 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7661 hRet = DISP_E_TYPEMISMATCH;
7662 else
7664 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7665 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7668 strIn += (dwLen - 1);
7669 bFound = TRUE;
7670 break;
7674 if (!bFound)
7676 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7677 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7679 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7680 if (*strIn == 'a' || *strIn == 'A')
7682 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7683 dp.dwParseFlags |= DP_AM;
7685 else
7687 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7688 dp.dwParseFlags |= DP_PM;
7690 strIn++;
7692 else
7694 TRACE("No matching token for %s\n", debugstr_w(strIn));
7695 hRet = DISP_E_TYPEMISMATCH;
7696 break;
7700 else if (*strIn == ':' || *strIn == '.')
7702 if (!dp.dwCount || !strIn[1])
7703 hRet = DISP_E_TYPEMISMATCH;
7704 else
7705 if (tokens[42][0] == *strIn)
7707 dwDateSeps++;
7708 if (dwDateSeps > 2)
7709 hRet = DISP_E_TYPEMISMATCH;
7710 else
7711 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7713 else
7714 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7716 else if (*strIn == '-' || *strIn == '/')
7718 dwDateSeps++;
7719 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7720 hRet = DISP_E_TYPEMISMATCH;
7721 else
7722 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7724 else if (*strIn == ',' || isspaceW(*strIn))
7726 if (*strIn == ',' && !strIn[1])
7727 hRet = DISP_E_TYPEMISMATCH;
7729 else
7731 hRet = DISP_E_TYPEMISMATCH;
7733 strIn++;
7736 if (!dp.dwCount || dp.dwCount > 6 ||
7737 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7738 hRet = DISP_E_TYPEMISMATCH;
7740 if (SUCCEEDED(hRet))
7742 SYSTEMTIME st;
7743 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7745 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7747 /* Figure out which numbers correspond to which fields.
7749 * This switch statement works based on the fact that native interprets any
7750 * fields that are not joined with a time separator ('.' or ':') as date
7751 * fields. Thus we construct a value from 0-32 where each set bit indicates
7752 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7753 * For valid permutations, we set dwOffset to point to the first date field
7754 * and shorten dp.dwCount by the number of time fields found. The real
7755 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7756 * each date number must represent in the context of iDate.
7758 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7760 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7762 case 0x1: /* TT TTDD TTDDD */
7763 if (dp.dwCount > 3 &&
7764 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7765 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7766 hRet = DISP_E_TYPEMISMATCH;
7767 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7768 hRet = DISP_E_TYPEMISMATCH;
7769 st.wHour = dp.dwValues[0];
7770 st.wMinute = dp.dwValues[1];
7771 dp.dwCount -= 2;
7772 dwOffset = 2;
7773 break;
7775 case 0x3: /* TTT TTTDD TTTDDD */
7776 if (dp.dwCount > 4 &&
7777 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7778 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7779 hRet = DISP_E_TYPEMISMATCH;
7780 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7781 hRet = DISP_E_TYPEMISMATCH;
7782 st.wHour = dp.dwValues[0];
7783 st.wMinute = dp.dwValues[1];
7784 st.wSecond = dp.dwValues[2];
7785 dwOffset = 3;
7786 dp.dwCount -= 3;
7787 break;
7789 case 0x4: /* DDTT */
7790 if (dp.dwCount != 4 ||
7791 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7792 hRet = DISP_E_TYPEMISMATCH;
7794 st.wHour = dp.dwValues[2];
7795 st.wMinute = dp.dwValues[3];
7796 dp.dwCount -= 2;
7797 break;
7799 case 0x0: /* T DD DDD TDDD TDDD */
7800 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7802 st.wHour = dp.dwValues[0]; /* T */
7803 dp.dwCount = 0;
7804 break;
7806 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7808 hRet = DISP_E_TYPEMISMATCH;
7810 else if (dp.dwCount == 3)
7812 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7814 dp.dwCount = 2;
7815 st.wHour = dp.dwValues[0];
7816 dwOffset = 1;
7817 break;
7819 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7821 dp.dwCount = 2;
7822 st.wHour = dp.dwValues[2];
7823 break;
7825 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7826 hRet = DISP_E_TYPEMISMATCH;
7828 else if (dp.dwCount == 4)
7830 dp.dwCount = 3;
7831 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7833 st.wHour = dp.dwValues[0];
7834 dwOffset = 1;
7836 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7838 st.wHour = dp.dwValues[3];
7840 else
7841 hRet = DISP_E_TYPEMISMATCH;
7842 break;
7844 /* .. fall through .. */
7846 case 0x8: /* DDDTT */
7847 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7848 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7849 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7850 dp.dwCount == 4 || dp.dwCount == 6)
7851 hRet = DISP_E_TYPEMISMATCH;
7852 st.wHour = dp.dwValues[3];
7853 st.wMinute = dp.dwValues[4];
7854 if (dp.dwCount == 5)
7855 dp.dwCount -= 2;
7856 break;
7858 case 0xC: /* DDTTT */
7859 if (dp.dwCount != 5 ||
7860 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7861 hRet = DISP_E_TYPEMISMATCH;
7862 st.wHour = dp.dwValues[2];
7863 st.wMinute = dp.dwValues[3];
7864 st.wSecond = dp.dwValues[4];
7865 dp.dwCount -= 3;
7866 break;
7868 case 0x18: /* DDDTTT */
7869 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7870 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7871 hRet = DISP_E_TYPEMISMATCH;
7872 st.wHour = dp.dwValues[3];
7873 st.wMinute = dp.dwValues[4];
7874 st.wSecond = dp.dwValues[5];
7875 dp.dwCount -= 3;
7876 break;
7878 default:
7879 hRet = DISP_E_TYPEMISMATCH;
7880 break;
7883 if (SUCCEEDED(hRet))
7885 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7887 if (dwFlags & VAR_TIMEVALUEONLY)
7889 st.wYear = 1899;
7890 st.wMonth = 12;
7891 st.wDay = 30;
7893 else if (dwFlags & VAR_DATEVALUEONLY)
7894 st.wHour = st.wMinute = st.wSecond = 0;
7896 /* Finally, convert the value to a VT_DATE */
7897 if (SUCCEEDED(hRet))
7898 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7902 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7903 SysFreeString(tokens[i]);
7904 return hRet;
7907 /******************************************************************************
7908 * VarDateFromI1 (OLEAUT32.221)
7910 * Convert a VT_I1 to a VT_DATE.
7912 * PARAMS
7913 * cIn [I] Source
7914 * pdateOut [O] Destination
7916 * RETURNS
7917 * S_OK.
7919 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7921 return VarR8FromI1(cIn, pdateOut);
7924 /******************************************************************************
7925 * VarDateFromUI2 (OLEAUT32.222)
7927 * Convert a VT_UI2 to a VT_DATE.
7929 * PARAMS
7930 * uiIn [I] Source
7931 * pdateOut [O] Destination
7933 * RETURNS
7934 * S_OK.
7936 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7938 return VarR8FromUI2(uiIn, pdateOut);
7941 /******************************************************************************
7942 * VarDateFromUI4 (OLEAUT32.223)
7944 * Convert a VT_UI4 to a VT_DATE.
7946 * PARAMS
7947 * ulIn [I] Source
7948 * pdateOut [O] Destination
7950 * RETURNS
7951 * S_OK.
7953 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7955 return VarDateFromR8(ulIn, pdateOut);
7958 /**********************************************************************
7959 * VarDateFromDec (OLEAUT32.224)
7961 * Convert a VT_DECIMAL to a VT_DATE.
7963 * PARAMS
7964 * pdecIn [I] Source
7965 * pdateOut [O] Destination
7967 * RETURNS
7968 * S_OK.
7970 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
7972 return VarR8FromDec(pdecIn, pdateOut);
7975 /******************************************************************************
7976 * VarDateFromI8 (OLEAUT32.364)
7978 * Convert a VT_I8 to a VT_DATE.
7980 * PARAMS
7981 * llIn [I] Source
7982 * pdateOut [O] Destination
7984 * RETURNS
7985 * Success: S_OK.
7986 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7988 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
7990 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
7991 *pdateOut = (DATE)llIn;
7992 return S_OK;
7995 /******************************************************************************
7996 * VarDateFromUI8 (OLEAUT32.365)
7998 * Convert a VT_UI8 to a VT_DATE.
8000 * PARAMS
8001 * ullIn [I] Source
8002 * pdateOut [O] Destination
8004 * RETURNS
8005 * Success: S_OK.
8006 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8008 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
8010 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
8011 *pdateOut = (DATE)ullIn;
8012 return S_OK;