winewayland.drv: Update desktop window size on display changes.
[wine.git] / dlls / oleaut32 / vartype.c
blobbc8bd0d2197c892fc52b1d1271491468f403a7f7
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 "winbase.h"
27 #include "winuser.h"
28 #include "winnt.h"
29 #include "variant.h"
30 #include "resource.h"
32 #include "locale.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(variant);
36 extern HMODULE hProxyDll DECLSPEC_HIDDEN;
38 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
39 #define CY_MULTIPLIER_F 10000.0
40 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
41 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
43 /* Copy data from one variant to another. */
44 static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
46 switch (vt)
48 case VT_I1:
49 case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
50 case VT_BOOL:
51 case VT_I2:
52 case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
53 case VT_R4:
54 case VT_INT:
55 case VT_I4:
56 case VT_UINT:
57 case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
58 case VT_R8:
59 case VT_DATE:
60 case VT_CY:
61 case VT_I8:
62 case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break;
63 case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break;
64 case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
65 case VT_BSTR: memcpy(pOut, &V_BSTR(srcVar), sizeof(BSTR)); break;
66 default:
67 FIXME("VT_ type %d unhandled, please report!\n", vt);
71 /* Macro to inline conversion from a float or double to any integer type,
72 * rounding according to the 'dutch' convention.
74 #define VARIANT_DutchRound(typ, value, res) do { \
75 double whole = value < 0 ? ceil(value) : floor(value); \
76 double fract = value - whole; \
77 if (fract > 0.5) res = (typ)whole + (typ)1; \
78 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
79 else if (fract >= 0.0) res = (typ)whole; \
80 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
81 else if (fract > -0.5) res = (typ)whole; \
82 else res = (typ)whole - (typ)1; \
83 } while(0)
86 /* Coerce VT_BSTR to a numeric type */
87 static HRESULT VARIANT_NumberFromBstr(const OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
88 void* pOut, VARTYPE vt)
90 VARIANTARG dstVar;
91 HRESULT hRet;
92 NUMPARSE np;
93 BYTE rgb[1024];
95 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
96 np.cDig = ARRAY_SIZE(rgb);
97 np.dwInFlags = NUMPRS_STD;
99 hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
101 if (SUCCEEDED(hRet))
103 /* 1 << vt gives us the VTBIT constant for the destination number type */
104 hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
105 if (SUCCEEDED(hRet))
106 VARIANT_CopyData(&dstVar, vt, pOut);
108 return hRet;
111 /* Coerce VT_DISPATCH to another type */
112 static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut,
113 VARTYPE vt, DWORD dwFlags)
115 static DISPPARAMS emptyParams = { NULL, NULL, 0, 0 };
116 VARIANTARG srcVar, dstVar;
117 HRESULT hRet;
119 if (!pdispIn)
120 return DISP_E_BADVARTYPE;
122 /* Get the default 'value' property from the IDispatch */
123 VariantInit(&srcVar);
124 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
125 &emptyParams, &srcVar, NULL, NULL);
127 if (SUCCEEDED(hRet))
129 /* Convert the property to the requested type */
130 VariantInit(&dstVar);
131 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt);
132 VariantClear(&srcVar);
134 if (SUCCEEDED(hRet))
135 VARIANT_CopyData(&dstVar, vt, pOut);
137 else
138 hRet = DISP_E_TYPEMISMATCH;
139 return hRet;
142 /* Inline return type */
143 #define RETTYP static inline HRESULT
146 /* Simple compiler cast from one type to another */
147 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
148 *out = in; return S_OK; }
150 /* Compiler cast where input cannot be negative */
151 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
152 if (in < 0) { return DISP_E_OVERFLOW; } *out = in; return S_OK; }
154 /* Compiler cast where input cannot be > some number */
155 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
156 if (in > (dest)tst) { return DISP_E_OVERFLOW; } *out = in; return S_OK; }
158 /* Compiler cast where input cannot be < some number or >= some other number */
159 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
160 if (in < (dest)lo || in > hi) { return DISP_E_OVERFLOW; } *out = in; return S_OK; }
162 /* I1 */
163 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX)
164 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX)
165 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX)
166 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool)
167 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX)
168 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX)
169 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX)
170 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX)
172 /* UI1 */
173 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX)
174 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool)
175 NEGTST(BYTE, signed char, VarUI1FromI1)
176 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX)
177 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX)
178 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX)
179 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX)
180 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX)
182 /* I2 */
183 SIMPLE(SHORT, BYTE, VarI2FromUI1)
184 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX)
185 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool)
186 SIMPLE(SHORT, signed char, VarI2FromI1)
187 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX)
188 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX)
189 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX)
190 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX)
192 /* UI2 */
193 SIMPLE(USHORT, BYTE, VarUI2FromUI1)
194 NEGTST(USHORT, SHORT, VarUI2FromI2)
195 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX)
196 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool)
197 NEGTST(USHORT, signed char, VarUI2FromI1)
198 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX)
199 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX)
200 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX)
202 /* I4 */
203 SIMPLE(LONG, BYTE, VarI4FromUI1)
204 SIMPLE(LONG, SHORT, VarI4FromI2)
205 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool)
206 SIMPLE(LONG, signed char, VarI4FromI1)
207 SIMPLE(LONG, USHORT, VarI4FromUI2)
208 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX)
209 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX)
210 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX)
212 /* UI4 */
213 SIMPLE(ULONG, BYTE, VarUI4FromUI1)
214 NEGTST(ULONG, SHORT, VarUI4FromI2)
215 NEGTST(ULONG, LONG, VarUI4FromI4)
216 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool)
217 NEGTST(ULONG, signed char, VarUI4FromI1)
218 SIMPLE(ULONG, USHORT, VarUI4FromUI2)
219 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX)
220 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX)
222 /* I8 */
223 SIMPLE(LONG64, BYTE, VarI8FromUI1)
224 SIMPLE(LONG64, SHORT, VarI8FromI2)
225 SIMPLE(LONG64, signed char, VarI8FromI1)
226 SIMPLE(LONG64, USHORT, VarI8FromUI2)
227 SIMPLE(LONG64, ULONG, VarI8FromUI4)
228 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX)
230 /* UI8 */
231 SIMPLE(ULONG64, BYTE, VarUI8FromUI1)
232 NEGTST(ULONG64, SHORT, VarUI8FromI2)
233 NEGTST(ULONG64, signed char, VarUI8FromI1)
234 SIMPLE(ULONG64, USHORT, VarUI8FromUI2)
235 SIMPLE(ULONG64, ULONG, VarUI8FromUI4)
236 NEGTST(ULONG64, LONG64, VarUI8FromI8)
238 /* R4 (float) */
239 SIMPLE(float, BYTE, VarR4FromUI1)
240 SIMPLE(float, SHORT, VarR4FromI2)
241 SIMPLE(float, signed char, VarR4FromI1)
242 SIMPLE(float, USHORT, VarR4FromUI2)
243 SIMPLE(float, LONG, VarR4FromI4)
244 SIMPLE(float, ULONG, VarR4FromUI4)
245 SIMPLE(float, LONG64, VarR4FromI8)
246 SIMPLE(float, ULONG64, VarR4FromUI8)
248 /* R8 (double) */
249 SIMPLE(double, BYTE, VarR8FromUI1)
250 SIMPLE(double, SHORT, VarR8FromI2)
251 SIMPLE(double, float, VarR8FromR4)
252 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
253 SIMPLE(double, DATE, VarR8FromDate)
254 SIMPLE(double, signed char, VarR8FromI1)
255 SIMPLE(double, USHORT, VarR8FromUI2)
256 SIMPLE(double, LONG, VarR8FromI4)
257 SIMPLE(double, ULONG, VarR8FromUI4)
258 SIMPLE(double, LONG64, VarR8FromI8)
259 SIMPLE(double, ULONG64, VarR8FromUI8)
262 /* I1
265 /************************************************************************
266 * VarI1FromUI1 (OLEAUT32.244)
268 * Convert a VT_UI1 to a VT_I1.
270 * PARAMS
271 * bIn [I] Source
272 * pcOut [O] Destination
274 * RETURNS
275 * Success: S_OK.
276 * Failure: E_INVALIDARG, if the source value is invalid
277 * DISP_E_OVERFLOW, if the value will not fit in the destination
279 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
281 return _VarI1FromUI1(bIn, pcOut);
284 /************************************************************************
285 * VarI1FromI2 (OLEAUT32.245)
287 * Convert a VT_I2 to a VT_I1.
289 * PARAMS
290 * sIn [I] Source
291 * pcOut [O] Destination
293 * RETURNS
294 * Success: S_OK.
295 * Failure: E_INVALIDARG, if the source value is invalid
296 * DISP_E_OVERFLOW, if the value will not fit in the destination
298 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
300 return _VarI1FromI2(sIn, pcOut);
303 /************************************************************************
304 * VarI1FromI4 (OLEAUT32.246)
306 * Convert a VT_I4 to a VT_I1.
308 * PARAMS
309 * iIn [I] Source
310 * pcOut [O] Destination
312 * RETURNS
313 * Success: S_OK.
314 * Failure: E_INVALIDARG, if the source value is invalid
315 * DISP_E_OVERFLOW, if the value will not fit in the destination
317 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
319 return _VarI1FromI4(iIn, pcOut);
322 /************************************************************************
323 * VarI1FromR4 (OLEAUT32.247)
325 * Convert a VT_R4 to a VT_I1.
327 * PARAMS
328 * fltIn [I] Source
329 * pcOut [O] Destination
331 * RETURNS
332 * Success: S_OK.
333 * Failure: E_INVALIDARG, if the source value is invalid
334 * DISP_E_OVERFLOW, if the value will not fit in the destination
336 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
338 return VarI1FromR8(fltIn, pcOut);
341 /************************************************************************
342 * VarI1FromR8 (OLEAUT32.248)
344 * Convert a VT_R8 to a VT_I1.
346 * PARAMS
347 * dblIn [I] Source
348 * pcOut [O] Destination
350 * RETURNS
351 * Success: S_OK.
352 * Failure: E_INVALIDARG, if the source value is invalid
353 * DISP_E_OVERFLOW, if the value will not fit in the destination
355 * NOTES
356 * See VarI8FromR8() for details concerning rounding.
358 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
360 if (dblIn < I1_MIN - 0.5 || dblIn >= I1_MAX + 0.5)
361 return DISP_E_OVERFLOW;
362 VARIANT_DutchRound(CHAR, dblIn, *pcOut);
363 return S_OK;
366 /************************************************************************
367 * VarI1FromDate (OLEAUT32.249)
369 * Convert a VT_DATE to a VT_I1.
371 * PARAMS
372 * dateIn [I] Source
373 * pcOut [O] Destination
375 * RETURNS
376 * Success: S_OK.
377 * Failure: E_INVALIDARG, if the source value is invalid
378 * DISP_E_OVERFLOW, if the value will not fit in the destination
380 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
382 return VarI1FromR8(dateIn, pcOut);
385 /************************************************************************
386 * VarI1FromCy (OLEAUT32.250)
388 * Convert a VT_CY to a VT_I1.
390 * PARAMS
391 * cyIn [I] Source
392 * pcOut [O] Destination
394 * RETURNS
395 * Success: S_OK.
396 * Failure: E_INVALIDARG, if the source value is invalid
397 * DISP_E_OVERFLOW, if the value will not fit in the destination
399 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
401 LONG i = I1_MAX + 1;
403 VarI4FromCy(cyIn, &i);
404 return _VarI1FromI4(i, pcOut);
407 /************************************************************************
408 * VarI1FromStr (OLEAUT32.251)
410 * Convert a VT_BSTR to a VT_I1.
412 * PARAMS
413 * strIn [I] Source
414 * lcid [I] LCID for the conversion
415 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
416 * pcOut [O] Destination
418 * RETURNS
419 * Success: S_OK.
420 * Failure: E_INVALIDARG, if the source value is invalid
421 * DISP_E_OVERFLOW, if the value will not fit in the destination
422 * DISP_E_TYPEMISMATCH, if the type cannot be converted
424 HRESULT WINAPI VarI1FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
426 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
429 /************************************************************************
430 * VarI1FromDisp (OLEAUT32.252)
432 * Convert a VT_DISPATCH to a VT_I1.
434 * PARAMS
435 * pdispIn [I] Source
436 * lcid [I] LCID for conversion
437 * pcOut [O] Destination
439 * RETURNS
440 * Success: S_OK.
441 * Failure: E_INVALIDARG, if the source value is invalid
442 * DISP_E_OVERFLOW, if the value will not fit in the destination
443 * DISP_E_TYPEMISMATCH, if the type cannot be converted
445 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
447 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0);
450 /************************************************************************
451 * VarI1FromBool (OLEAUT32.253)
453 * Convert a VT_BOOL to a VT_I1.
455 * PARAMS
456 * boolIn [I] Source
457 * pcOut [O] Destination
459 * RETURNS
460 * S_OK.
462 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
464 return _VarI1FromBool(boolIn, pcOut);
467 /************************************************************************
468 * VarI1FromUI2 (OLEAUT32.254)
470 * Convert a VT_UI2 to a VT_I1.
472 * PARAMS
473 * usIn [I] Source
474 * pcOut [O] Destination
476 * RETURNS
477 * Success: S_OK.
478 * Failure: E_INVALIDARG, if the source value is invalid
479 * DISP_E_OVERFLOW, if the value will not fit in the destination
481 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
483 return _VarI1FromUI2(usIn, pcOut);
486 /************************************************************************
487 * VarI1FromUI4 (OLEAUT32.255)
489 * Convert a VT_UI4 to a VT_I1.
491 * PARAMS
492 * ulIn [I] Source
493 * pcOut [O] Destination
495 * RETURNS
496 * Success: S_OK.
497 * Failure: E_INVALIDARG, if the source value is invalid
498 * DISP_E_OVERFLOW, if the value will not fit in the destination
499 * DISP_E_TYPEMISMATCH, if the type cannot be converted
501 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
503 return _VarI1FromUI4(ulIn, pcOut);
506 /************************************************************************
507 * VarI1FromDec (OLEAUT32.256)
509 * Convert a VT_DECIMAL to a VT_I1.
511 * PARAMS
512 * pDecIn [I] Source
513 * pcOut [O] Destination
515 * RETURNS
516 * Success: S_OK.
517 * Failure: E_INVALIDARG, if the source value is invalid
518 * DISP_E_OVERFLOW, if the value will not fit in the destination
520 HRESULT WINAPI VarI1FromDec(const DECIMAL *pdecIn, signed char* pcOut)
522 LONG64 i64;
523 HRESULT hRet;
525 hRet = VarI8FromDec(pdecIn, &i64);
527 if (SUCCEEDED(hRet))
528 hRet = _VarI1FromI8(i64, pcOut);
529 return hRet;
532 /************************************************************************
533 * VarI1FromI8 (OLEAUT32.376)
535 * Convert a VT_I8 to a VT_I1.
537 * PARAMS
538 * llIn [I] Source
539 * pcOut [O] Destination
541 * RETURNS
542 * Success: S_OK.
543 * Failure: E_INVALIDARG, if the source value is invalid
544 * DISP_E_OVERFLOW, if the value will not fit in the destination
546 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
548 return _VarI1FromI8(llIn, pcOut);
551 /************************************************************************
552 * VarI1FromUI8 (OLEAUT32.377)
554 * Convert a VT_UI8 to a VT_I1.
556 * PARAMS
557 * ullIn [I] Source
558 * pcOut [O] Destination
560 * RETURNS
561 * Success: S_OK.
562 * Failure: E_INVALIDARG, if the source value is invalid
563 * DISP_E_OVERFLOW, if the value will not fit in the destination
565 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
567 return _VarI1FromUI8(ullIn, pcOut);
570 /* UI1
573 /************************************************************************
574 * VarUI1FromI2 (OLEAUT32.130)
576 * Convert a VT_I2 to a VT_UI1.
578 * PARAMS
579 * sIn [I] Source
580 * pbOut [O] Destination
582 * RETURNS
583 * Success: S_OK.
584 * Failure: E_INVALIDARG, if the source value is invalid
585 * DISP_E_OVERFLOW, if the value will not fit in the destination
587 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
589 return _VarUI1FromI2(sIn, pbOut);
592 /************************************************************************
593 * VarUI1FromI4 (OLEAUT32.131)
595 * Convert a VT_I4 to a VT_UI1.
597 * PARAMS
598 * iIn [I] Source
599 * pbOut [O] Destination
601 * RETURNS
602 * Success: S_OK.
603 * Failure: E_INVALIDARG, if the source value is invalid
604 * DISP_E_OVERFLOW, if the value will not fit in the destination
606 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
608 return _VarUI1FromI4(iIn, pbOut);
611 /************************************************************************
612 * VarUI1FromR4 (OLEAUT32.132)
614 * Convert a VT_R4 to a VT_UI1.
616 * PARAMS
617 * fltIn [I] Source
618 * pbOut [O] Destination
620 * RETURNS
621 * Success: S_OK.
622 * Failure: E_INVALIDARG, if the source value is invalid
623 * DISP_E_OVERFLOW, if the value will not fit in the destination
624 * DISP_E_TYPEMISMATCH, if the type cannot be converted
626 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
628 return VarUI1FromR8(fltIn, pbOut);
631 /************************************************************************
632 * VarUI1FromR8 (OLEAUT32.133)
634 * Convert a VT_R8 to a VT_UI1.
636 * PARAMS
637 * dblIn [I] Source
638 * pbOut [O] Destination
640 * RETURNS
641 * Success: S_OK.
642 * Failure: E_INVALIDARG, if the source value is invalid
643 * DISP_E_OVERFLOW, if the value will not fit in the destination
645 * NOTES
646 * See VarI8FromR8() for details concerning rounding.
648 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
650 if (dblIn < -0.5 || dblIn >= UI1_MAX + 0.5)
651 return DISP_E_OVERFLOW;
652 VARIANT_DutchRound(BYTE, dblIn, *pbOut);
653 return S_OK;
656 /************************************************************************
657 * VarUI1FromCy (OLEAUT32.134)
659 * Convert a VT_CY to a VT_UI1.
661 * PARAMS
662 * cyIn [I] Source
663 * pbOut [O] Destination
665 * RETURNS
666 * Success: S_OK.
667 * Failure: E_INVALIDARG, if the source value is invalid
668 * DISP_E_OVERFLOW, if the value will not fit in the destination
670 * NOTES
671 * Negative values >= -5000 will be converted to 0.
673 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
675 ULONG i = UI1_MAX + 1;
677 VarUI4FromCy(cyIn, &i);
678 return _VarUI1FromUI4(i, pbOut);
681 /************************************************************************
682 * VarUI1FromDate (OLEAUT32.135)
684 * Convert a VT_DATE to a VT_UI1.
686 * PARAMS
687 * dateIn [I] Source
688 * pbOut [O] Destination
690 * RETURNS
691 * Success: S_OK.
692 * Failure: E_INVALIDARG, if the source value is invalid
693 * DISP_E_OVERFLOW, if the value will not fit in the destination
695 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
697 return VarUI1FromR8(dateIn, pbOut);
700 /************************************************************************
701 * VarUI1FromStr (OLEAUT32.136)
703 * Convert a VT_BSTR to a VT_UI1.
705 * PARAMS
706 * strIn [I] Source
707 * lcid [I] LCID for the conversion
708 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
709 * pbOut [O] Destination
711 * RETURNS
712 * Success: S_OK.
713 * Failure: E_INVALIDARG, if the source value is invalid
714 * DISP_E_OVERFLOW, if the value will not fit in the destination
715 * DISP_E_TYPEMISMATCH, if the type cannot be converted
717 HRESULT WINAPI VarUI1FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
719 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
722 /************************************************************************
723 * VarUI1FromDisp (OLEAUT32.137)
725 * Convert a VT_DISPATCH to a VT_UI1.
727 * PARAMS
728 * pdispIn [I] Source
729 * lcid [I] LCID for conversion
730 * pbOut [O] Destination
732 * RETURNS
733 * Success: S_OK.
734 * Failure: E_INVALIDARG, if the source value is invalid
735 * DISP_E_OVERFLOW, if the value will not fit in the destination
736 * DISP_E_TYPEMISMATCH, if the type cannot be converted
738 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
740 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0);
743 /************************************************************************
744 * VarUI1FromBool (OLEAUT32.138)
746 * Convert a VT_BOOL to a VT_UI1.
748 * PARAMS
749 * boolIn [I] Source
750 * pbOut [O] Destination
752 * RETURNS
753 * S_OK.
755 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
757 return _VarUI1FromBool(boolIn, pbOut);
760 /************************************************************************
761 * VarUI1FromI1 (OLEAUT32.237)
763 * Convert a VT_I1 to a VT_UI1.
765 * PARAMS
766 * cIn [I] Source
767 * pbOut [O] Destination
769 * RETURNS
770 * Success: S_OK.
771 * Failure: E_INVALIDARG, if the source value is invalid
772 * DISP_E_OVERFLOW, if the value will not fit in the destination
774 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
776 return _VarUI1FromI1(cIn, pbOut);
779 /************************************************************************
780 * VarUI1FromUI2 (OLEAUT32.238)
782 * Convert a VT_UI2 to a VT_UI1.
784 * PARAMS
785 * usIn [I] Source
786 * pbOut [O] Destination
788 * RETURNS
789 * Success: S_OK.
790 * Failure: E_INVALIDARG, if the source value is invalid
791 * DISP_E_OVERFLOW, if the value will not fit in the destination
793 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
795 return _VarUI1FromUI2(usIn, pbOut);
798 /************************************************************************
799 * VarUI1FromUI4 (OLEAUT32.239)
801 * Convert a VT_UI4 to a VT_UI1.
803 * PARAMS
804 * ulIn [I] Source
805 * pbOut [O] Destination
807 * RETURNS
808 * Success: S_OK.
809 * Failure: E_INVALIDARG, if the source value is invalid
810 * DISP_E_OVERFLOW, if the value will not fit in the destination
812 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
814 return _VarUI1FromUI4(ulIn, pbOut);
817 /************************************************************************
818 * VarUI1FromDec (OLEAUT32.240)
820 * Convert a VT_DECIMAL to a VT_UI1.
822 * PARAMS
823 * pDecIn [I] Source
824 * pbOut [O] Destination
826 * RETURNS
827 * Success: S_OK.
828 * Failure: E_INVALIDARG, if the source value is invalid
829 * DISP_E_OVERFLOW, if the value will not fit in the destination
831 HRESULT WINAPI VarUI1FromDec(const DECIMAL *pdecIn, BYTE* pbOut)
833 LONG64 i64;
834 HRESULT hRet;
836 hRet = VarI8FromDec(pdecIn, &i64);
838 if (SUCCEEDED(hRet))
839 hRet = _VarUI1FromI8(i64, pbOut);
840 return hRet;
843 /************************************************************************
844 * VarUI1FromI8 (OLEAUT32.372)
846 * Convert a VT_I8 to a VT_UI1.
848 * PARAMS
849 * llIn [I] Source
850 * pbOut [O] Destination
852 * RETURNS
853 * Success: S_OK.
854 * Failure: E_INVALIDARG, if the source value is invalid
855 * DISP_E_OVERFLOW, if the value will not fit in the destination
857 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
859 return _VarUI1FromI8(llIn, pbOut);
862 /************************************************************************
863 * VarUI1FromUI8 (OLEAUT32.373)
865 * Convert a VT_UI8 to a VT_UI1.
867 * PARAMS
868 * ullIn [I] Source
869 * pbOut [O] Destination
871 * RETURNS
872 * Success: S_OK.
873 * Failure: E_INVALIDARG, if the source value is invalid
874 * DISP_E_OVERFLOW, if the value will not fit in the destination
876 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
878 return _VarUI1FromUI8(ullIn, pbOut);
882 /* I2
885 /************************************************************************
886 * VarI2FromUI1 (OLEAUT32.48)
888 * Convert a VT_UI2 to a VT_I2.
890 * PARAMS
891 * bIn [I] Source
892 * psOut [O] Destination
894 * RETURNS
895 * S_OK.
897 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
899 return _VarI2FromUI1(bIn, psOut);
902 /************************************************************************
903 * VarI2FromI4 (OLEAUT32.49)
905 * Convert a VT_I4 to a VT_I2.
907 * PARAMS
908 * iIn [I] Source
909 * psOut [O] Destination
911 * RETURNS
912 * Success: S_OK.
913 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
915 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
917 return _VarI2FromI4(iIn, psOut);
920 /************************************************************************
921 * VarI2FromR4 (OLEAUT32.50)
923 * Convert a VT_R4 to a VT_I2.
925 * PARAMS
926 * fltIn [I] Source
927 * psOut [O] Destination
929 * RETURNS
930 * Success: S_OK.
931 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
933 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
935 return VarI2FromR8(fltIn, psOut);
938 /************************************************************************
939 * VarI2FromR8 (OLEAUT32.51)
941 * Convert a VT_R8 to a VT_I2.
943 * PARAMS
944 * dblIn [I] Source
945 * psOut [O] Destination
947 * RETURNS
948 * Success: S_OK.
949 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
951 * NOTES
952 * See VarI8FromR8() for details concerning rounding.
954 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
956 if (dblIn < I2_MIN - 0.5 || dblIn >= I2_MAX + 0.5)
957 return DISP_E_OVERFLOW;
958 VARIANT_DutchRound(SHORT, dblIn, *psOut);
959 return S_OK;
962 /************************************************************************
963 * VarI2FromCy (OLEAUT32.52)
965 * Convert a VT_CY to a VT_I2.
967 * PARAMS
968 * cyIn [I] Source
969 * psOut [O] Destination
971 * RETURNS
972 * Success: S_OK.
973 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
975 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
977 LONG i = I2_MAX + 1;
979 VarI4FromCy(cyIn, &i);
980 return _VarI2FromI4(i, psOut);
983 /************************************************************************
984 * VarI2FromDate (OLEAUT32.53)
986 * Convert a VT_DATE to a VT_I2.
988 * PARAMS
989 * dateIn [I] Source
990 * psOut [O] Destination
992 * RETURNS
993 * Success: S_OK.
994 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
996 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
998 return VarI2FromR8(dateIn, psOut);
1001 /************************************************************************
1002 * VarI2FromStr (OLEAUT32.54)
1004 * Convert a VT_BSTR to a VT_I2.
1006 * PARAMS
1007 * strIn [I] Source
1008 * lcid [I] LCID for the conversion
1009 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1010 * psOut [O] Destination
1012 * RETURNS
1013 * Success: S_OK.
1014 * Failure: E_INVALIDARG, if any parameter is invalid
1015 * DISP_E_OVERFLOW, if the value will not fit in the destination
1016 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1018 HRESULT WINAPI VarI2FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
1020 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
1023 /************************************************************************
1024 * VarI2FromDisp (OLEAUT32.55)
1026 * Convert a VT_DISPATCH to a VT_I2.
1028 * PARAMS
1029 * pdispIn [I] Source
1030 * lcid [I] LCID for conversion
1031 * psOut [O] Destination
1033 * RETURNS
1034 * Success: S_OK.
1035 * Failure: E_INVALIDARG, if pdispIn is invalid,
1036 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1037 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1039 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
1041 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0);
1044 /************************************************************************
1045 * VarI2FromBool (OLEAUT32.56)
1047 * Convert a VT_BOOL to a VT_I2.
1049 * PARAMS
1050 * boolIn [I] Source
1051 * psOut [O] Destination
1053 * RETURNS
1054 * S_OK.
1056 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
1058 return _VarI2FromBool(boolIn, psOut);
1061 /************************************************************************
1062 * VarI2FromI1 (OLEAUT32.205)
1064 * Convert a VT_I1 to a VT_I2.
1066 * PARAMS
1067 * cIn [I] Source
1068 * psOut [O] Destination
1070 * RETURNS
1071 * S_OK.
1073 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
1075 return _VarI2FromI1(cIn, psOut);
1078 /************************************************************************
1079 * VarI2FromUI2 (OLEAUT32.206)
1081 * Convert a VT_UI2 to a VT_I2.
1083 * PARAMS
1084 * usIn [I] Source
1085 * psOut [O] Destination
1087 * RETURNS
1088 * Success: S_OK.
1089 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1091 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
1093 return _VarI2FromUI2(usIn, psOut);
1096 /************************************************************************
1097 * VarI2FromUI4 (OLEAUT32.207)
1099 * Convert a VT_UI4 to a VT_I2.
1101 * PARAMS
1102 * ulIn [I] Source
1103 * psOut [O] Destination
1105 * RETURNS
1106 * Success: S_OK.
1107 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1109 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
1111 return _VarI2FromUI4(ulIn, psOut);
1114 /************************************************************************
1115 * VarI2FromDec (OLEAUT32.208)
1117 * Convert a VT_DECIMAL to a VT_I2.
1119 * PARAMS
1120 * pDecIn [I] Source
1121 * psOut [O] Destination
1123 * RETURNS
1124 * Success: S_OK.
1125 * Failure: E_INVALIDARG, if the source value is invalid
1126 * DISP_E_OVERFLOW, if the value will not fit in the destination
1128 HRESULT WINAPI VarI2FromDec(const DECIMAL *pdecIn, SHORT* psOut)
1130 LONG64 i64;
1131 HRESULT hRet;
1133 hRet = VarI8FromDec(pdecIn, &i64);
1135 if (SUCCEEDED(hRet))
1136 hRet = _VarI2FromI8(i64, psOut);
1137 return hRet;
1140 /************************************************************************
1141 * VarI2FromI8 (OLEAUT32.346)
1143 * Convert a VT_I8 to a VT_I2.
1145 * PARAMS
1146 * llIn [I] Source
1147 * psOut [O] Destination
1149 * RETURNS
1150 * Success: S_OK.
1151 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1153 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
1155 return _VarI2FromI8(llIn, psOut);
1158 /************************************************************************
1159 * VarI2FromUI8 (OLEAUT32.347)
1161 * Convert a VT_UI8 to a VT_I2.
1163 * PARAMS
1164 * ullIn [I] Source
1165 * psOut [O] Destination
1167 * RETURNS
1168 * Success: S_OK.
1169 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1171 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
1173 return _VarI2FromUI8(ullIn, psOut);
1176 /* UI2
1179 /************************************************************************
1180 * VarUI2FromUI1 (OLEAUT32.257)
1182 * Convert a VT_UI1 to a VT_UI2.
1184 * PARAMS
1185 * bIn [I] Source
1186 * pusOut [O] Destination
1188 * RETURNS
1189 * S_OK.
1191 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
1193 return _VarUI2FromUI1(bIn, pusOut);
1196 /************************************************************************
1197 * VarUI2FromI2 (OLEAUT32.258)
1199 * Convert a VT_I2 to a VT_UI2.
1201 * PARAMS
1202 * sIn [I] Source
1203 * pusOut [O] Destination
1205 * RETURNS
1206 * Success: S_OK.
1207 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1209 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
1211 return _VarUI2FromI2(sIn, pusOut);
1214 /************************************************************************
1215 * VarUI2FromI4 (OLEAUT32.259)
1217 * Convert a VT_I4 to a VT_UI2.
1219 * PARAMS
1220 * iIn [I] Source
1221 * pusOut [O] Destination
1223 * RETURNS
1224 * Success: S_OK.
1225 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1227 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
1229 return _VarUI2FromI4(iIn, pusOut);
1232 /************************************************************************
1233 * VarUI2FromR4 (OLEAUT32.260)
1235 * Convert a VT_R4 to a VT_UI2.
1237 * PARAMS
1238 * fltIn [I] Source
1239 * pusOut [O] Destination
1241 * RETURNS
1242 * Success: S_OK.
1243 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1245 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
1247 return VarUI2FromR8(fltIn, pusOut);
1250 /************************************************************************
1251 * VarUI2FromR8 (OLEAUT32.261)
1253 * Convert a VT_R8 to a VT_UI2.
1255 * PARAMS
1256 * dblIn [I] Source
1257 * pusOut [O] Destination
1259 * RETURNS
1260 * Success: S_OK.
1261 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1263 * NOTES
1264 * See VarI8FromR8() for details concerning rounding.
1266 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
1268 if (dblIn < -0.5 || dblIn >= UI2_MAX + 0.5)
1269 return DISP_E_OVERFLOW;
1270 VARIANT_DutchRound(USHORT, dblIn, *pusOut);
1271 return S_OK;
1274 /************************************************************************
1275 * VarUI2FromDate (OLEAUT32.262)
1277 * Convert a VT_DATE to a VT_UI2.
1279 * PARAMS
1280 * dateIn [I] Source
1281 * pusOut [O] Destination
1283 * RETURNS
1284 * Success: S_OK.
1285 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1287 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
1289 return VarUI2FromR8(dateIn, pusOut);
1292 /************************************************************************
1293 * VarUI2FromCy (OLEAUT32.263)
1295 * Convert a VT_CY to a VT_UI2.
1297 * PARAMS
1298 * cyIn [I] Source
1299 * pusOut [O] Destination
1301 * RETURNS
1302 * Success: S_OK.
1303 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1305 * NOTES
1306 * Negative values >= -5000 will be converted to 0.
1308 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
1310 ULONG i = UI2_MAX + 1;
1312 VarUI4FromCy(cyIn, &i);
1313 return _VarUI2FromUI4(i, pusOut);
1316 /************************************************************************
1317 * VarUI2FromStr (OLEAUT32.264)
1319 * Convert a VT_BSTR to a VT_UI2.
1321 * PARAMS
1322 * strIn [I] Source
1323 * lcid [I] LCID for the conversion
1324 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1325 * pusOut [O] Destination
1327 * RETURNS
1328 * Success: S_OK.
1329 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1330 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1332 HRESULT WINAPI VarUI2FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
1334 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
1337 /************************************************************************
1338 * VarUI2FromDisp (OLEAUT32.265)
1340 * Convert a VT_DISPATCH to a VT_UI2.
1342 * PARAMS
1343 * pdispIn [I] Source
1344 * lcid [I] LCID for conversion
1345 * pusOut [O] Destination
1347 * RETURNS
1348 * Success: S_OK.
1349 * Failure: E_INVALIDARG, if the source value is invalid
1350 * DISP_E_OVERFLOW, if the value will not fit in the destination
1351 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1353 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
1355 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0);
1358 /************************************************************************
1359 * VarUI2FromBool (OLEAUT32.266)
1361 * Convert a VT_BOOL to a VT_UI2.
1363 * PARAMS
1364 * boolIn [I] Source
1365 * pusOut [O] Destination
1367 * RETURNS
1368 * S_OK.
1370 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
1372 return _VarUI2FromBool(boolIn, pusOut);
1375 /************************************************************************
1376 * VarUI2FromI1 (OLEAUT32.267)
1378 * Convert a VT_I1 to a VT_UI2.
1380 * PARAMS
1381 * cIn [I] Source
1382 * pusOut [O] Destination
1384 * RETURNS
1385 * Success: S_OK.
1386 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1388 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
1390 return _VarUI2FromI1(cIn, pusOut);
1393 /************************************************************************
1394 * VarUI2FromUI4 (OLEAUT32.268)
1396 * Convert a VT_UI4 to a VT_UI2.
1398 * PARAMS
1399 * ulIn [I] Source
1400 * pusOut [O] Destination
1402 * RETURNS
1403 * Success: S_OK.
1404 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1406 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
1408 return _VarUI2FromUI4(ulIn, pusOut);
1411 /************************************************************************
1412 * VarUI2FromDec (OLEAUT32.269)
1414 * Convert a VT_DECIMAL to a VT_UI2.
1416 * PARAMS
1417 * pDecIn [I] Source
1418 * pusOut [O] Destination
1420 * RETURNS
1421 * Success: S_OK.
1422 * Failure: E_INVALIDARG, if the source value is invalid
1423 * DISP_E_OVERFLOW, if the value will not fit in the destination
1425 HRESULT WINAPI VarUI2FromDec(const DECIMAL *pdecIn, USHORT* pusOut)
1427 LONG64 i64;
1428 HRESULT hRet;
1430 hRet = VarI8FromDec(pdecIn, &i64);
1432 if (SUCCEEDED(hRet))
1433 hRet = _VarUI2FromI8(i64, pusOut);
1434 return hRet;
1437 /************************************************************************
1438 * VarUI2FromI8 (OLEAUT32.378)
1440 * Convert a VT_I8 to a VT_UI2.
1442 * PARAMS
1443 * llIn [I] Source
1444 * pusOut [O] Destination
1446 * RETURNS
1447 * Success: S_OK.
1448 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1450 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
1452 return _VarUI2FromI8(llIn, pusOut);
1455 /************************************************************************
1456 * VarUI2FromUI8 (OLEAUT32.379)
1458 * Convert a VT_UI8 to a VT_UI2.
1460 * PARAMS
1461 * ullIn [I] Source
1462 * pusOut [O] Destination
1464 * RETURNS
1465 * Success: S_OK.
1466 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1468 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
1470 return _VarUI2FromUI8(ullIn, pusOut);
1473 /* I4
1476 /************************************************************************
1477 * VarI4FromUI1 (OLEAUT32.58)
1479 * Convert a VT_UI1 to a VT_I4.
1481 * PARAMS
1482 * bIn [I] Source
1483 * piOut [O] Destination
1485 * RETURNS
1486 * S_OK.
1488 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
1490 return _VarI4FromUI1(bIn, piOut);
1493 /************************************************************************
1494 * VarI4FromI2 (OLEAUT32.59)
1496 * Convert a VT_I2 to a VT_I4.
1498 * PARAMS
1499 * sIn [I] Source
1500 * piOut [O] Destination
1502 * RETURNS
1503 * Success: S_OK.
1504 * Failure: E_INVALIDARG, if the source value is invalid
1505 * DISP_E_OVERFLOW, if the value will not fit in the destination
1507 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
1509 return _VarI4FromI2(sIn, piOut);
1512 /************************************************************************
1513 * VarI4FromR4 (OLEAUT32.60)
1515 * Convert a VT_R4 to a VT_I4.
1517 * PARAMS
1518 * fltIn [I] Source
1519 * piOut [O] Destination
1521 * RETURNS
1522 * Success: S_OK.
1523 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1525 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
1527 return VarI4FromR8(fltIn, piOut);
1530 /************************************************************************
1531 * VarI4FromR8 (OLEAUT32.61)
1533 * Convert a VT_R8 to a VT_I4.
1535 * PARAMS
1536 * dblIn [I] Source
1537 * piOut [O] Destination
1539 * RETURNS
1540 * Success: S_OK.
1541 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1543 * NOTES
1544 * See VarI8FromR8() for details concerning rounding.
1546 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
1548 if (dblIn < I4_MIN - 0.5 || dblIn >= I4_MAX + 0.5)
1549 return DISP_E_OVERFLOW;
1550 VARIANT_DutchRound(LONG, dblIn, *piOut);
1551 return S_OK;
1554 /************************************************************************
1555 * VarI4FromCy (OLEAUT32.62)
1557 * Convert a VT_CY to a VT_I4.
1559 * PARAMS
1560 * cyIn [I] Source
1561 * piOut [O] Destination
1563 * RETURNS
1564 * Success: S_OK.
1565 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1567 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
1569 double d = cyIn.int64 / CY_MULTIPLIER_F;
1570 return VarI4FromR8(d, piOut);
1573 /************************************************************************
1574 * VarI4FromDate (OLEAUT32.63)
1576 * Convert a VT_DATE to a VT_I4.
1578 * PARAMS
1579 * dateIn [I] Source
1580 * piOut [O] Destination
1582 * RETURNS
1583 * Success: S_OK.
1584 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1586 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
1588 return VarI4FromR8(dateIn, piOut);
1591 /************************************************************************
1592 * VarI4FromStr (OLEAUT32.64)
1594 * Convert a VT_BSTR to a VT_I4.
1596 * PARAMS
1597 * strIn [I] Source
1598 * lcid [I] LCID for the conversion
1599 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1600 * piOut [O] Destination
1602 * RETURNS
1603 * Success: S_OK.
1604 * Failure: E_INVALIDARG, if any parameter is invalid
1605 * DISP_E_OVERFLOW, if the value will not fit in the destination
1606 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1608 HRESULT WINAPI VarI4FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
1610 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
1613 /************************************************************************
1614 * VarI4FromDisp (OLEAUT32.65)
1616 * Convert a VT_DISPATCH to a VT_I4.
1618 * PARAMS
1619 * pdispIn [I] Source
1620 * lcid [I] LCID for conversion
1621 * piOut [O] Destination
1623 * RETURNS
1624 * Success: S_OK.
1625 * Failure: E_INVALIDARG, if the source value is invalid
1626 * DISP_E_OVERFLOW, if the value will not fit in the destination
1627 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1629 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
1631 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0);
1634 /************************************************************************
1635 * VarI4FromBool (OLEAUT32.66)
1637 * Convert a VT_BOOL to a VT_I4.
1639 * PARAMS
1640 * boolIn [I] Source
1641 * piOut [O] Destination
1643 * RETURNS
1644 * S_OK.
1646 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
1648 return _VarI4FromBool(boolIn, piOut);
1651 /************************************************************************
1652 * VarI4FromI1 (OLEAUT32.209)
1654 * Convert a VT_I1 to a VT_I4.
1656 * PARAMS
1657 * cIn [I] Source
1658 * piOut [O] Destination
1660 * RETURNS
1661 * S_OK.
1663 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
1665 return _VarI4FromI1(cIn, piOut);
1668 /************************************************************************
1669 * VarI4FromUI2 (OLEAUT32.210)
1671 * Convert a VT_UI2 to a VT_I4.
1673 * PARAMS
1674 * usIn [I] Source
1675 * piOut [O] Destination
1677 * RETURNS
1678 * S_OK.
1680 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
1682 return _VarI4FromUI2(usIn, piOut);
1685 /************************************************************************
1686 * VarI4FromUI4 (OLEAUT32.211)
1688 * Convert a VT_UI4 to a VT_I4.
1690 * PARAMS
1691 * ulIn [I] Source
1692 * piOut [O] Destination
1694 * RETURNS
1695 * Success: S_OK.
1696 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1698 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
1700 return _VarI4FromUI4(ulIn, piOut);
1703 /************************************************************************
1704 * VarI4FromDec (OLEAUT32.212)
1706 * Convert a VT_DECIMAL to a VT_I4.
1708 * PARAMS
1709 * pDecIn [I] Source
1710 * piOut [O] Destination
1712 * RETURNS
1713 * Success: S_OK.
1714 * Failure: E_INVALIDARG, if pdecIn is invalid
1715 * DISP_E_OVERFLOW, if the value will not fit in the destination
1717 HRESULT WINAPI VarI4FromDec(const DECIMAL *pdecIn, LONG *piOut)
1719 LONG64 i64;
1720 HRESULT hRet;
1722 hRet = VarI8FromDec(pdecIn, &i64);
1724 if (SUCCEEDED(hRet))
1725 hRet = _VarI4FromI8(i64, piOut);
1726 return hRet;
1729 /************************************************************************
1730 * VarI4FromI8 (OLEAUT32.348)
1732 * Convert a VT_I8 to a VT_I4.
1734 * PARAMS
1735 * llIn [I] Source
1736 * piOut [O] Destination
1738 * RETURNS
1739 * Success: S_OK.
1740 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1742 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
1744 return _VarI4FromI8(llIn, piOut);
1747 /************************************************************************
1748 * VarI4FromUI8 (OLEAUT32.349)
1750 * Convert a VT_UI8 to a VT_I4.
1752 * PARAMS
1753 * ullIn [I] Source
1754 * piOut [O] Destination
1756 * RETURNS
1757 * Success: S_OK.
1758 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1760 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
1762 return _VarI4FromUI8(ullIn, piOut);
1765 /* UI4
1768 /************************************************************************
1769 * VarUI4FromUI1 (OLEAUT32.270)
1771 * Convert a VT_UI1 to a VT_UI4.
1773 * PARAMS
1774 * bIn [I] Source
1775 * pulOut [O] Destination
1777 * RETURNS
1778 * S_OK.
1780 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
1782 return _VarUI4FromUI1(bIn, pulOut);
1785 /************************************************************************
1786 * VarUI4FromI2 (OLEAUT32.271)
1788 * Convert a VT_I2 to a VT_UI4.
1790 * PARAMS
1791 * sIn [I] Source
1792 * pulOut [O] Destination
1794 * RETURNS
1795 * Success: S_OK.
1796 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1798 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
1800 return _VarUI4FromI2(sIn, pulOut);
1803 /************************************************************************
1804 * VarUI4FromI4 (OLEAUT32.272)
1806 * Convert a VT_I4 to a VT_UI4.
1808 * PARAMS
1809 * iIn [I] Source
1810 * pulOut [O] Destination
1812 * RETURNS
1813 * Success: S_OK.
1814 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1816 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
1818 return _VarUI4FromI4(iIn, pulOut);
1821 /************************************************************************
1822 * VarUI4FromR4 (OLEAUT32.273)
1824 * Convert a VT_R4 to a VT_UI4.
1826 * PARAMS
1827 * fltIn [I] Source
1828 * pulOut [O] Destination
1830 * RETURNS
1831 * Success: S_OK.
1832 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1834 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
1836 return VarUI4FromR8(fltIn, pulOut);
1839 /************************************************************************
1840 * VarUI4FromR8 (OLEAUT32.274)
1842 * Convert a VT_R8 to a VT_UI4.
1844 * PARAMS
1845 * dblIn [I] Source
1846 * pulOut [O] Destination
1848 * RETURNS
1849 * Success: S_OK.
1850 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1852 * NOTES
1853 * See VarI8FromR8() for details concerning rounding.
1855 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
1857 if (dblIn < -0.5 || dblIn >= UI4_MAX + 0.5)
1858 return DISP_E_OVERFLOW;
1859 VARIANT_DutchRound(ULONG, dblIn, *pulOut);
1860 return S_OK;
1863 /************************************************************************
1864 * VarUI4FromDate (OLEAUT32.275)
1866 * Convert a VT_DATE to a VT_UI4.
1868 * PARAMS
1869 * dateIn [I] Source
1870 * pulOut [O] Destination
1872 * RETURNS
1873 * Success: S_OK.
1874 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1876 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
1878 return VarUI4FromR8(dateIn, pulOut);
1881 /************************************************************************
1882 * VarUI4FromCy (OLEAUT32.276)
1884 * Convert a VT_CY to a VT_UI4.
1886 * PARAMS
1887 * cyIn [I] Source
1888 * pulOut [O] Destination
1890 * RETURNS
1891 * Success: S_OK.
1892 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1894 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
1896 double d = cyIn.int64 / CY_MULTIPLIER_F;
1897 return VarUI4FromR8(d, pulOut);
1900 /************************************************************************
1901 * VarUI4FromStr (OLEAUT32.277)
1903 * Convert a VT_BSTR to a VT_UI4.
1905 * PARAMS
1906 * strIn [I] Source
1907 * lcid [I] LCID for the conversion
1908 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1909 * pulOut [O] Destination
1911 * RETURNS
1912 * Success: S_OK.
1913 * Failure: E_INVALIDARG, if any parameter is invalid
1914 * DISP_E_OVERFLOW, if the value will not fit in the destination
1915 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1917 HRESULT WINAPI VarUI4FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
1919 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
1922 /************************************************************************
1923 * VarUI4FromDisp (OLEAUT32.278)
1925 * Convert a VT_DISPATCH to a VT_UI4.
1927 * PARAMS
1928 * pdispIn [I] Source
1929 * lcid [I] LCID for conversion
1930 * pulOut [O] Destination
1932 * RETURNS
1933 * Success: S_OK.
1934 * Failure: E_INVALIDARG, if the source value is invalid
1935 * DISP_E_OVERFLOW, if the value will not fit in the destination
1936 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1938 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
1940 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0);
1943 /************************************************************************
1944 * VarUI4FromBool (OLEAUT32.279)
1946 * Convert a VT_BOOL to a VT_UI4.
1948 * PARAMS
1949 * boolIn [I] Source
1950 * pulOut [O] Destination
1952 * RETURNS
1953 * S_OK.
1955 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
1957 return _VarUI4FromBool(boolIn, pulOut);
1960 /************************************************************************
1961 * VarUI4FromI1 (OLEAUT32.280)
1963 * Convert a VT_I1 to a VT_UI4.
1965 * PARAMS
1966 * cIn [I] Source
1967 * pulOut [O] Destination
1969 * RETURNS
1970 * Success: S_OK.
1971 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1973 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
1975 return _VarUI4FromI1(cIn, pulOut);
1978 /************************************************************************
1979 * VarUI4FromUI2 (OLEAUT32.281)
1981 * Convert a VT_UI2 to a VT_UI4.
1983 * PARAMS
1984 * usIn [I] Source
1985 * pulOut [O] Destination
1987 * RETURNS
1988 * S_OK.
1990 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
1992 return _VarUI4FromUI2(usIn, pulOut);
1995 /************************************************************************
1996 * VarUI4FromDec (OLEAUT32.282)
1998 * Convert a VT_DECIMAL to a VT_UI4.
2000 * PARAMS
2001 * pDecIn [I] Source
2002 * pulOut [O] Destination
2004 * RETURNS
2005 * Success: S_OK.
2006 * Failure: E_INVALIDARG, if pdecIn is invalid
2007 * DISP_E_OVERFLOW, if the value will not fit in the destination
2009 HRESULT WINAPI VarUI4FromDec(const DECIMAL *pdecIn, ULONG *pulOut)
2011 LONG64 i64;
2012 HRESULT hRet;
2014 hRet = VarI8FromDec(pdecIn, &i64);
2016 if (SUCCEEDED(hRet))
2017 hRet = _VarUI4FromI8(i64, pulOut);
2018 return hRet;
2021 /************************************************************************
2022 * VarUI4FromI8 (OLEAUT32.425)
2024 * Convert a VT_I8 to a VT_UI4.
2026 * PARAMS
2027 * llIn [I] Source
2028 * pulOut [O] Destination
2030 * RETURNS
2031 * Success: S_OK.
2032 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2034 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
2036 return _VarUI4FromI8(llIn, pulOut);
2039 /************************************************************************
2040 * VarUI4FromUI8 (OLEAUT32.426)
2042 * Convert a VT_UI8 to a VT_UI4.
2044 * PARAMS
2045 * ullIn [I] Source
2046 * pulOut [O] Destination
2048 * RETURNS
2049 * Success: S_OK.
2050 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2052 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
2054 return _VarUI4FromUI8(ullIn, pulOut);
2057 /* I8
2060 /************************************************************************
2061 * VarI8FromUI1 (OLEAUT32.333)
2063 * Convert a VT_UI1 to a VT_I8.
2065 * PARAMS
2066 * bIn [I] Source
2067 * pi64Out [O] Destination
2069 * RETURNS
2070 * S_OK.
2072 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
2074 return _VarI8FromUI1(bIn, pi64Out);
2078 /************************************************************************
2079 * VarI8FromI2 (OLEAUT32.334)
2081 * Convert a VT_I2 to a VT_I8.
2083 * PARAMS
2084 * sIn [I] Source
2085 * pi64Out [O] Destination
2087 * RETURNS
2088 * S_OK.
2090 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
2092 return _VarI8FromI2(sIn, pi64Out);
2095 /************************************************************************
2096 * VarI8FromR4 (OLEAUT32.335)
2098 * Convert a VT_R4 to a VT_I8.
2100 * PARAMS
2101 * fltIn [I] Source
2102 * pi64Out [O] Destination
2104 * RETURNS
2105 * Success: S_OK.
2106 * Failure: E_INVALIDARG, if the source value is invalid
2107 * DISP_E_OVERFLOW, if the value will not fit in the destination
2109 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
2111 return VarI8FromR8(fltIn, pi64Out);
2114 /************************************************************************
2115 * VarI8FromR8 (OLEAUT32.336)
2117 * Convert a VT_R8 to a VT_I8.
2119 * PARAMS
2120 * dblIn [I] Source
2121 * pi64Out [O] Destination
2123 * RETURNS
2124 * Success: S_OK.
2125 * Failure: E_INVALIDARG, if the source value is invalid
2126 * DISP_E_OVERFLOW, if the value will not fit in the destination
2128 * NOTES
2129 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2130 * very high or low values will not be accurately converted.
2132 * Numbers are rounded using Dutch rounding, as follows:
2134 *| Fractional Part Sign Direction Example
2135 *| --------------- ---- --------- -------
2136 *| < 0.5 + Down 0.4 -> 0.0
2137 *| < 0.5 - Up -0.4 -> 0.0
2138 *| > 0.5 + Up 0.6 -> 1.0
2139 *| < 0.5 - Up -0.6 -> -1.0
2140 *| = 0.5 + Up/Down Down if even, Up if odd
2141 *| = 0.5 - Up/Down Up if even, Down if odd
2143 * This system is often used in supermarkets.
2145 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
2147 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
2148 return DISP_E_OVERFLOW;
2149 VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
2150 return S_OK;
2153 /************************************************************************
2154 * VarI8FromCy (OLEAUT32.337)
2156 * Convert a VT_CY to a VT_I8.
2158 * PARAMS
2159 * cyIn [I] Source
2160 * pi64Out [O] Destination
2162 * RETURNS
2163 * S_OK.
2165 * NOTES
2166 * All negative numbers are rounded down by 1, including those that are
2167 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2168 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2169 * for details.
2171 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
2173 *pi64Out = cyIn.int64 / CY_MULTIPLIER;
2175 if (cyIn.int64 < 0)
2176 (*pi64Out)--; /* Mimic Win32 bug */
2177 else
2179 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2181 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1)))
2182 (*pi64Out)++;
2184 return S_OK;
2187 /************************************************************************
2188 * VarI8FromDate (OLEAUT32.338)
2190 * Convert a VT_DATE to a VT_I8.
2192 * PARAMS
2193 * dateIn [I] Source
2194 * pi64Out [O] Destination
2196 * RETURNS
2197 * Success: S_OK.
2198 * Failure: E_INVALIDARG, if the source value is invalid
2199 * DISP_E_OVERFLOW, if the value will not fit in the destination
2200 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2202 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
2204 return VarI8FromR8(dateIn, pi64Out);
2207 /************************************************************************
2208 * VarI8FromStr (OLEAUT32.339)
2210 * Convert a VT_BSTR to a VT_I8.
2212 * PARAMS
2213 * strIn [I] Source
2214 * lcid [I] LCID for the conversion
2215 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2216 * pi64Out [O] Destination
2218 * RETURNS
2219 * Success: S_OK.
2220 * Failure: E_INVALIDARG, if the source value is invalid
2221 * DISP_E_OVERFLOW, if the value will not fit in the destination
2222 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2224 HRESULT WINAPI VarI8FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
2226 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
2229 /************************************************************************
2230 * VarI8FromDisp (OLEAUT32.340)
2232 * Convert a VT_DISPATCH to a VT_I8.
2234 * PARAMS
2235 * pdispIn [I] Source
2236 * lcid [I] LCID for conversion
2237 * pi64Out [O] Destination
2239 * RETURNS
2240 * Success: S_OK.
2241 * Failure: E_INVALIDARG, if the source value is invalid
2242 * DISP_E_OVERFLOW, if the value will not fit in the destination
2243 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2245 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
2247 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0);
2250 /************************************************************************
2251 * VarI8FromBool (OLEAUT32.341)
2253 * Convert a VT_BOOL to a VT_I8.
2255 * PARAMS
2256 * boolIn [I] Source
2257 * pi64Out [O] Destination
2259 * RETURNS
2260 * S_OK.
2262 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
2264 return VarI8FromI2(boolIn, pi64Out);
2267 /************************************************************************
2268 * VarI8FromI1 (OLEAUT32.342)
2270 * Convert a VT_I1 to a VT_I8.
2272 * PARAMS
2273 * cIn [I] Source
2274 * pi64Out [O] Destination
2276 * RETURNS
2277 * S_OK.
2279 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
2281 return _VarI8FromI1(cIn, pi64Out);
2284 /************************************************************************
2285 * VarI8FromUI2 (OLEAUT32.343)
2287 * Convert a VT_UI2 to a VT_I8.
2289 * PARAMS
2290 * usIn [I] Source
2291 * pi64Out [O] Destination
2293 * RETURNS
2294 * S_OK.
2296 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
2298 return _VarI8FromUI2(usIn, pi64Out);
2301 /************************************************************************
2302 * VarI8FromUI4 (OLEAUT32.344)
2304 * Convert a VT_UI4 to a VT_I8.
2306 * PARAMS
2307 * ulIn [I] Source
2308 * pi64Out [O] Destination
2310 * RETURNS
2311 * S_OK.
2313 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
2315 return _VarI8FromUI4(ulIn, pi64Out);
2318 /************************************************************************
2319 * VarI8FromDec (OLEAUT32.345)
2321 * Convert a VT_DECIMAL to a VT_I8.
2323 * PARAMS
2324 * pDecIn [I] Source
2325 * pi64Out [O] Destination
2327 * RETURNS
2328 * Success: S_OK.
2329 * Failure: E_INVALIDARG, if the source value is invalid
2330 * DISP_E_OVERFLOW, if the value will not fit in the destination
2332 HRESULT WINAPI VarI8FromDec(const DECIMAL *pdecIn, LONG64* pi64Out)
2334 if (!DEC_SCALE(pdecIn))
2336 /* This decimal is just a 96 bit integer */
2337 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2338 return E_INVALIDARG;
2340 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000)
2341 return DISP_E_OVERFLOW;
2343 if (DEC_SIGN(pdecIn))
2344 *pi64Out = -DEC_LO64(pdecIn);
2345 else
2346 *pi64Out = DEC_LO64(pdecIn);
2347 return S_OK;
2349 else
2351 /* Decimal contains a floating point number */
2352 HRESULT hRet;
2353 double dbl;
2355 hRet = VarR8FromDec(pdecIn, &dbl);
2356 if (SUCCEEDED(hRet))
2357 hRet = VarI8FromR8(dbl, pi64Out);
2358 return hRet;
2362 /************************************************************************
2363 * VarI8FromUI8 (OLEAUT32.427)
2365 * Convert a VT_UI8 to a VT_I8.
2367 * PARAMS
2368 * ullIn [I] Source
2369 * pi64Out [O] Destination
2371 * RETURNS
2372 * Success: S_OK.
2373 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2375 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
2377 return _VarI8FromUI8(ullIn, pi64Out);
2380 /* UI8
2383 /************************************************************************
2384 * VarUI8FromI8 (OLEAUT32.428)
2386 * Convert a VT_I8 to a VT_UI8.
2388 * PARAMS
2389 * ulIn [I] Source
2390 * pui64Out [O] Destination
2392 * RETURNS
2393 * Success: S_OK.
2394 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2396 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
2398 return _VarUI8FromI8(llIn, pui64Out);
2401 /************************************************************************
2402 * VarUI8FromUI1 (OLEAUT32.429)
2404 * Convert a VT_UI1 to a VT_UI8.
2406 * PARAMS
2407 * bIn [I] Source
2408 * pui64Out [O] Destination
2410 * RETURNS
2411 * S_OK.
2413 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
2415 return _VarUI8FromUI1(bIn, pui64Out);
2418 /************************************************************************
2419 * VarUI8FromI2 (OLEAUT32.430)
2421 * Convert a VT_I2 to a VT_UI8.
2423 * PARAMS
2424 * sIn [I] Source
2425 * pui64Out [O] Destination
2427 * RETURNS
2428 * S_OK.
2430 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
2432 return _VarUI8FromI2(sIn, pui64Out);
2435 /************************************************************************
2436 * VarUI8FromR4 (OLEAUT32.431)
2438 * Convert a VT_R4 to a VT_UI8.
2440 * PARAMS
2441 * fltIn [I] Source
2442 * pui64Out [O] Destination
2444 * RETURNS
2445 * Success: S_OK.
2446 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2448 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
2450 return VarUI8FromR8(fltIn, pui64Out);
2453 /************************************************************************
2454 * VarUI8FromR8 (OLEAUT32.432)
2456 * Convert a VT_R8 to a VT_UI8.
2458 * PARAMS
2459 * dblIn [I] Source
2460 * pui64Out [O] Destination
2462 * RETURNS
2463 * Success: S_OK.
2464 * Failure: E_INVALIDARG, if the source value is invalid
2465 * DISP_E_OVERFLOW, if the value will not fit in the destination
2467 * NOTES
2468 * See VarI8FromR8() for details concerning rounding.
2470 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
2472 if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
2473 return DISP_E_OVERFLOW;
2474 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
2475 return S_OK;
2478 /************************************************************************
2479 * VarUI8FromCy (OLEAUT32.433)
2481 * Convert a VT_CY to a VT_UI8.
2483 * PARAMS
2484 * cyIn [I] Source
2485 * pui64Out [O] Destination
2487 * RETURNS
2488 * Success: S_OK.
2489 * Failure: E_INVALIDARG, if the source value is invalid
2490 * DISP_E_OVERFLOW, if the value will not fit in the destination
2492 * NOTES
2493 * Negative values >= -5000 will be converted to 0.
2495 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
2497 if (cyIn.int64 < 0)
2499 if (cyIn.int64 < -CY_HALF)
2500 return DISP_E_OVERFLOW;
2501 *pui64Out = 0;
2503 else
2505 *pui64Out = cyIn.int64 / CY_MULTIPLIER;
2507 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2509 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1)))
2510 (*pui64Out)++;
2512 return S_OK;
2515 /************************************************************************
2516 * VarUI8FromDate (OLEAUT32.434)
2518 * Convert a VT_DATE to a VT_UI8.
2520 * PARAMS
2521 * dateIn [I] Source
2522 * pui64Out [O] Destination
2524 * RETURNS
2525 * Success: S_OK.
2526 * Failure: E_INVALIDARG, if the source value is invalid
2527 * DISP_E_OVERFLOW, if the value will not fit in the destination
2528 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2530 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
2532 return VarUI8FromR8(dateIn, pui64Out);
2535 /************************************************************************
2536 * VarUI8FromStr (OLEAUT32.435)
2538 * Convert a VT_BSTR to a VT_UI8.
2540 * PARAMS
2541 * strIn [I] Source
2542 * lcid [I] LCID for the conversion
2543 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2544 * pui64Out [O] Destination
2546 * RETURNS
2547 * Success: S_OK.
2548 * Failure: E_INVALIDARG, if the source value is invalid
2549 * DISP_E_OVERFLOW, if the value will not fit in the destination
2550 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2552 HRESULT WINAPI VarUI8FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
2554 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
2557 /************************************************************************
2558 * VarUI8FromDisp (OLEAUT32.436)
2560 * Convert a VT_DISPATCH to a VT_UI8.
2562 * PARAMS
2563 * pdispIn [I] Source
2564 * lcid [I] LCID for conversion
2565 * pui64Out [O] Destination
2567 * RETURNS
2568 * Success: S_OK.
2569 * Failure: E_INVALIDARG, if the source value is invalid
2570 * DISP_E_OVERFLOW, if the value will not fit in the destination
2571 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2573 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
2575 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0);
2578 /************************************************************************
2579 * VarUI8FromBool (OLEAUT32.437)
2581 * Convert a VT_BOOL to a VT_UI8.
2583 * PARAMS
2584 * boolIn [I] Source
2585 * pui64Out [O] Destination
2587 * RETURNS
2588 * Success: S_OK.
2589 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2591 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
2593 return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
2595 /************************************************************************
2596 * VarUI8FromI1 (OLEAUT32.438)
2598 * Convert a VT_I1 to a VT_UI8.
2600 * PARAMS
2601 * cIn [I] Source
2602 * pui64Out [O] Destination
2604 * RETURNS
2605 * Success: S_OK.
2606 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2608 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
2610 return _VarUI8FromI1(cIn, pui64Out);
2613 /************************************************************************
2614 * VarUI8FromUI2 (OLEAUT32.439)
2616 * Convert a VT_UI2 to a VT_UI8.
2618 * PARAMS
2619 * usIn [I] Source
2620 * pui64Out [O] Destination
2622 * RETURNS
2623 * S_OK.
2625 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
2627 return _VarUI8FromUI2(usIn, pui64Out);
2630 /************************************************************************
2631 * VarUI8FromUI4 (OLEAUT32.440)
2633 * Convert a VT_UI4 to a VT_UI8.
2635 * PARAMS
2636 * ulIn [I] Source
2637 * pui64Out [O] Destination
2639 * RETURNS
2640 * S_OK.
2642 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
2644 return _VarUI8FromUI4(ulIn, pui64Out);
2647 /************************************************************************
2648 * VarUI8FromDec (OLEAUT32.441)
2650 * Convert a VT_DECIMAL to a VT_UI8.
2652 * PARAMS
2653 * pDecIn [I] Source
2654 * pui64Out [O] Destination
2656 * RETURNS
2657 * Success: S_OK.
2658 * Failure: E_INVALIDARG, if the source value is invalid
2659 * DISP_E_OVERFLOW, if the value will not fit in the destination
2661 * NOTES
2662 * Under native Win32, if the source value has a scale of 0, its sign is
2663 * ignored, i.e. this function takes the absolute value rather than fail
2664 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2665 * (use VarAbs() on pDecIn first if you really want this behaviour).
2667 HRESULT WINAPI VarUI8FromDec(const DECIMAL *pdecIn, ULONG64* pui64Out)
2669 if (!DEC_SCALE(pdecIn))
2671 /* This decimal is just a 96 bit integer */
2672 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2673 return E_INVALIDARG;
2675 if (DEC_HI32(pdecIn))
2676 return DISP_E_OVERFLOW;
2678 if (DEC_SIGN(pdecIn))
2680 WARN("Sign would be ignored under Win32!\n");
2681 return DISP_E_OVERFLOW;
2684 *pui64Out = DEC_LO64(pdecIn);
2685 return S_OK;
2687 else
2689 /* Decimal contains a floating point number */
2690 HRESULT hRet;
2691 double dbl;
2693 hRet = VarR8FromDec(pdecIn, &dbl);
2694 if (SUCCEEDED(hRet))
2695 hRet = VarUI8FromR8(dbl, pui64Out);
2696 return hRet;
2700 /* R4
2703 /************************************************************************
2704 * VarR4FromUI1 (OLEAUT32.68)
2706 * Convert a VT_UI1 to a VT_R4.
2708 * PARAMS
2709 * bIn [I] Source
2710 * pFltOut [O] Destination
2712 * RETURNS
2713 * S_OK.
2715 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
2717 return _VarR4FromUI1(bIn, pFltOut);
2720 /************************************************************************
2721 * VarR4FromI2 (OLEAUT32.69)
2723 * Convert a VT_I2 to a VT_R4.
2725 * PARAMS
2726 * sIn [I] Source
2727 * pFltOut [O] Destination
2729 * RETURNS
2730 * S_OK.
2732 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
2734 return _VarR4FromI2(sIn, pFltOut);
2737 /************************************************************************
2738 * VarR4FromI4 (OLEAUT32.70)
2740 * Convert a VT_I4 to a VT_R4.
2742 * PARAMS
2743 * sIn [I] Source
2744 * pFltOut [O] Destination
2746 * RETURNS
2747 * S_OK.
2749 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
2751 return _VarR4FromI4(lIn, pFltOut);
2754 /************************************************************************
2755 * VarR4FromR8 (OLEAUT32.71)
2757 * Convert a VT_R8 to a VT_R4.
2759 * PARAMS
2760 * dblIn [I] Source
2761 * pFltOut [O] Destination
2763 * RETURNS
2764 * Success: S_OK.
2765 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2767 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
2769 double d = dblIn < 0.0 ? -dblIn : dblIn;
2770 if (d > R4_MAX) return DISP_E_OVERFLOW;
2771 *pFltOut = dblIn;
2772 return S_OK;
2775 /************************************************************************
2776 * VarR4FromCy (OLEAUT32.72)
2778 * Convert a VT_CY to a VT_R4.
2780 * PARAMS
2781 * cyIn [I] Source
2782 * pFltOut [O] Destination
2784 * RETURNS
2785 * S_OK.
2787 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
2789 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
2790 return S_OK;
2793 /************************************************************************
2794 * VarR4FromDate (OLEAUT32.73)
2796 * Convert a VT_DATE to a VT_R4.
2798 * PARAMS
2799 * dateIn [I] Source
2800 * pFltOut [O] Destination
2802 * RETURNS
2803 * Success: S_OK.
2804 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2806 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
2808 return VarR4FromR8(dateIn, pFltOut);
2811 /************************************************************************
2812 * VarR4FromStr (OLEAUT32.74)
2814 * Convert a VT_BSTR to a VT_R4.
2816 * PARAMS
2817 * strIn [I] Source
2818 * lcid [I] LCID for the conversion
2819 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2820 * pFltOut [O] Destination
2822 * RETURNS
2823 * Success: S_OK.
2824 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2825 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2827 HRESULT WINAPI VarR4FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
2829 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
2832 /************************************************************************
2833 * VarR4FromDisp (OLEAUT32.75)
2835 * Convert a VT_DISPATCH to a VT_R4.
2837 * PARAMS
2838 * pdispIn [I] Source
2839 * lcid [I] LCID for conversion
2840 * pFltOut [O] Destination
2842 * RETURNS
2843 * Success: S_OK.
2844 * Failure: E_INVALIDARG, if the source value is invalid
2845 * DISP_E_OVERFLOW, if the value will not fit in the destination
2846 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2848 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
2850 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0);
2853 /************************************************************************
2854 * VarR4FromBool (OLEAUT32.76)
2856 * Convert a VT_BOOL to a VT_R4.
2858 * PARAMS
2859 * boolIn [I] Source
2860 * pFltOut [O] Destination
2862 * RETURNS
2863 * S_OK.
2865 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2867 return VarR4FromI2(boolIn, pFltOut);
2870 /************************************************************************
2871 * VarR4FromI1 (OLEAUT32.213)
2873 * Convert a VT_I1 to a VT_R4.
2875 * PARAMS
2876 * cIn [I] Source
2877 * pFltOut [O] Destination
2879 * RETURNS
2880 * Success: S_OK.
2881 * Failure: E_INVALIDARG, if the source value is invalid
2882 * DISP_E_OVERFLOW, if the value will not fit in the destination
2883 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2885 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2887 return _VarR4FromI1(cIn, pFltOut);
2890 /************************************************************************
2891 * VarR4FromUI2 (OLEAUT32.214)
2893 * Convert a VT_UI2 to a VT_R4.
2895 * PARAMS
2896 * usIn [I] Source
2897 * pFltOut [O] Destination
2899 * RETURNS
2900 * Success: S_OK.
2901 * Failure: E_INVALIDARG, if the source value is invalid
2902 * DISP_E_OVERFLOW, if the value will not fit in the destination
2903 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2905 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2907 return _VarR4FromUI2(usIn, pFltOut);
2910 /************************************************************************
2911 * VarR4FromUI4 (OLEAUT32.215)
2913 * Convert a VT_UI4 to a VT_R4.
2915 * PARAMS
2916 * ulIn [I] Source
2917 * pFltOut [O] Destination
2919 * RETURNS
2920 * Success: S_OK.
2921 * Failure: E_INVALIDARG, if the source value is invalid
2922 * DISP_E_OVERFLOW, if the value will not fit in the destination
2923 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2925 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2927 return _VarR4FromUI4(ulIn, pFltOut);
2930 /************************************************************************
2931 * VarR4FromDec (OLEAUT32.216)
2933 * Convert a VT_DECIMAL to a VT_R4.
2935 * PARAMS
2936 * pDecIn [I] Source
2937 * pFltOut [O] Destination
2939 * RETURNS
2940 * Success: S_OK.
2941 * Failure: E_INVALIDARG, if the source value is invalid.
2943 HRESULT WINAPI VarR4FromDec(const DECIMAL* pDecIn, float *pFltOut)
2945 BYTE scale = DEC_SCALE(pDecIn);
2946 double divisor = 1.0;
2947 double highPart;
2949 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2950 return E_INVALIDARG;
2952 while (scale--)
2953 divisor *= 10.0;
2955 if (DEC_SIGN(pDecIn))
2956 divisor = -divisor;
2958 if (DEC_HI32(pDecIn))
2960 highPart = (double)DEC_HI32(pDecIn) / divisor;
2961 highPart *= 4294967296.0F;
2962 highPart *= 4294967296.0F;
2964 else
2965 highPart = 0.0;
2967 *pFltOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
2968 return S_OK;
2971 /************************************************************************
2972 * VarR4FromI8 (OLEAUT32.360)
2974 * Convert a VT_I8 to a VT_R4.
2976 * PARAMS
2977 * ullIn [I] Source
2978 * pFltOut [O] Destination
2980 * RETURNS
2981 * S_OK.
2983 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2985 return _VarR4FromI8(llIn, pFltOut);
2988 /************************************************************************
2989 * VarR4FromUI8 (OLEAUT32.361)
2991 * Convert a VT_UI8 to a VT_R4.
2993 * PARAMS
2994 * ullIn [I] Source
2995 * pFltOut [O] Destination
2997 * RETURNS
2998 * S_OK.
3000 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
3002 return _VarR4FromUI8(ullIn, pFltOut);
3005 /************************************************************************
3006 * VarR4CmpR8 (OLEAUT32.316)
3008 * Compare a VT_R4 to a VT_R8.
3010 * PARAMS
3011 * fltLeft [I] Source
3012 * dblRight [I] Value to compare
3014 * RETURNS
3015 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3016 * equal to or greater than dblRight respectively.
3018 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3020 if (fltLeft < dblRight)
3021 return VARCMP_LT;
3022 else if (fltLeft > dblRight)
3023 return VARCMP_GT;
3024 return VARCMP_EQ;
3027 /* R8
3030 /************************************************************************
3031 * VarR8FromUI1 (OLEAUT32.78)
3033 * Convert a VT_UI1 to a VT_R8.
3035 * PARAMS
3036 * bIn [I] Source
3037 * pDblOut [O] Destination
3039 * RETURNS
3040 * S_OK.
3042 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3044 return _VarR8FromUI1(bIn, pDblOut);
3047 /************************************************************************
3048 * VarR8FromI2 (OLEAUT32.79)
3050 * Convert a VT_I2 to a VT_R8.
3052 * PARAMS
3053 * sIn [I] Source
3054 * pDblOut [O] Destination
3056 * RETURNS
3057 * S_OK.
3059 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3061 return _VarR8FromI2(sIn, pDblOut);
3064 /************************************************************************
3065 * VarR8FromI4 (OLEAUT32.80)
3067 * Convert a VT_I4 to a VT_R8.
3069 * PARAMS
3070 * sIn [I] Source
3071 * pDblOut [O] Destination
3073 * RETURNS
3074 * S_OK.
3076 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3078 return _VarR8FromI4(lIn, pDblOut);
3081 /************************************************************************
3082 * VarR8FromR4 (OLEAUT32.81)
3084 * Convert a VT_R4 to a VT_R8.
3086 * PARAMS
3087 * fltIn [I] Source
3088 * pDblOut [O] Destination
3090 * RETURNS
3091 * S_OK.
3093 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3095 return _VarR8FromR4(fltIn, pDblOut);
3098 /************************************************************************
3099 * VarR8FromCy (OLEAUT32.82)
3101 * Convert a VT_CY to a VT_R8.
3103 * PARAMS
3104 * cyIn [I] Source
3105 * pDblOut [O] Destination
3107 * RETURNS
3108 * S_OK.
3110 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3112 return _VarR8FromCy(cyIn, pDblOut);
3115 /************************************************************************
3116 * VarR8FromDate (OLEAUT32.83)
3118 * Convert a VT_DATE to a VT_R8.
3120 * PARAMS
3121 * dateIn [I] Source
3122 * pDblOut [O] Destination
3124 * RETURNS
3125 * S_OK.
3127 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3129 return _VarR8FromDate(dateIn, pDblOut);
3132 /************************************************************************
3133 * VarR8FromStr (OLEAUT32.84)
3135 * Convert a VT_BSTR to a VT_R8.
3137 * PARAMS
3138 * strIn [I] Source
3139 * lcid [I] LCID for the conversion
3140 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3141 * pDblOut [O] Destination
3143 * RETURNS
3144 * Success: S_OK.
3145 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3146 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3148 HRESULT WINAPI VarR8FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3150 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3153 /************************************************************************
3154 * VarR8FromDisp (OLEAUT32.85)
3156 * Convert a VT_DISPATCH to a VT_R8.
3158 * PARAMS
3159 * pdispIn [I] Source
3160 * lcid [I] LCID for conversion
3161 * pDblOut [O] Destination
3163 * RETURNS
3164 * Success: S_OK.
3165 * Failure: E_INVALIDARG, if the source value is invalid
3166 * DISP_E_OVERFLOW, if the value will not fit in the destination
3167 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3169 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3171 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0);
3174 /************************************************************************
3175 * VarR8FromBool (OLEAUT32.86)
3177 * Convert a VT_BOOL to a VT_R8.
3179 * PARAMS
3180 * boolIn [I] Source
3181 * pDblOut [O] Destination
3183 * RETURNS
3184 * S_OK.
3186 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3188 return VarR8FromI2(boolIn, pDblOut);
3191 /************************************************************************
3192 * VarR8FromI1 (OLEAUT32.217)
3194 * Convert a VT_I1 to a VT_R8.
3196 * PARAMS
3197 * cIn [I] Source
3198 * pDblOut [O] Destination
3200 * RETURNS
3201 * Success: S_OK.
3202 * Failure: E_INVALIDARG, if the source value is invalid
3203 * DISP_E_OVERFLOW, if the value will not fit in the destination
3204 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3206 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3208 return _VarR8FromI1(cIn, pDblOut);
3211 /************************************************************************
3212 * VarR8FromUI2 (OLEAUT32.218)
3214 * Convert a VT_UI2 to a VT_R8.
3216 * PARAMS
3217 * usIn [I] Source
3218 * pDblOut [O] Destination
3220 * RETURNS
3221 * Success: S_OK.
3222 * Failure: E_INVALIDARG, if the source value is invalid
3223 * DISP_E_OVERFLOW, if the value will not fit in the destination
3224 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3226 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3228 return _VarR8FromUI2(usIn, pDblOut);
3231 /************************************************************************
3232 * VarR8FromUI4 (OLEAUT32.219)
3234 * Convert a VT_UI4 to a VT_R8.
3236 * PARAMS
3237 * ulIn [I] Source
3238 * pDblOut [O] Destination
3240 * RETURNS
3241 * Success: S_OK.
3242 * Failure: E_INVALIDARG, if the source value is invalid
3243 * DISP_E_OVERFLOW, if the value will not fit in the destination
3244 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3246 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3248 return _VarR8FromUI4(ulIn, pDblOut);
3251 /************************************************************************
3252 * VarR8FromDec (OLEAUT32.220)
3254 * Convert a VT_DECIMAL to a VT_R8.
3256 * PARAMS
3257 * pDecIn [I] Source
3258 * pDblOut [O] Destination
3260 * RETURNS
3261 * Success: S_OK.
3262 * Failure: E_INVALIDARG, if the source value is invalid.
3264 HRESULT WINAPI VarR8FromDec(const DECIMAL* pDecIn, double *pDblOut)
3266 BYTE scale = DEC_SCALE(pDecIn);
3267 double divisor = 1.0, highPart;
3269 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3270 return E_INVALIDARG;
3272 while (scale--)
3273 divisor *= 10;
3275 if (DEC_SIGN(pDecIn))
3276 divisor = -divisor;
3278 if (DEC_HI32(pDecIn))
3280 highPart = (double)DEC_HI32(pDecIn) / divisor;
3281 highPart *= 4294967296.0F;
3282 highPart *= 4294967296.0F;
3284 else
3285 highPart = 0.0;
3287 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3288 return S_OK;
3291 /************************************************************************
3292 * VarR8FromI8 (OLEAUT32.362)
3294 * Convert a VT_I8 to a VT_R8.
3296 * PARAMS
3297 * ullIn [I] Source
3298 * pDblOut [O] Destination
3300 * RETURNS
3301 * S_OK.
3303 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3305 return _VarR8FromI8(llIn, pDblOut);
3308 /************************************************************************
3309 * VarR8FromUI8 (OLEAUT32.363)
3311 * Convert a VT_UI8 to a VT_R8.
3313 * PARAMS
3314 * ullIn [I] Source
3315 * pDblOut [O] Destination
3317 * RETURNS
3318 * S_OK.
3320 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3322 return _VarR8FromUI8(ullIn, pDblOut);
3325 /************************************************************************
3326 * VarR8Pow (OLEAUT32.315)
3328 * Raise a VT_R8 to a power.
3330 * PARAMS
3331 * dblLeft [I] Source
3332 * dblPow [I] Power to raise dblLeft by
3333 * pDblOut [O] Destination
3335 * RETURNS
3336 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3338 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3340 *pDblOut = pow(dblLeft, dblPow);
3341 return S_OK;
3344 /************************************************************************
3345 * VarR8Round (OLEAUT32.317)
3347 * Round a VT_R8 to a given number of decimal points.
3349 * PARAMS
3350 * dblIn [I] Source
3351 * nDig [I] Number of decimal points to round to
3352 * pDblOut [O] Destination for rounded number
3354 * RETURNS
3355 * Success: S_OK. pDblOut is rounded to nDig digits.
3356 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3358 * NOTES
3359 * The native version of this function rounds using the internal
3360 * binary representation of the number. Wine uses the dutch rounding
3361 * convention, so therefore small differences can occur in the value returned.
3362 * MSDN says that you should use your own rounding function if you want
3363 * rounding to be predictable in your application.
3365 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3367 double scale, whole, fract;
3369 if (nDig < 0)
3370 return E_INVALIDARG;
3372 scale = pow(10.0, nDig);
3374 dblIn *= scale;
3375 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3376 fract = dblIn - whole;
3378 if (fract > 0.5)
3379 dblIn = whole + 1.0;
3380 else if (fract == 0.5)
3381 dblIn = whole + fmod(whole, 2.0);
3382 else if (fract >= 0.0)
3383 dblIn = whole;
3384 else if (fract == -0.5)
3385 dblIn = whole - fmod(whole, 2.0);
3386 else if (fract > -0.5)
3387 dblIn = whole;
3388 else
3389 dblIn = whole - 1.0;
3391 *pDblOut = dblIn / scale;
3392 return S_OK;
3395 /* CY
3398 /* Powers of 10 from 0..4 D.P. */
3399 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3400 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3402 /************************************************************************
3403 * VarCyFromUI1 (OLEAUT32.98)
3405 * Convert a VT_UI1 to a VT_CY.
3407 * PARAMS
3408 * bIn [I] Source
3409 * pCyOut [O] Destination
3411 * RETURNS
3412 * Success: S_OK.
3413 * Failure: E_INVALIDARG, if the source value is invalid
3414 * DISP_E_OVERFLOW, if the value will not fit in the destination
3415 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3417 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3419 pCyOut->int64 = (ULONG64)bIn * CY_MULTIPLIER;
3420 return S_OK;
3423 /************************************************************************
3424 * VarCyFromI2 (OLEAUT32.99)
3426 * Convert a VT_I2 to a VT_CY.
3428 * PARAMS
3429 * sIn [I] Source
3430 * pCyOut [O] Destination
3432 * RETURNS
3433 * Success: S_OK.
3434 * Failure: E_INVALIDARG, if the source value is invalid
3435 * DISP_E_OVERFLOW, if the value will not fit in the destination
3436 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3438 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3440 pCyOut->int64 = (LONG64)sIn * CY_MULTIPLIER;
3441 return S_OK;
3444 /************************************************************************
3445 * VarCyFromI4 (OLEAUT32.100)
3447 * Convert a VT_I4 to a VT_CY.
3449 * PARAMS
3450 * sIn [I] Source
3451 * pCyOut [O] Destination
3453 * RETURNS
3454 * Success: S_OK.
3455 * Failure: E_INVALIDARG, if the source value is invalid
3456 * DISP_E_OVERFLOW, if the value will not fit in the destination
3457 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3459 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3461 pCyOut->int64 = (LONG64)lIn * CY_MULTIPLIER;
3462 return S_OK;
3465 /************************************************************************
3466 * VarCyFromR4 (OLEAUT32.101)
3468 * Convert a VT_R4 to a VT_CY.
3470 * PARAMS
3471 * fltIn [I] Source
3472 * pCyOut [O] Destination
3474 * RETURNS
3475 * Success: S_OK.
3476 * Failure: E_INVALIDARG, if the source value is invalid
3477 * DISP_E_OVERFLOW, if the value will not fit in the destination
3478 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3480 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3482 return VarCyFromR8(fltIn, pCyOut);
3485 /************************************************************************
3486 * VarCyFromR8 (OLEAUT32.102)
3488 * Convert a VT_R8 to a VT_CY.
3490 * PARAMS
3491 * dblIn [I] Source
3492 * pCyOut [O] Destination
3494 * RETURNS
3495 * Success: S_OK.
3496 * Failure: E_INVALIDARG, if the source value is invalid
3497 * DISP_E_OVERFLOW, if the value will not fit in the destination
3498 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3500 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3502 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3503 /* This code gives identical results to Win32 on Intel.
3504 * Here we use fp exceptions to catch overflows when storing the value.
3506 static const unsigned short r8_fpcontrol = 0x137f;
3507 static const double r8_multiplier = CY_MULTIPLIER_F;
3508 unsigned short old_fpcontrol, result_fpstatus;
3510 /* Clear exceptions, save the old fp state and load the new state */
3511 __asm__ __volatile__( "fnclex" );
3512 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3513 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3514 /* Perform the conversion. */
3515 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3516 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3517 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3518 /* Save the resulting fp state, load the old state and clear exceptions */
3519 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3520 __asm__ __volatile__( "fnclex" );
3521 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3523 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3524 return DISP_E_OVERFLOW;
3525 #else
3526 /* This version produces slightly different results for boundary cases */
3527 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3528 return DISP_E_OVERFLOW;
3529 dblIn *= CY_MULTIPLIER_F;
3530 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3531 #endif
3532 return S_OK;
3535 /************************************************************************
3536 * VarCyFromDate (OLEAUT32.103)
3538 * Convert a VT_DATE to a VT_CY.
3540 * PARAMS
3541 * dateIn [I] Source
3542 * pCyOut [O] Destination
3544 * RETURNS
3545 * Success: S_OK.
3546 * Failure: E_INVALIDARG, if the source value is invalid
3547 * DISP_E_OVERFLOW, if the value will not fit in the destination
3548 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3550 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3552 return VarCyFromR8(dateIn, pCyOut);
3555 /************************************************************************
3556 * VarCyFromStr (OLEAUT32.104)
3558 * Convert a VT_BSTR to a VT_CY.
3560 * PARAMS
3561 * strIn [I] Source
3562 * lcid [I] LCID for the conversion
3563 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3564 * pCyOut [O] Destination
3566 * RETURNS
3567 * Success: S_OK.
3568 * Failure: E_INVALIDARG, if the source value is invalid
3569 * DISP_E_OVERFLOW, if the value will not fit in the destination
3570 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3572 HRESULT WINAPI VarCyFromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3574 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3577 /************************************************************************
3578 * VarCyFromDisp (OLEAUT32.105)
3580 * Convert a VT_DISPATCH to a VT_CY.
3582 * PARAMS
3583 * pdispIn [I] Source
3584 * lcid [I] LCID for conversion
3585 * pCyOut [O] Destination
3587 * RETURNS
3588 * Success: S_OK.
3589 * Failure: E_INVALIDARG, if the source value is invalid
3590 * DISP_E_OVERFLOW, if the value will not fit in the destination
3591 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3593 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3595 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0);
3598 /************************************************************************
3599 * VarCyFromBool (OLEAUT32.106)
3601 * Convert a VT_BOOL to a VT_CY.
3603 * PARAMS
3604 * boolIn [I] Source
3605 * pCyOut [O] Destination
3607 * RETURNS
3608 * Success: S_OK.
3609 * Failure: E_INVALIDARG, if the source value is invalid
3610 * DISP_E_OVERFLOW, if the value will not fit in the destination
3611 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3613 * NOTES
3614 * While the sign of the boolean is stored in the currency, the value is
3615 * converted to either 0 or 1.
3617 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3619 pCyOut->int64 = (LONG64)boolIn * CY_MULTIPLIER;
3620 return S_OK;
3623 /************************************************************************
3624 * VarCyFromI1 (OLEAUT32.225)
3626 * Convert a VT_I1 to a VT_CY.
3628 * PARAMS
3629 * cIn [I] Source
3630 * pCyOut [O] Destination
3632 * RETURNS
3633 * Success: S_OK.
3634 * Failure: E_INVALIDARG, if the source value is invalid
3635 * DISP_E_OVERFLOW, if the value will not fit in the destination
3636 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3638 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3640 pCyOut->int64 = (LONG64)cIn * CY_MULTIPLIER;
3641 return S_OK;
3644 /************************************************************************
3645 * VarCyFromUI2 (OLEAUT32.226)
3647 * Convert a VT_UI2 to a VT_CY.
3649 * PARAMS
3650 * usIn [I] Source
3651 * pCyOut [O] Destination
3653 * RETURNS
3654 * Success: S_OK.
3655 * Failure: E_INVALIDARG, if the source value is invalid
3656 * DISP_E_OVERFLOW, if the value will not fit in the destination
3657 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3659 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3661 pCyOut->int64 = (ULONG64)usIn * CY_MULTIPLIER;
3662 return S_OK;
3665 /************************************************************************
3666 * VarCyFromUI4 (OLEAUT32.227)
3668 * Convert a VT_UI4 to a VT_CY.
3670 * PARAMS
3671 * ulIn [I] Source
3672 * pCyOut [O] Destination
3674 * RETURNS
3675 * Success: S_OK.
3676 * Failure: E_INVALIDARG, if the source value is invalid
3677 * DISP_E_OVERFLOW, if the value will not fit in the destination
3678 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3680 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3682 pCyOut->int64 = (ULONG64)ulIn * CY_MULTIPLIER;
3683 return S_OK;
3686 /************************************************************************
3687 * VarCyFromDec (OLEAUT32.228)
3689 * Convert a VT_DECIMAL to a VT_CY.
3691 * PARAMS
3692 * pdecIn [I] Source
3693 * pCyOut [O] Destination
3695 * RETURNS
3696 * Success: S_OK.
3697 * Failure: E_INVALIDARG, if the source value is invalid
3698 * DISP_E_OVERFLOW, if the value will not fit in the destination
3699 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3701 HRESULT WINAPI VarCyFromDec(const DECIMAL* pdecIn, CY* pCyOut)
3703 DECIMAL rounded;
3704 HRESULT hRet;
3706 hRet = VarDecRound(pdecIn, 4, &rounded);
3708 if (SUCCEEDED(hRet))
3710 double d;
3712 if (DEC_HI32(&rounded))
3713 return DISP_E_OVERFLOW;
3715 /* Note: Without the casts this promotes to int64 which loses precision */
3716 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3717 if (DEC_SIGN(&rounded))
3718 d = -d;
3719 return VarCyFromR8(d, pCyOut);
3721 return hRet;
3724 /************************************************************************
3725 * VarCyFromI8 (OLEAUT32.366)
3727 * Convert a VT_I8 to a VT_CY.
3729 * PARAMS
3730 * ullIn [I] Source
3731 * pCyOut [O] Destination
3733 * RETURNS
3734 * Success: S_OK.
3735 * Failure: E_INVALIDARG, if the source value is invalid
3736 * DISP_E_OVERFLOW, if the value will not fit in the destination
3737 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3739 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3741 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3742 pCyOut->int64 = llIn * CY_MULTIPLIER;
3743 return S_OK;
3746 /************************************************************************
3747 * VarCyFromUI8 (OLEAUT32.375)
3749 * Convert a VT_UI8 to a VT_CY.
3751 * PARAMS
3752 * ullIn [I] Source
3753 * pCyOut [O] Destination
3755 * RETURNS
3756 * Success: S_OK.
3757 * Failure: E_INVALIDARG, if the source value is invalid
3758 * DISP_E_OVERFLOW, if the value will not fit in the destination
3759 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3761 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3763 if (ullIn > (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3764 pCyOut->int64 = ullIn * CY_MULTIPLIER;
3765 return S_OK;
3768 /************************************************************************
3769 * VarCyAdd (OLEAUT32.299)
3771 * Add one CY to another.
3773 * PARAMS
3774 * cyLeft [I] Source
3775 * cyRight [I] Value to add
3776 * pCyOut [O] Destination
3778 * RETURNS
3779 * Success: S_OK.
3780 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3782 HRESULT WINAPI VarCyAdd(CY cyLeft, CY cyRight, CY* pCyOut)
3784 double l,r;
3785 _VarR8FromCy(cyLeft, &l);
3786 _VarR8FromCy(cyRight, &r);
3787 l = l + r;
3788 return VarCyFromR8(l, pCyOut);
3791 /************************************************************************
3792 * VarCyMul (OLEAUT32.303)
3794 * Multiply one CY by another.
3796 * PARAMS
3797 * cyLeft [I] Source
3798 * cyRight [I] Value to multiply by
3799 * pCyOut [O] Destination
3801 * RETURNS
3802 * Success: S_OK.
3803 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3805 HRESULT WINAPI VarCyMul(CY cyLeft, CY cyRight, CY* pCyOut)
3807 double l,r;
3808 _VarR8FromCy(cyLeft, &l);
3809 _VarR8FromCy(cyRight, &r);
3810 l = l * r;
3811 return VarCyFromR8(l, pCyOut);
3814 /************************************************************************
3815 * VarCyMulI4 (OLEAUT32.304)
3817 * Multiply one CY by a VT_I4.
3819 * PARAMS
3820 * cyLeft [I] Source
3821 * lRight [I] Value to multiply by
3822 * pCyOut [O] Destination
3824 * RETURNS
3825 * Success: S_OK.
3826 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3828 HRESULT WINAPI VarCyMulI4(CY cyLeft, LONG lRight, CY* pCyOut)
3830 double d;
3832 _VarR8FromCy(cyLeft, &d);
3833 d = d * lRight;
3834 return VarCyFromR8(d, pCyOut);
3837 /************************************************************************
3838 * VarCySub (OLEAUT32.305)
3840 * Subtract one CY from another.
3842 * PARAMS
3843 * cyLeft [I] Source
3844 * cyRight [I] Value to subtract
3845 * pCyOut [O] Destination
3847 * RETURNS
3848 * Success: S_OK.
3849 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3851 HRESULT WINAPI VarCySub(CY cyLeft, CY cyRight, CY* pCyOut)
3853 double l,r;
3854 _VarR8FromCy(cyLeft, &l);
3855 _VarR8FromCy(cyRight, &r);
3856 l = l - r;
3857 return VarCyFromR8(l, pCyOut);
3860 /************************************************************************
3861 * VarCyAbs (OLEAUT32.306)
3863 * Convert a VT_CY into its absolute value.
3865 * PARAMS
3866 * cyIn [I] Source
3867 * pCyOut [O] Destination
3869 * RETURNS
3870 * Success: S_OK. pCyOut contains the absolute value.
3871 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3873 HRESULT WINAPI VarCyAbs(CY cyIn, CY* pCyOut)
3875 if (cyIn.s.Hi == 0x80000000 && !cyIn.s.Lo)
3876 return DISP_E_OVERFLOW;
3878 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3879 return S_OK;
3882 /************************************************************************
3883 * VarCyFix (OLEAUT32.307)
3885 * Return the integer part of a VT_CY.
3887 * PARAMS
3888 * cyIn [I] Source
3889 * pCyOut [O] Destination
3891 * RETURNS
3892 * Success: S_OK.
3893 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3895 * NOTES
3896 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3897 * negative numbers away from 0, while this function rounds them towards zero.
3899 HRESULT WINAPI VarCyFix(CY cyIn, CY* pCyOut)
3901 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3902 pCyOut->int64 *= CY_MULTIPLIER;
3903 return S_OK;
3906 /************************************************************************
3907 * VarCyInt (OLEAUT32.308)
3909 * Return the integer part of a VT_CY.
3911 * PARAMS
3912 * cyIn [I] Source
3913 * pCyOut [O] Destination
3915 * RETURNS
3916 * Success: S_OK.
3917 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3919 * NOTES
3920 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3921 * negative numbers towards 0, while this function rounds them away from zero.
3923 HRESULT WINAPI VarCyInt(CY cyIn, CY* pCyOut)
3925 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3926 pCyOut->int64 *= CY_MULTIPLIER;
3928 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3930 pCyOut->int64 -= CY_MULTIPLIER;
3932 return S_OK;
3935 /************************************************************************
3936 * VarCyNeg (OLEAUT32.309)
3938 * Change the sign of a VT_CY.
3940 * PARAMS
3941 * cyIn [I] Source
3942 * pCyOut [O] Destination
3944 * RETURNS
3945 * Success: S_OK.
3946 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3948 HRESULT WINAPI VarCyNeg(CY cyIn, CY* pCyOut)
3950 if (cyIn.s.Hi == 0x80000000 && !cyIn.s.Lo)
3951 return DISP_E_OVERFLOW;
3953 pCyOut->int64 = -cyIn.int64;
3954 return S_OK;
3957 /************************************************************************
3958 * VarCyRound (OLEAUT32.310)
3960 * Change the precision of a VT_CY.
3962 * PARAMS
3963 * cyIn [I] Source
3964 * cDecimals [I] New number of decimals to keep
3965 * pCyOut [O] Destination
3967 * RETURNS
3968 * Success: S_OK.
3969 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3971 HRESULT WINAPI VarCyRound(CY cyIn, int cDecimals, CY* pCyOut)
3973 if (cDecimals < 0)
3974 return E_INVALIDARG;
3976 if (cDecimals > 3)
3978 /* Rounding to more precision than we have */
3979 *pCyOut = cyIn;
3980 return S_OK;
3982 else
3984 double d, div = CY_Divisors[cDecimals];
3986 _VarR8FromCy(cyIn, &d);
3987 d = d * div;
3988 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3989 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3990 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3991 return S_OK;
3995 /************************************************************************
3996 * VarCyCmp (OLEAUT32.311)
3998 * Compare two VT_CY values.
4000 * PARAMS
4001 * cyLeft [I] Source
4002 * cyRight [I] Value to compare
4004 * RETURNS
4005 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4006 * compare is less, equal or greater than source respectively.
4007 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4009 HRESULT WINAPI VarCyCmp(CY cyLeft, CY cyRight)
4011 HRESULT hRet;
4012 CY result;
4014 /* Subtract right from left, and compare the result to 0 */
4015 hRet = VarCySub(cyLeft, cyRight, &result);
4017 if (SUCCEEDED(hRet))
4019 if (result.int64 < 0)
4020 hRet = (HRESULT)VARCMP_LT;
4021 else if (result.int64 > 0)
4022 hRet = (HRESULT)VARCMP_GT;
4023 else
4024 hRet = (HRESULT)VARCMP_EQ;
4026 return hRet;
4029 /************************************************************************
4030 * VarCyCmpR8 (OLEAUT32.312)
4032 * Compare a VT_CY to a double
4034 * PARAMS
4035 * cyLeft [I] Currency Source
4036 * dblRight [I] double to compare to cyLeft
4038 * RETURNS
4039 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4040 * less than, equal to or greater than cyLeft respectively.
4041 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4043 HRESULT WINAPI VarCyCmpR8(CY cyLeft, double dblRight)
4045 HRESULT hRet;
4046 CY cyRight;
4048 hRet = VarCyFromR8(dblRight, &cyRight);
4050 if (SUCCEEDED(hRet))
4051 hRet = VarCyCmp(cyLeft, cyRight);
4053 return hRet;
4056 /************************************************************************
4057 * VarCyMulI8 (OLEAUT32.329)
4059 * Multiply a VT_CY by a VT_I8.
4061 * PARAMS
4062 * cyLeft [I] Source
4063 * llRight [I] Value to multiply by
4064 * pCyOut [O] Destination
4066 * RETURNS
4067 * Success: S_OK.
4068 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4070 HRESULT WINAPI VarCyMulI8(CY cyLeft, LONG64 llRight, CY* pCyOut)
4072 double d;
4074 _VarR8FromCy(cyLeft, &d);
4075 d = d * (double)llRight;
4076 return VarCyFromR8(d, pCyOut);
4079 /* DECIMAL
4082 /************************************************************************
4083 * VarDecFromUI1 (OLEAUT32.190)
4085 * Convert a VT_UI1 to a DECIMAL.
4087 * PARAMS
4088 * bIn [I] Source
4089 * pDecOut [O] Destination
4091 * RETURNS
4092 * S_OK.
4094 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4096 return VarDecFromUI4(bIn, pDecOut);
4099 /************************************************************************
4100 * VarDecFromI2 (OLEAUT32.191)
4102 * Convert a VT_I2 to a DECIMAL.
4104 * PARAMS
4105 * sIn [I] Source
4106 * pDecOut [O] Destination
4108 * RETURNS
4109 * S_OK.
4111 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4113 return VarDecFromI4(sIn, pDecOut);
4116 /************************************************************************
4117 * VarDecFromI4 (OLEAUT32.192)
4119 * Convert a VT_I4 to a DECIMAL.
4121 * PARAMS
4122 * sIn [I] Source
4123 * pDecOut [O] Destination
4125 * RETURNS
4126 * S_OK.
4128 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4130 DEC_HI32(pDecOut) = 0;
4131 DEC_MID32(pDecOut) = 0;
4133 if (lIn < 0)
4135 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4136 DEC_LO32(pDecOut) = -lIn;
4138 else
4140 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4141 DEC_LO32(pDecOut) = lIn;
4143 return S_OK;
4146 /* internal representation of the value stored in a DECIMAL. The bytes are
4147 stored from LSB at index 0 to MSB at index 11
4149 typedef struct DECIMAL_internal
4151 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4152 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4153 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4154 } VARIANT_DI;
4156 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest);
4157 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest);
4158 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to);
4159 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to);
4160 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor);
4161 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n);
4163 /************************************************************************
4164 * VarDecFromR4 (OLEAUT32.193)
4166 * Convert a VT_R4 to a DECIMAL.
4168 * PARAMS
4169 * fltIn [I] Source
4170 * pDecOut [O] Destination
4172 * RETURNS
4173 * S_OK.
4175 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4177 VARIANT_DI di;
4178 HRESULT hres;
4180 hres = VARIANT_DI_FromR4(fltIn, &di);
4181 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4182 return hres;
4185 /************************************************************************
4186 * VarDecFromR8 (OLEAUT32.194)
4188 * Convert a VT_R8 to a DECIMAL.
4190 * PARAMS
4191 * dblIn [I] Source
4192 * pDecOut [O] Destination
4194 * RETURNS
4195 * S_OK.
4197 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4199 VARIANT_DI di;
4200 HRESULT hres;
4202 hres = VARIANT_DI_FromR8(dblIn, &di);
4203 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4204 return hres;
4207 /************************************************************************
4208 * VarDecFromDate (OLEAUT32.195)
4210 * Convert a VT_DATE to a DECIMAL.
4212 * PARAMS
4213 * dateIn [I] Source
4214 * pDecOut [O] Destination
4216 * RETURNS
4217 * S_OK.
4219 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4221 return VarDecFromR8(dateIn, pDecOut);
4224 /************************************************************************
4225 * VarDecFromCy (OLEAUT32.196)
4227 * Convert a VT_CY to a DECIMAL.
4229 * PARAMS
4230 * cyIn [I] Source
4231 * pDecOut [O] Destination
4233 * RETURNS
4234 * S_OK.
4236 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4238 DEC_HI32(pDecOut) = 0;
4240 /* Note: This assumes 2s complement integer representation */
4241 if (cyIn.s.Hi & 0x80000000)
4243 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4244 DEC_LO64(pDecOut) = -cyIn.int64;
4246 else
4248 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4249 DEC_MID32(pDecOut) = cyIn.s.Hi;
4250 DEC_LO32(pDecOut) = cyIn.s.Lo;
4252 return S_OK;
4255 /************************************************************************
4256 * VarDecFromStr (OLEAUT32.197)
4258 * Convert a VT_BSTR to a DECIMAL.
4260 * PARAMS
4261 * strIn [I] Source
4262 * lcid [I] LCID for the conversion
4263 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4264 * pDecOut [O] Destination
4266 * RETURNS
4267 * Success: S_OK.
4268 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4270 HRESULT WINAPI VarDecFromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4272 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4275 /************************************************************************
4276 * VarDecFromDisp (OLEAUT32.198)
4278 * Convert a VT_DISPATCH to a DECIMAL.
4280 * PARAMS
4281 * pdispIn [I] Source
4282 * lcid [I] LCID for conversion
4283 * pDecOut [O] Destination
4285 * RETURNS
4286 * Success: S_OK.
4287 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4289 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4291 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0);
4294 /************************************************************************
4295 * VarDecFromBool (OLEAUT32.199)
4297 * Convert a VT_BOOL to a DECIMAL.
4299 * PARAMS
4300 * bIn [I] Source
4301 * pDecOut [O] Destination
4303 * RETURNS
4304 * S_OK.
4306 * NOTES
4307 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4309 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4311 DEC_HI32(pDecOut) = 0;
4312 DEC_MID32(pDecOut) = 0;
4313 if (bIn)
4315 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4316 DEC_LO32(pDecOut) = 1;
4318 else
4320 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4321 DEC_LO32(pDecOut) = 0;
4323 return S_OK;
4326 /************************************************************************
4327 * VarDecFromI1 (OLEAUT32.241)
4329 * Convert a VT_I1 to a DECIMAL.
4331 * PARAMS
4332 * cIn [I] Source
4333 * pDecOut [O] Destination
4335 * RETURNS
4336 * S_OK.
4338 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4340 return VarDecFromI4(cIn, pDecOut);
4343 /************************************************************************
4344 * VarDecFromUI2 (OLEAUT32.242)
4346 * Convert a VT_UI2 to a DECIMAL.
4348 * PARAMS
4349 * usIn [I] Source
4350 * pDecOut [O] Destination
4352 * RETURNS
4353 * S_OK.
4355 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4357 return VarDecFromUI4(usIn, pDecOut);
4360 /************************************************************************
4361 * VarDecFromUI4 (OLEAUT32.243)
4363 * Convert a VT_UI4 to a DECIMAL.
4365 * PARAMS
4366 * ulIn [I] Source
4367 * pDecOut [O] Destination
4369 * RETURNS
4370 * S_OK.
4372 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4374 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4375 DEC_HI32(pDecOut) = 0;
4376 DEC_MID32(pDecOut) = 0;
4377 DEC_LO32(pDecOut) = ulIn;
4378 return S_OK;
4381 /************************************************************************
4382 * VarDecFromI8 (OLEAUT32.374)
4384 * Convert a VT_I8 to a DECIMAL.
4386 * PARAMS
4387 * llIn [I] Source
4388 * pDecOut [O] Destination
4390 * RETURNS
4391 * S_OK.
4393 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4395 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4397 DEC_HI32(pDecOut) = 0;
4399 /* Note: This assumes 2s complement integer representation */
4400 if (pLi->u.HighPart & 0x80000000)
4402 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4403 DEC_LO64(pDecOut) = -pLi->QuadPart;
4405 else
4407 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4408 DEC_MID32(pDecOut) = pLi->u.HighPart;
4409 DEC_LO32(pDecOut) = pLi->u.LowPart;
4411 return S_OK;
4414 /************************************************************************
4415 * VarDecFromUI8 (OLEAUT32.375)
4417 * Convert a VT_UI8 to a DECIMAL.
4419 * PARAMS
4420 * ullIn [I] Source
4421 * pDecOut [O] Destination
4423 * RETURNS
4424 * S_OK.
4426 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4428 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4429 DEC_HI32(pDecOut) = 0;
4430 DEC_LO64(pDecOut) = ullIn;
4431 return S_OK;
4434 /* Make two DECIMALS the same scale; used by math functions below */
4435 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4436 const DECIMAL** ppDecRight,
4437 DECIMAL pDecOut[2])
4439 static DECIMAL scaleFactor;
4440 unsigned char remainder;
4441 DECIMAL decTemp;
4442 VARIANT_DI di;
4443 int scaleAmount, i;
4445 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4446 return E_INVALIDARG;
4448 DEC_LO32(&scaleFactor) = 10;
4450 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4452 if (!scaleAmount)
4453 return S_OK; /* Same scale */
4455 if (scaleAmount > 0)
4457 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4458 *ppDecRight = &pDecOut[0];
4460 else
4462 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4463 *ppDecLeft = &pDecOut[0];
4464 i = -scaleAmount;
4467 /* Multiply up the value to be scaled by the correct amount (if possible) */
4468 while (i > 0 && SUCCEEDED(VarDecMul(&decTemp, &scaleFactor, &pDecOut[0])))
4470 decTemp = pDecOut[0];
4471 i--;
4474 if (!i)
4476 DEC_SCALE(&pDecOut[0]) += (scaleAmount > 0) ? scaleAmount : (-scaleAmount);
4477 return S_OK; /* Same scale */
4480 /* Scaling further not possible, reduce accuracy of other argument */
4481 pDecOut[0] = decTemp;
4482 if (scaleAmount > 0)
4484 DEC_SCALE(&pDecOut[0]) += scaleAmount - i;
4485 VARIANT_DIFromDec(*ppDecLeft, &di);
4486 *ppDecLeft = &pDecOut[1];
4488 else
4490 DEC_SCALE(&pDecOut[0]) += (-scaleAmount) - i;
4491 VARIANT_DIFromDec(*ppDecRight, &di);
4492 *ppDecRight = &pDecOut[1];
4495 di.scale -= i;
4496 remainder = 0;
4497 while (i-- > 0 && !VARIANT_int_iszero(di.bitsnum, ARRAY_SIZE(di.bitsnum)))
4499 remainder = VARIANT_int_divbychar(di.bitsnum, ARRAY_SIZE(di.bitsnum), 10);
4500 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4503 /* round up the result - native oleaut32 does this */
4504 if (remainder >= 5) {
4505 for (remainder = 1, i = 0; i < ARRAY_SIZE(di.bitsnum) && remainder; i++) {
4506 ULONGLONG digit = di.bitsnum[i] + 1;
4507 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4508 di.bitsnum[i] = digit & 0xFFFFFFFF;
4512 VARIANT_DecFromDI(&di, &pDecOut[1]);
4513 return S_OK;
4516 /* Add two unsigned 32 bit values with overflow */
4517 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4519 ULARGE_INTEGER ul64;
4521 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4522 *pulHigh = ul64.u.HighPart;
4523 return ul64.u.LowPart;
4526 /* Subtract two unsigned 32 bit values with underflow */
4527 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4529 BOOL invert = FALSE;
4530 ULARGE_INTEGER ul64;
4532 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4533 if (ulLeft < ulRight)
4534 invert = TRUE;
4536 if (ul64.QuadPart > (ULONG64)*pulHigh)
4537 ul64.QuadPart -= (ULONG64)*pulHigh;
4538 else
4540 ul64.QuadPart -= (ULONG64)*pulHigh;
4541 invert = TRUE;
4543 if (invert)
4544 ul64.u.HighPart = -ul64.u.HighPart ;
4546 *pulHigh = ul64.u.HighPart;
4547 return ul64.u.LowPart;
4550 /* Multiply two unsigned 32 bit values with overflow */
4551 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4553 ULARGE_INTEGER ul64;
4555 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4556 *pulHigh = ul64.u.HighPart;
4557 return ul64.u.LowPart;
4560 /* Compare two decimals that have the same scale */
4561 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4563 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4564 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4565 return -1;
4566 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4567 return 0;
4568 return 1;
4571 /************************************************************************
4572 * VarDecAdd (OLEAUT32.177)
4574 * Add one DECIMAL to another.
4576 * PARAMS
4577 * pDecLeft [I] Source
4578 * pDecRight [I] Value to add
4579 * pDecOut [O] Destination
4581 * RETURNS
4582 * Success: S_OK.
4583 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4585 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4587 HRESULT hRet;
4588 DECIMAL scaled[2];
4590 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, scaled);
4592 if (SUCCEEDED(hRet))
4594 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4595 ULONG overflow = 0;
4596 BYTE sign = DECIMAL_POS;
4597 int cmp;
4599 /* Correct for the sign of the result */
4600 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4602 /* -x + -y : Negative */
4603 sign = DECIMAL_NEG;
4604 goto VarDecAdd_AsPositive;
4606 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4608 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4610 /* -x + y : Negative if x > y */
4611 if (cmp > 0)
4613 sign = DECIMAL_NEG;
4614 VarDecAdd_AsNegative:
4615 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4616 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4617 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4619 else
4621 VarDecAdd_AsInvertedNegative:
4622 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4623 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4624 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4627 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4629 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4631 /* x + -y : Negative if x <= y */
4632 if (cmp <= 0)
4634 sign = DECIMAL_NEG;
4635 goto VarDecAdd_AsInvertedNegative;
4637 goto VarDecAdd_AsNegative;
4639 else
4641 /* x + y : Positive */
4642 VarDecAdd_AsPositive:
4643 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4644 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4645 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4647 if (overflow)
4649 int i;
4650 DWORD n[4];
4651 unsigned char remainder;
4653 if (!DEC_SCALE(pDecLeft))
4654 return DISP_E_OVERFLOW;
4656 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft) - 1;
4657 DEC_SIGN(pDecOut) = sign;
4659 n[0] = DEC_LO32(pDecOut);
4660 n[1] = DEC_MID32(pDecOut);
4661 n[2] = DEC_HI32(pDecOut);
4662 n[3] = overflow;
4664 remainder = VARIANT_int_divbychar(n,4,10);
4666 /* round up the result */
4667 if (remainder >= 5)
4669 for (remainder = 1, i = 0; i < ARRAY_SIZE(n) && remainder; i++)
4671 ULONGLONG digit = n[i] + 1;
4672 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4673 n[i] = digit & 0xFFFFFFFF;
4677 DEC_LO32(pDecOut) = n[0] ;
4678 DEC_MID32(pDecOut) = n[1];
4679 DEC_HI32(pDecOut) = n[2];
4681 return S_OK;
4685 if (overflow)
4686 return DISP_E_OVERFLOW; /* overflowed */
4688 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4689 DEC_SIGN(pDecOut) = sign;
4691 return hRet;
4694 /* translate from external DECIMAL format into an internal representation */
4695 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4697 to->scale = DEC_SCALE(from);
4698 to->sign = DEC_SIGN(from) ? 1 : 0;
4700 to->bitsnum[0] = DEC_LO32(from);
4701 to->bitsnum[1] = DEC_MID32(from);
4702 to->bitsnum[2] = DEC_HI32(from);
4705 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to)
4707 if (from->sign) {
4708 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4709 } else {
4710 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4713 DEC_LO32(to) = from->bitsnum[0];
4714 DEC_MID32(to) = from->bitsnum[1];
4715 DEC_HI32(to) = from->bitsnum[2];
4718 /* clear an internal representation of a DECIMAL */
4719 static void VARIANT_DI_clear(VARIANT_DI * i)
4721 memset(i, 0, sizeof(VARIANT_DI));
4724 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4725 size is supported. The value in p is replaced by the quotient of the division, and
4726 the remainder is returned as a result. This routine is most often used with a divisor
4727 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4729 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4731 if (divisor == 0) {
4732 /* division by 0 */
4733 return 0xFF;
4734 } else if (divisor == 1) {
4735 /* dividend remains unchanged */
4736 return 0;
4737 } else {
4738 unsigned char remainder = 0;
4739 ULONGLONG iTempDividend;
4740 signed int i;
4742 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4743 for (; i >= 0; i--) {
4744 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4745 remainder = iTempDividend % divisor;
4746 p[i] = iTempDividend / divisor;
4749 return remainder;
4753 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4754 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n)
4756 for (; n > 0; n--) if (*p++ != 0) return FALSE;
4757 return TRUE;
4760 /* multiply two DECIMALS, without changing either one, and place result in third
4761 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4762 digits when scale > 0 in order to fit an overflowing result. Final overflow
4763 flag is returned.
4765 static int VARIANT_DI_mul(const VARIANT_DI * a, const VARIANT_DI * b, VARIANT_DI * result)
4767 BOOL r_overflow = FALSE;
4768 DWORD running[6];
4769 signed int mulstart;
4771 VARIANT_DI_clear(result);
4772 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4774 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4775 of the result is formed by adding the scales of the operands.
4777 result->scale = a->scale + b->scale;
4778 memset(running, 0, sizeof(running));
4780 /* count number of leading zero-bytes in operand A */
4781 for (mulstart = ARRAY_SIZE(a->bitsnum) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4782 if (mulstart < 0) {
4783 /* result is 0, because operand A is 0 */
4784 result->scale = 0;
4785 result->sign = 0;
4786 } else {
4787 unsigned char remainder = 0;
4788 int iA;
4790 /* perform actual multiplication */
4791 for (iA = 0; iA <= mulstart; iA++) {
4792 ULONG iOverflowMul;
4793 int iB;
4795 for (iOverflowMul = 0, iB = 0; iB < ARRAY_SIZE(b->bitsnum); iB++) {
4796 ULONG iRV;
4797 int iR;
4799 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4800 iR = iA + iB;
4801 do {
4802 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4803 iR++;
4804 } while (iRV);
4808 /* Too bad - native oleaut does not do this, so we should not either */
4809 #if 0
4810 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4811 This operation should not lose significant digits, and gives an
4812 opportunity to reduce the possibility of overflows in future
4813 operations issued by the application.
4815 while (result->scale > 0) {
4816 memcpy(quotient, running, sizeof(quotient));
4817 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4818 if (remainder > 0) break;
4819 memcpy(running, quotient, sizeof(quotient));
4820 result->scale--;
4822 #endif
4823 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4824 This operation *will* lose significant digits of the result because
4825 all the factors of 10 were consumed by the previous operation.
4827 while (result->scale > 0 && !VARIANT_int_iszero(running + ARRAY_SIZE(result->bitsnum),
4828 ARRAY_SIZE(running) - ARRAY_SIZE(result->bitsnum))) {
4830 remainder = VARIANT_int_divbychar(running, ARRAY_SIZE(running), 10);
4831 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4832 result->scale--;
4835 /* round up the result - native oleaut32 does this */
4836 if (remainder >= 5) {
4837 unsigned int i;
4838 for (remainder = 1, i = 0; i < ARRAY_SIZE(running) && remainder; i++) {
4839 ULONGLONG digit = running[i] + 1;
4840 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4841 running[i] = digit & 0xFFFFFFFF;
4845 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4846 and copy result bits into result structure
4848 r_overflow = !VARIANT_int_iszero(running + ARRAY_SIZE(result->bitsnum),
4849 ARRAY_SIZE(running) - ARRAY_SIZE(result->bitsnum));
4850 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4852 return r_overflow;
4855 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4856 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4857 success, FALSE if insufficient space in output buffer.
4859 static BOOL VARIANT_DI_tostringW(const VARIANT_DI * a, WCHAR * s, unsigned int n)
4861 BOOL overflow = FALSE;
4862 DWORD quotient[3];
4863 unsigned char remainder;
4864 unsigned int i;
4866 /* place negative sign */
4867 if (!VARIANT_int_iszero(a->bitsnum, ARRAY_SIZE(a->bitsnum)) && a->sign) {
4868 if (n > 0) {
4869 *s++ = '-';
4870 n--;
4872 else overflow = TRUE;
4875 /* prepare initial 0 */
4876 if (!overflow) {
4877 if (n >= 2) {
4878 s[0] = '0';
4879 s[1] = '\0';
4880 } else overflow = TRUE;
4883 i = 0;
4884 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4885 while (!overflow && !VARIANT_int_iszero(quotient, ARRAY_SIZE(quotient))) {
4886 remainder = VARIANT_int_divbychar(quotient, ARRAY_SIZE(quotient), 10);
4887 if (i + 2 > n) {
4888 overflow = TRUE;
4889 } else {
4890 s[i++] = '0' + remainder;
4891 s[i] = '\0';
4895 if (!overflow && !VARIANT_int_iszero(a->bitsnum, ARRAY_SIZE(a->bitsnum))) {
4897 /* reverse order of digits */
4898 WCHAR * x = s; WCHAR * y = s + i - 1;
4899 while (x < y) {
4900 *x ^= *y;
4901 *y ^= *x;
4902 *x++ ^= *y--;
4905 /* check for decimal point. "i" now has string length */
4906 if (i <= a->scale) {
4907 unsigned int numzeroes = a->scale + 1 - i;
4908 if (i + 1 + numzeroes >= n) {
4909 overflow = TRUE;
4910 } else {
4911 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4912 i += numzeroes;
4913 while (numzeroes > 0) {
4914 s[--numzeroes] = '0';
4919 /* place decimal point */
4920 if (a->scale > 0) {
4921 unsigned int periodpos = i - a->scale;
4922 if (i + 2 >= n) {
4923 overflow = TRUE;
4924 } else {
4925 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4926 s[periodpos] = '.'; i++;
4928 /* remove extra zeros at the end, if any */
4929 while (s[i - 1] == '0') s[--i] = '\0';
4930 if (s[i - 1] == '.') s[--i] = '\0';
4935 return !overflow;
4938 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4939 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4941 DWORD shifted;
4942 unsigned int i;
4944 /* shift whole DWORDs to the left */
4945 while (shift >= 32)
4947 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4948 *p = 0; shift -= 32;
4951 /* shift remainder (1..31 bits) */
4952 shifted = 0;
4953 if (shift > 0) for (i = 0; i < n; i++)
4955 DWORD b;
4956 b = p[i] >> (32 - shift);
4957 p[i] = (p[i] << shift) | shifted;
4958 shifted = b;
4962 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4963 Value at v is incremented by the value at p. Any size is supported, provided
4964 that v is not shorter than p. Any unapplied carry is returned as a result.
4966 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, const DWORD * p,
4967 unsigned int np)
4969 unsigned char carry = 0;
4971 if (nv >= np) {
4972 ULONGLONG sum;
4973 unsigned int i;
4975 for (i = 0; i < np; i++) {
4976 sum = (ULONGLONG)v[i]
4977 + (ULONGLONG)p[i]
4978 + (ULONGLONG)carry;
4979 v[i] = sum & 0xffffffff;
4980 carry = sum >> 32;
4982 for (; i < nv && carry; i++) {
4983 sum = (ULONGLONG)v[i]
4984 + (ULONGLONG)carry;
4985 v[i] = sum & 0xffffffff;
4986 carry = sum >> 32;
4989 return carry;
4992 /* perform integral division with operand p as dividend. Parameter n indicates
4993 number of available DWORDs in divisor p, but available space in p must be
4994 actually at least 2 * n DWORDs, because the remainder of the integral
4995 division is built in the next n DWORDs past the start of the quotient. This
4996 routine replaces the dividend in p with the quotient, and appends n
4997 additional DWORDs for the remainder.
4999 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
5000 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
5001 source code to the VLI (Very Large Integer) division operator. This algorithm
5002 was then heavily modified by me (Alex Villacis Lasso) in order to handle
5003 variably-scaled integers such as the MS DECIMAL representation.
5005 static void VARIANT_int_div(DWORD * p, unsigned int n, const DWORD * divisor,
5006 unsigned int dn)
5008 unsigned int i;
5009 DWORD tempsub[8];
5010 DWORD * negdivisor = tempsub + n;
5012 /* build 2s-complement of divisor */
5013 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
5014 p[n] = 1;
5015 VARIANT_int_add(negdivisor, n, p + n, 1);
5016 memset(p + n, 0, n * sizeof(DWORD));
5018 /* skip all leading zero DWORDs in quotient */
5019 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
5020 /* i is now number of DWORDs left to process */
5021 for (i <<= 5; i < (n << 5); i++) {
5022 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
5024 /* trial subtraction */
5025 memcpy(tempsub, p + n, n * sizeof(DWORD));
5026 VARIANT_int_add(tempsub, n, negdivisor, n);
5028 /* check whether result of subtraction was negative */
5029 if ((tempsub[n - 1] & 0x80000000) == 0) {
5030 memcpy(p + n, tempsub, n * sizeof(DWORD));
5031 p[0] |= 1;
5036 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
5037 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
5039 unsigned int i;
5040 ULONG iOverflowMul;
5042 for (iOverflowMul = 0, i = 0; i < n; i++)
5043 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
5044 return (unsigned char)iOverflowMul;
5047 /* increment value in A by the value indicated in B, with scale adjusting.
5048 Modifies parameters by adjusting scales. Returns 0 if addition was
5049 successful, nonzero if a parameter underflowed before it could be
5050 successfully used in the addition.
5052 static int VARIANT_int_addlossy(
5053 DWORD * a, int * ascale, unsigned int an,
5054 DWORD * b, int * bscale, unsigned int bn)
5056 int underflow = 0;
5058 if (VARIANT_int_iszero(a, an)) {
5059 /* if A is zero, copy B into A, after removing digits */
5060 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
5061 VARIANT_int_divbychar(b, bn, 10);
5062 (*bscale)--;
5064 memcpy(a, b, an * sizeof(DWORD));
5065 *ascale = *bscale;
5066 } else if (!VARIANT_int_iszero(b, bn)) {
5067 unsigned int tn = an + 1;
5068 DWORD t[5];
5070 if (bn + 1 > tn) tn = bn + 1;
5071 if (*ascale != *bscale) {
5072 /* first (optimistic) try - try to scale down the one with the bigger
5073 scale, while this number is divisible by 10 */
5074 DWORD * digitchosen;
5075 unsigned int nchosen;
5076 int * scalechosen;
5077 int targetscale;
5079 if (*ascale < *bscale) {
5080 targetscale = *ascale;
5081 scalechosen = bscale;
5082 digitchosen = b;
5083 nchosen = bn;
5084 } else {
5085 targetscale = *bscale;
5086 scalechosen = ascale;
5087 digitchosen = a;
5088 nchosen = an;
5090 memset(t, 0, tn * sizeof(DWORD));
5091 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5093 /* divide by 10 until target scale is reached */
5094 while (*scalechosen > targetscale) {
5095 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5096 if (!remainder) {
5097 (*scalechosen)--;
5098 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5099 } else break;
5103 if (*ascale != *bscale) {
5104 DWORD * digitchosen;
5105 unsigned int nchosen;
5106 int * scalechosen;
5107 int targetscale;
5109 /* try to scale up the one with the smaller scale */
5110 if (*ascale > *bscale) {
5111 targetscale = *ascale;
5112 scalechosen = bscale;
5113 digitchosen = b;
5114 nchosen = bn;
5115 } else {
5116 targetscale = *bscale;
5117 scalechosen = ascale;
5118 digitchosen = a;
5119 nchosen = an;
5121 memset(t, 0, tn * sizeof(DWORD));
5122 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5124 /* multiply by 10 until target scale is reached, or
5125 significant bytes overflow the number
5127 while (*scalechosen < targetscale && t[nchosen] == 0) {
5128 VARIANT_int_mulbychar(t, tn, 10);
5129 if (t[nchosen] == 0) {
5130 /* still does not overflow */
5131 (*scalechosen)++;
5132 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5137 if (*ascale != *bscale) {
5138 /* still different? try to scale down the one with the bigger scale
5139 (this *will* lose significant digits) */
5140 DWORD * digitchosen;
5141 unsigned int nchosen;
5142 int * scalechosen;
5143 int targetscale;
5145 if (*ascale < *bscale) {
5146 targetscale = *ascale;
5147 scalechosen = bscale;
5148 digitchosen = b;
5149 nchosen = bn;
5150 } else {
5151 targetscale = *bscale;
5152 scalechosen = ascale;
5153 digitchosen = a;
5154 nchosen = an;
5156 memset(t, 0, tn * sizeof(DWORD));
5157 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5159 /* divide by 10 until target scale is reached */
5160 while (*scalechosen > targetscale) {
5161 VARIANT_int_divbychar(t, tn, 10);
5162 (*scalechosen)--;
5163 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5167 /* check whether any of the operands still has significant digits
5168 (underflow case 1)
5170 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5171 underflow = 1;
5172 } else {
5173 /* at this step, both numbers have the same scale and can be added
5174 as integers. However, the result might not fit in A, so further
5175 scaling down might be necessary.
5177 while (!underflow) {
5178 memset(t, 0, tn * sizeof(DWORD));
5179 memcpy(t, a, an * sizeof(DWORD));
5181 VARIANT_int_add(t, tn, b, bn);
5182 if (VARIANT_int_iszero(t + an, tn - an)) {
5183 /* addition was successful */
5184 memcpy(a, t, an * sizeof(DWORD));
5185 break;
5186 } else {
5187 /* addition overflowed - remove significant digits
5188 from both operands and try again */
5189 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5190 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5191 /* check whether any operand keeps significant digits after
5192 scaledown (underflow case 2)
5194 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5199 return underflow;
5202 /* perform complete DECIMAL division in the internal representation. Returns
5203 0 if the division was completed (even if quotient is set to 0), or nonzero
5204 in case of quotient overflow.
5206 static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * divisor,
5207 VARIANT_DI * quotient, BOOL round_remainder)
5209 HRESULT r_overflow = S_OK;
5211 if (VARIANT_int_iszero(divisor->bitsnum, ARRAY_SIZE(divisor->bitsnum))) {
5212 /* division by 0 */
5213 r_overflow = DISP_E_DIVBYZERO;
5214 } else if (VARIANT_int_iszero(dividend->bitsnum, ARRAY_SIZE(dividend->bitsnum))) {
5215 VARIANT_DI_clear(quotient);
5216 } else {
5217 int quotientscale, remainderscale, tempquotientscale;
5218 DWORD remainderplusquotient[8];
5219 int underflow;
5221 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5222 tempquotientscale = quotientscale;
5223 VARIANT_DI_clear(quotient);
5224 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5226 /* The following strategy is used for division
5227 1) if there was a nonzero remainder from previous iteration, use it as
5228 dividend for this iteration, else (for first iteration) use intended
5229 dividend
5230 2) perform integer division in temporary buffer, develop quotient in
5231 low-order part, remainder in high-order part
5232 3) add quotient from step 2 to final result, with possible loss of
5233 significant digits
5234 4) multiply integer part of remainder by 10, while incrementing the
5235 scale of the remainder. This operation preserves the intended value
5236 of the remainder.
5237 5) loop to step 1 until one of the following is true:
5238 a) remainder is zero (exact division achieved)
5239 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5241 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5242 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5243 do {
5244 VARIANT_int_div(remainderplusquotient, 4, divisor->bitsnum, ARRAY_SIZE(divisor->bitsnum));
5245 underflow = VARIANT_int_addlossy( quotient->bitsnum, &quotientscale,
5246 ARRAY_SIZE(quotient->bitsnum), remainderplusquotient, &tempquotientscale, 4);
5247 if (round_remainder) {
5248 if(remainderplusquotient[4] >= 5){
5249 unsigned int i;
5250 unsigned char remainder = 1;
5251 for (i = 0; i < ARRAY_SIZE(quotient->bitsnum) && remainder; i++) {
5252 ULONGLONG digit = quotient->bitsnum[i] + 1;
5253 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5254 quotient->bitsnum[i] = digit & 0xFFFFFFFF;
5257 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5258 } else {
5259 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5260 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5262 tempquotientscale = ++remainderscale;
5263 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5265 /* quotient scale might now be negative (extremely big number). If, so, try
5266 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5267 until scale is 0. If this cannot be done, it is a real overflow.
5269 while (r_overflow == S_OK && quotientscale < 0) {
5270 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5271 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5272 VARIANT_int_mulbychar(remainderplusquotient, ARRAY_SIZE(remainderplusquotient), 10);
5273 if (VARIANT_int_iszero(remainderplusquotient + ARRAY_SIZE(quotient->bitsnum),
5274 ARRAY_SIZE(remainderplusquotient) - ARRAY_SIZE(quotient->bitsnum))) {
5275 quotientscale++;
5276 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5277 } else r_overflow = DISP_E_OVERFLOW;
5279 if (r_overflow == S_OK) {
5280 if (quotientscale <= 255) quotient->scale = quotientscale;
5281 else VARIANT_DI_clear(quotient);
5284 return r_overflow;
5287 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5288 with an undefined scale, which will be assigned to (if possible). It also
5289 receives an exponent of 2. This procedure will then manipulate the mantissa
5290 and calculate a corresponding scale, so that the exponent2 value is assimilated
5291 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5292 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5293 a DECIMAL. */
5294 static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, BOOL isDouble)
5296 HRESULT hres = S_OK;
5297 int exponent5, exponent10;
5299 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5300 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5301 exponent10 might be used to set the VARIANT_DI scale directly. However,
5302 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5303 exponent5 = -exponent2;
5304 exponent10 = exponent2;
5306 /* Handle exponent5 > 0 */
5307 while (exponent5 > 0) {
5308 char bPrevCarryBit;
5309 char bCurrCarryBit;
5311 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5312 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5313 somehow the mantissa should be divided by 2. */
5314 if ((val->bitsnum[0] & 1) == 0) {
5315 /* The mantissa is divisible by 2. Therefore the division can be done
5316 without losing significant digits. */
5317 exponent10++; exponent5--;
5319 /* Shift right */
5320 bPrevCarryBit = val->bitsnum[2] & 1;
5321 val->bitsnum[2] >>= 1;
5322 bCurrCarryBit = val->bitsnum[1] & 1;
5323 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5324 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5325 } else {
5326 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5327 be multiplied by 5, unless the multiplication overflows. */
5328 DWORD temp_bitsnum[3];
5330 exponent5--;
5332 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5333 if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) {
5334 /* Multiplication succeeded without overflow, so copy result back
5335 into VARIANT_DI */
5336 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5338 /* Mask out 3 extraneous bits introduced by the multiply */
5339 } else {
5340 /* Multiplication by 5 overflows. The mantissa should be divided
5341 by 2, and therefore will lose significant digits. */
5342 exponent10++;
5344 /* Shift right */
5345 bPrevCarryBit = val->bitsnum[2] & 1;
5346 val->bitsnum[2] >>= 1;
5347 bCurrCarryBit = val->bitsnum[1] & 1;
5348 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5349 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5354 /* Handle exponent5 < 0 */
5355 while (exponent5 < 0) {
5356 /* In order to divide the value represented by the VARIANT_DI by 5, it
5357 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5358 and the mantissa should be multiplied by 2 */
5359 if ((val->bitsnum[2] & 0x80000000) == 0) {
5360 /* The mantissa can withstand a shift-left without overflowing */
5361 exponent10--; exponent5++;
5362 VARIANT_int_shiftleft(val->bitsnum, 3, 1);
5363 } else {
5364 /* The mantissa would overflow if shifted. Therefore it should be
5365 directly divided by 5. This will lose significant digits, unless
5366 by chance the mantissa happens to be divisible by 5 */
5367 exponent5++;
5368 VARIANT_int_divbychar(val->bitsnum, 3, 5);
5372 /* At this point, the mantissa has assimilated the exponent5, but the
5373 exponent10 might not be suitable for assignment. The exponent10 must be
5374 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5375 down appropriately. */
5376 while (hres == S_OK && exponent10 > 0) {
5377 /* In order to bring exponent10 down to 0, the mantissa should be
5378 multiplied by 10 to compensate. If the exponent10 is too big, this
5379 will cause the mantissa to overflow. */
5380 if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) {
5381 exponent10--;
5382 } else {
5383 hres = DISP_E_OVERFLOW;
5386 while (exponent10 < -DEC_MAX_SCALE) {
5387 int rem10;
5388 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5389 be divided by 10 to compensate. If the exponent10 is too small, this
5390 will cause the mantissa to underflow and become 0 */
5391 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5392 exponent10++;
5393 if (VARIANT_int_iszero(val->bitsnum, 3)) {
5394 /* Underflow, unable to keep dividing */
5395 exponent10 = 0;
5396 } else if (rem10 >= 5) {
5397 DWORD x = 1;
5398 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5401 /* This step is required in order to remove excess bits of precision from the
5402 end of the bit representation, down to the precision guaranteed by the
5403 floating point number. */
5404 if (isDouble) {
5405 while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[1] & 0xFFE00000) != 0)) {
5406 int rem10;
5408 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5409 exponent10++;
5410 if (rem10 >= 5) {
5411 DWORD x = 1;
5412 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5415 } else {
5416 while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 ||
5417 (val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) {
5418 int rem10;
5420 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5421 exponent10++;
5422 if (rem10 >= 5) {
5423 DWORD x = 1;
5424 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5428 /* Remove multiples of 10 from the representation */
5429 while (exponent10 < 0) {
5430 DWORD temp_bitsnum[3];
5432 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5433 if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) {
5434 exponent10++;
5435 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5436 } else break;
5439 /* Scale assignment */
5440 if (hres == S_OK) val->scale = -exponent10;
5442 return hres;
5445 typedef union
5447 struct
5449 unsigned int m : 23;
5450 unsigned int exp_bias : 8;
5451 unsigned int sign : 1;
5452 } i;
5453 float f;
5454 } R4_FIELDS;
5456 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5457 intermediate string step. */
5458 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest)
5460 HRESULT hres = S_OK;
5461 R4_FIELDS fx;
5463 fx.f = source;
5465 /* Detect special cases */
5466 if (fx.i.m == 0 && fx.i.exp_bias == 0) {
5467 /* Floating-point zero */
5468 VARIANT_DI_clear(dest);
5469 } else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) {
5470 /* Floating-point infinity */
5471 hres = DISP_E_OVERFLOW;
5472 } else if (fx.i.exp_bias == 0xFF) {
5473 /* Floating-point NaN */
5474 hres = DISP_E_BADVARTYPE;
5475 } else {
5476 int exponent2;
5477 VARIANT_DI_clear(dest);
5479 exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */
5480 dest->sign = fx.i.sign; /* Sign is simply copied */
5482 /* Copy significant bits to VARIANT_DI mantissa */
5483 dest->bitsnum[0] = fx.i.m;
5484 dest->bitsnum[0] &= 0x007FFFFF;
5485 if (fx.i.exp_bias == 0) {
5486 /* Denormalized number - correct exponent */
5487 exponent2++;
5488 } else {
5489 /* Add hidden bit to mantissa */
5490 dest->bitsnum[0] |= 0x00800000;
5493 /* The act of copying a FP mantissa as integer bits is equivalent to
5494 shifting left the mantissa 23 bits. The exponent2 is reduced to
5495 compensate. */
5496 exponent2 -= 23;
5498 hres = VARIANT_DI_normalize(dest, exponent2, FALSE);
5501 return hres;
5504 typedef union
5506 struct
5508 unsigned int m_lo : 32; /* 52 bits of precision */
5509 unsigned int m_hi : 20;
5510 unsigned int exp_bias : 11; /* bias == 1023 */
5511 unsigned int sign : 1;
5512 } i;
5513 double d;
5514 } R8_FIELDS;
5516 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5517 intermediate string step. */
5518 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest)
5520 HRESULT hres = S_OK;
5521 R8_FIELDS fx;
5523 fx.d = source;
5525 /* Detect special cases */
5526 if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) {
5527 /* Floating-point zero */
5528 VARIANT_DI_clear(dest);
5529 } else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) {
5530 /* Floating-point infinity */
5531 hres = DISP_E_OVERFLOW;
5532 } else if (fx.i.exp_bias == 0x7FF) {
5533 /* Floating-point NaN */
5534 hres = DISP_E_BADVARTYPE;
5535 } else {
5536 int exponent2;
5537 VARIANT_DI_clear(dest);
5539 exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */
5540 dest->sign = fx.i.sign; /* Sign is simply copied */
5542 /* Copy significant bits to VARIANT_DI mantissa */
5543 dest->bitsnum[0] = fx.i.m_lo;
5544 dest->bitsnum[1] = fx.i.m_hi;
5545 dest->bitsnum[1] &= 0x000FFFFF;
5546 if (fx.i.exp_bias == 0) {
5547 /* Denormalized number - correct exponent */
5548 exponent2++;
5549 } else {
5550 /* Add hidden bit to mantissa */
5551 dest->bitsnum[1] |= 0x00100000;
5554 /* The act of copying a FP mantissa as integer bits is equivalent to
5555 shifting left the mantissa 52 bits. The exponent2 is reduced to
5556 compensate. */
5557 exponent2 -= 52;
5559 hres = VARIANT_DI_normalize(dest, exponent2, TRUE);
5562 return hres;
5565 static HRESULT VARIANT_do_division(const DECIMAL *pDecLeft, const DECIMAL *pDecRight, DECIMAL *pDecOut,
5566 BOOL round)
5568 HRESULT hRet = S_OK;
5569 VARIANT_DI di_left, di_right, di_result;
5570 HRESULT divresult;
5572 VARIANT_DIFromDec(pDecLeft, &di_left);
5573 VARIANT_DIFromDec(pDecRight, &di_right);
5574 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result, round);
5575 if (divresult != S_OK)
5577 /* division actually overflowed */
5578 hRet = divresult;
5580 else
5582 hRet = S_OK;
5584 if (di_result.scale > DEC_MAX_SCALE)
5586 unsigned char remainder = 0;
5588 /* division underflowed. In order to comply with the MSDN
5589 specifications for DECIMAL ranges, some significant digits
5590 must be removed
5592 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5593 di_result.scale);
5594 while (di_result.scale > DEC_MAX_SCALE &&
5595 !VARIANT_int_iszero(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum)))
5597 remainder = VARIANT_int_divbychar(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum), 10);
5598 di_result.scale--;
5600 if (di_result.scale > DEC_MAX_SCALE)
5602 WARN("result underflowed, setting to 0\n");
5603 di_result.scale = 0;
5604 di_result.sign = 0;
5606 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5608 unsigned int i;
5609 for (remainder = 1, i = 0; i < ARRAY_SIZE(di_result.bitsnum) && remainder; i++) {
5610 ULONGLONG digit = di_result.bitsnum[i] + 1;
5611 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5612 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5616 VARIANT_DecFromDI(&di_result, pDecOut);
5618 return hRet;
5621 /************************************************************************
5622 * VarDecDiv (OLEAUT32.178)
5624 * Divide one DECIMAL by another.
5626 * PARAMS
5627 * pDecLeft [I] Source
5628 * pDecRight [I] Value to divide by
5629 * pDecOut [O] Destination
5631 * RETURNS
5632 * Success: S_OK.
5633 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5635 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5637 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5639 return VARIANT_do_division(pDecLeft, pDecRight, pDecOut, FALSE);
5642 /************************************************************************
5643 * VarDecMul (OLEAUT32.179)
5645 * Multiply one DECIMAL by another.
5647 * PARAMS
5648 * pDecLeft [I] Source
5649 * pDecRight [I] Value to multiply by
5650 * pDecOut [O] Destination
5652 * RETURNS
5653 * Success: S_OK.
5654 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5656 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5658 HRESULT hRet = S_OK;
5659 VARIANT_DI di_left, di_right, di_result;
5660 int mulresult;
5662 VARIANT_DIFromDec(pDecLeft, &di_left);
5663 VARIANT_DIFromDec(pDecRight, &di_right);
5664 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5665 if (mulresult)
5667 /* multiplication actually overflowed */
5668 hRet = DISP_E_OVERFLOW;
5670 else
5672 if (di_result.scale > DEC_MAX_SCALE)
5674 /* multiplication underflowed. In order to comply with the MSDN
5675 specifications for DECIMAL ranges, some significant digits
5676 must be removed
5678 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5679 di_result.scale);
5680 while (di_result.scale > DEC_MAX_SCALE &&
5681 !VARIANT_int_iszero(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum)))
5683 VARIANT_int_divbychar(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum), 10);
5684 di_result.scale--;
5686 if (di_result.scale > DEC_MAX_SCALE)
5688 WARN("result underflowed, setting to 0\n");
5689 di_result.scale = 0;
5690 di_result.sign = 0;
5693 VARIANT_DecFromDI(&di_result, pDecOut);
5695 return hRet;
5698 /************************************************************************
5699 * VarDecSub (OLEAUT32.181)
5701 * Subtract one DECIMAL from another.
5703 * PARAMS
5704 * pDecLeft [I] Source
5705 * pDecRight [I] DECIMAL to subtract from pDecLeft
5706 * pDecOut [O] Destination
5708 * RETURNS
5709 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5711 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5713 DECIMAL decRight;
5715 /* Implement as addition of the negative */
5716 VarDecNeg(pDecRight, &decRight);
5717 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5720 /************************************************************************
5721 * VarDecAbs (OLEAUT32.182)
5723 * Convert a DECIMAL into its absolute value.
5725 * PARAMS
5726 * pDecIn [I] Source
5727 * pDecOut [O] Destination
5729 * RETURNS
5730 * S_OK. This function does not fail.
5732 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5734 *pDecOut = *pDecIn;
5735 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5736 return S_OK;
5739 /************************************************************************
5740 * VarDecFix (OLEAUT32.187)
5742 * Return the integer portion of a DECIMAL.
5744 * PARAMS
5745 * pDecIn [I] Source
5746 * pDecOut [O] Destination
5748 * RETURNS
5749 * Success: S_OK.
5750 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5752 * NOTES
5753 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5754 * negative numbers away from 0, while this function rounds them towards zero.
5756 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5758 double dbl;
5759 HRESULT hr;
5761 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5762 return E_INVALIDARG;
5764 if (!DEC_SCALE(pDecIn))
5766 *pDecOut = *pDecIn; /* Already an integer */
5767 return S_OK;
5770 hr = VarR8FromDec(pDecIn, &dbl);
5771 if (SUCCEEDED(hr)) {
5772 LONGLONG rounded = dbl;
5774 hr = VarDecFromI8(rounded, pDecOut);
5776 return hr;
5779 /************************************************************************
5780 * VarDecInt (OLEAUT32.188)
5782 * Return the integer portion of a DECIMAL.
5784 * PARAMS
5785 * pDecIn [I] Source
5786 * pDecOut [O] Destination
5788 * RETURNS
5789 * Success: S_OK.
5790 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5792 * NOTES
5793 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5794 * negative numbers towards 0, while this function rounds them away from zero.
5796 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5798 double dbl;
5799 HRESULT hr;
5801 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5802 return E_INVALIDARG;
5804 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5805 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5807 hr = VarR8FromDec(pDecIn, &dbl);
5808 if (SUCCEEDED(hr)) {
5809 LONGLONG rounded = dbl >= 0.0 ? dbl + 0.5 : dbl - 0.5;
5811 hr = VarDecFromI8(rounded, pDecOut);
5813 return hr;
5816 /************************************************************************
5817 * VarDecNeg (OLEAUT32.189)
5819 * Change the sign of a DECIMAL.
5821 * PARAMS
5822 * pDecIn [I] Source
5823 * pDecOut [O] Destination
5825 * RETURNS
5826 * S_OK. This function does not fail.
5828 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5830 *pDecOut = *pDecIn;
5831 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5832 return S_OK;
5835 /************************************************************************
5836 * VarDecRound (OLEAUT32.203)
5838 * Change the precision of a DECIMAL.
5840 * PARAMS
5841 * pDecIn [I] Source
5842 * cDecimals [I] New number of decimals to keep
5843 * pDecOut [O] Destination
5845 * RETURNS
5846 * Success: S_OK. pDecOut contains the rounded value.
5847 * Failure: E_INVALIDARG if any argument is invalid.
5849 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5851 DECIMAL divisor, tmp;
5852 HRESULT hr;
5853 unsigned int i;
5855 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5856 return E_INVALIDARG;
5858 if (cDecimals >= DEC_SCALE(pDecIn))
5860 *pDecOut = *pDecIn; /* More precision than we have */
5861 return S_OK;
5864 /* truncate significant digits and rescale */
5865 memset(&divisor, 0, sizeof(divisor));
5866 DEC_LO64(&divisor) = 1;
5868 memset(&tmp, 0, sizeof(tmp));
5869 DEC_LO64(&tmp) = 10;
5870 for (i = 0; i < DEC_SCALE(pDecIn) - cDecimals; ++i)
5872 hr = VarDecMul(&divisor, &tmp, &divisor);
5873 if (FAILED(hr))
5874 return hr;
5877 hr = VARIANT_do_division(pDecIn, &divisor, pDecOut, TRUE);
5878 if (FAILED(hr))
5879 return hr;
5881 DEC_SCALE(pDecOut) = cDecimals;
5883 return S_OK;
5886 /************************************************************************
5887 * VarDecCmp (OLEAUT32.204)
5889 * Compare two DECIMAL values.
5891 * PARAMS
5892 * pDecLeft [I] Source
5893 * pDecRight [I] Value to compare
5895 * RETURNS
5896 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5897 * is less than, equal to or greater than pDecRight respectively.
5898 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5900 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5902 HRESULT hRet;
5903 DECIMAL result;
5905 if (!pDecLeft || !pDecRight)
5906 return VARCMP_NULL;
5908 if ((!(DEC_SIGN(pDecLeft) & DECIMAL_NEG)) && (DEC_SIGN(pDecRight) & DECIMAL_NEG) &&
5909 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5910 return VARCMP_GT;
5911 else if ((DEC_SIGN(pDecLeft) & DECIMAL_NEG) && (!(DEC_SIGN(pDecRight) & DECIMAL_NEG)) &&
5912 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5913 return VARCMP_LT;
5915 /* Subtract right from left, and compare the result to 0 */
5916 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5918 if (SUCCEEDED(hRet))
5920 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5922 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5923 hRet = (HRESULT)VARCMP_LT;
5924 else if (non_zero)
5925 hRet = (HRESULT)VARCMP_GT;
5926 else
5927 hRet = (HRESULT)VARCMP_EQ;
5929 return hRet;
5932 /************************************************************************
5933 * VarDecCmpR8 (OLEAUT32.298)
5935 * Compare a DECIMAL to a double
5937 * PARAMS
5938 * pDecLeft [I] DECIMAL Source
5939 * dblRight [I] double to compare to pDecLeft
5941 * RETURNS
5942 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5943 * is less than, equal to or greater than pDecLeft respectively.
5944 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5946 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5948 HRESULT hRet;
5949 DECIMAL decRight;
5951 hRet = VarDecFromR8(dblRight, &decRight);
5953 if (SUCCEEDED(hRet))
5954 hRet = VarDecCmp(pDecLeft, &decRight);
5956 return hRet;
5959 /* BOOL
5962 /************************************************************************
5963 * VarBoolFromUI1 (OLEAUT32.118)
5965 * Convert a VT_UI1 to a VT_BOOL.
5967 * PARAMS
5968 * bIn [I] Source
5969 * pBoolOut [O] Destination
5971 * RETURNS
5972 * S_OK.
5974 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5976 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5977 return S_OK;
5980 /************************************************************************
5981 * VarBoolFromI2 (OLEAUT32.119)
5983 * Convert a VT_I2 to a VT_BOOL.
5985 * PARAMS
5986 * sIn [I] Source
5987 * pBoolOut [O] Destination
5989 * RETURNS
5990 * S_OK.
5992 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5994 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5995 return S_OK;
5998 /************************************************************************
5999 * VarBoolFromI4 (OLEAUT32.120)
6001 * Convert a VT_I4 to a VT_BOOL.
6003 * PARAMS
6004 * sIn [I] Source
6005 * pBoolOut [O] Destination
6007 * RETURNS
6008 * S_OK.
6010 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
6012 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
6013 return S_OK;
6016 /************************************************************************
6017 * VarBoolFromR4 (OLEAUT32.121)
6019 * Convert a VT_R4 to a VT_BOOL.
6021 * PARAMS
6022 * fltIn [I] Source
6023 * pBoolOut [O] Destination
6025 * RETURNS
6026 * S_OK.
6028 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
6030 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
6031 return S_OK;
6034 /************************************************************************
6035 * VarBoolFromR8 (OLEAUT32.122)
6037 * Convert a VT_R8 to a VT_BOOL.
6039 * PARAMS
6040 * dblIn [I] Source
6041 * pBoolOut [O] Destination
6043 * RETURNS
6044 * S_OK.
6046 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
6048 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
6049 return S_OK;
6052 /************************************************************************
6053 * VarBoolFromDate (OLEAUT32.123)
6055 * Convert a VT_DATE to a VT_BOOL.
6057 * PARAMS
6058 * dateIn [I] Source
6059 * pBoolOut [O] Destination
6061 * RETURNS
6062 * S_OK.
6064 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
6066 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
6067 return S_OK;
6070 /************************************************************************
6071 * VarBoolFromCy (OLEAUT32.124)
6073 * Convert a VT_CY to a VT_BOOL.
6075 * PARAMS
6076 * cyIn [I] Source
6077 * pBoolOut [O] Destination
6079 * RETURNS
6080 * S_OK.
6082 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
6084 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
6085 return S_OK;
6088 /************************************************************************
6089 * VARIANT_GetLocalisedText [internal]
6091 * Get a localized string from the resources
6094 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
6096 HRSRC hrsrc;
6098 hrsrc = FindResourceExW( hProxyDll, (LPWSTR)RT_STRING,
6099 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
6100 if (hrsrc)
6102 HGLOBAL hmem = LoadResource( hProxyDll, hrsrc );
6104 if (hmem)
6106 const WCHAR *p;
6107 unsigned int i;
6109 p = LockResource( hmem );
6110 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
6112 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
6113 lpszDest[*p] = '\0';
6114 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
6115 return TRUE;
6118 return FALSE;
6121 /************************************************************************
6122 * VarBoolFromStr (OLEAUT32.125)
6124 * Convert a VT_BSTR to a VT_BOOL.
6126 * PARAMS
6127 * strIn [I] Source
6128 * lcid [I] LCID for the conversion
6129 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6130 * pBoolOut [O] Destination
6132 * RETURNS
6133 * Success: S_OK.
6134 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6135 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6137 * NOTES
6138 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6139 * it may contain (in any case mapping) the text "true" or "false".
6140 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6141 * localised text of "True" or "False" in the language specified by lcid.
6142 * - If none of these matches occur, the string is treated as a numeric string
6143 * and the boolean pBoolOut will be set according to whether the number is zero
6144 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6145 * - If the text is not numeric and does not match any of the above, then
6146 * DISP_E_TYPEMISMATCH is returned.
6148 HRESULT WINAPI VarBoolFromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
6150 WCHAR szBuff[64];
6151 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6152 HRESULT hRes = S_OK;
6154 if (!strIn || !pBoolOut)
6155 return DISP_E_TYPEMISMATCH;
6157 /* Check if we should be comparing against localised text */
6158 if (dwFlags & VAR_LOCALBOOL)
6160 /* Convert our LCID into a usable value */
6161 lcid = ConvertDefaultLocale(lcid);
6163 langId = LANGIDFROMLCID(lcid);
6165 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6166 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6168 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6169 * I don't think this is needed unless any of the localised text strings
6170 * contain characters that can be so mapped. In the event that this is
6171 * true for a given language (possibly some Asian languages), then strIn
6172 * should be mapped here _only_ if langId is an Id for which this can occur.
6176 /* Note that if we are not comparing against localised strings, langId
6177 * will have its default value of LANG_ENGLISH. This allows us to mimic
6178 * the native behaviour of always checking against English strings even
6179 * after we've checked for localised ones.
6181 VarBoolFromStr_CheckLocalised:
6182 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
6184 /* Compare against localised strings, ignoring case */
6185 if (!wcsicmp(strIn, szBuff))
6187 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
6188 return hRes;
6190 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
6191 if (!wcsicmp(strIn, szBuff))
6193 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
6194 return hRes;
6198 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6200 /* We have checked the localised text, now check English */
6201 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6202 goto VarBoolFromStr_CheckLocalised;
6205 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6206 if (!wcscmp(strIn, L"#FALSE#"))
6207 *pBoolOut = VARIANT_FALSE;
6208 else if (!wcscmp(strIn, L"#TRUE#"))
6209 *pBoolOut = VARIANT_TRUE;
6210 else
6212 double d;
6214 /* If this string is a number, convert it as one */
6215 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
6216 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
6218 return hRes;
6221 /************************************************************************
6222 * VarBoolFromDisp (OLEAUT32.126)
6224 * Convert a VT_DISPATCH to a VT_BOOL.
6226 * PARAMS
6227 * pdispIn [I] Source
6228 * lcid [I] LCID for conversion
6229 * pBoolOut [O] Destination
6231 * RETURNS
6232 * Success: S_OK.
6233 * Failure: E_INVALIDARG, if the source value is invalid
6234 * DISP_E_OVERFLOW, if the value will not fit in the destination
6235 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6237 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
6239 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
6242 /************************************************************************
6243 * VarBoolFromI1 (OLEAUT32.233)
6245 * Convert a VT_I1 to a VT_BOOL.
6247 * PARAMS
6248 * cIn [I] Source
6249 * pBoolOut [O] Destination
6251 * RETURNS
6252 * S_OK.
6254 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
6256 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
6257 return S_OK;
6260 /************************************************************************
6261 * VarBoolFromUI2 (OLEAUT32.234)
6263 * Convert a VT_UI2 to a VT_BOOL.
6265 * PARAMS
6266 * usIn [I] Source
6267 * pBoolOut [O] Destination
6269 * RETURNS
6270 * S_OK.
6272 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
6274 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
6275 return S_OK;
6278 /************************************************************************
6279 * VarBoolFromUI4 (OLEAUT32.235)
6281 * Convert a VT_UI4 to a VT_BOOL.
6283 * PARAMS
6284 * ulIn [I] Source
6285 * pBoolOut [O] Destination
6287 * RETURNS
6288 * S_OK.
6290 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
6292 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
6293 return S_OK;
6296 /************************************************************************
6297 * VarBoolFromDec (OLEAUT32.236)
6299 * Convert a VT_DECIMAL to a VT_BOOL.
6301 * PARAMS
6302 * pDecIn [I] Source
6303 * pBoolOut [O] Destination
6305 * RETURNS
6306 * Success: S_OK.
6307 * Failure: E_INVALIDARG, if pDecIn is invalid.
6309 HRESULT WINAPI VarBoolFromDec(const DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
6311 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
6312 return E_INVALIDARG;
6314 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
6315 *pBoolOut = VARIANT_TRUE;
6316 else
6317 *pBoolOut = VARIANT_FALSE;
6318 return S_OK;
6321 /************************************************************************
6322 * VarBoolFromI8 (OLEAUT32.370)
6324 * Convert a VT_I8 to a VT_BOOL.
6326 * PARAMS
6327 * ullIn [I] Source
6328 * pBoolOut [O] Destination
6330 * RETURNS
6331 * S_OK.
6333 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
6335 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
6336 return S_OK;
6339 /************************************************************************
6340 * VarBoolFromUI8 (OLEAUT32.371)
6342 * Convert a VT_UI8 to a VT_BOOL.
6344 * PARAMS
6345 * ullIn [I] Source
6346 * pBoolOut [O] Destination
6348 * RETURNS
6349 * S_OK.
6351 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
6353 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
6354 return S_OK;
6357 /* BSTR
6360 /* Write a number from a UI8 and sign */
6361 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
6365 WCHAR ulNextDigit = ulVal % 10;
6367 *szOut-- = '0' + ulNextDigit;
6368 ulVal = (ulVal - ulNextDigit) / 10;
6369 } while (ulVal);
6371 szOut++;
6372 return szOut;
6375 /* Create a (possibly localised) BSTR from a UI8 and sign */
6376 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
6378 WCHAR szConverted[256];
6380 if (dwFlags & VAR_NEGATIVE)
6381 *--szOut = '-';
6383 if (dwFlags & LOCALE_USE_NLS)
6385 /* Format the number for the locale */
6386 szConverted[0] = '\0';
6387 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6388 szOut, NULL, szConverted, ARRAY_SIZE(szConverted));
6389 szOut = szConverted;
6391 return SysAllocStringByteLen((LPCSTR)szOut, lstrlenW(szOut) * sizeof(WCHAR));
6394 /* Create a (possibly localised) BSTR from a UI8 and sign */
6395 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
6397 WCHAR szBuff[64], *szOut = szBuff + ARRAY_SIZE(szBuff) - 1;
6399 if (!pbstrOut)
6400 return E_INVALIDARG;
6402 /* Create the basic number string */
6403 *szOut-- = '\0';
6404 szOut = VARIANT_WriteNumber(ulVal, szOut);
6406 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
6407 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6408 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6411 /******************************************************************************
6412 * VarBstrFromUI1 (OLEAUT32.108)
6414 * Convert a VT_UI1 to a VT_BSTR.
6416 * PARAMS
6417 * bIn [I] Source
6418 * lcid [I] LCID for the conversion
6419 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6420 * pbstrOut [O] Destination
6422 * RETURNS
6423 * Success: S_OK.
6424 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6425 * E_OUTOFMEMORY, if memory allocation fails.
6427 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6429 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6432 /******************************************************************************
6433 * VarBstrFromI2 (OLEAUT32.109)
6435 * Convert a VT_I2 to a VT_BSTR.
6437 * PARAMS
6438 * sIn [I] Source
6439 * lcid [I] LCID for the conversion
6440 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6441 * pbstrOut [O] Destination
6443 * RETURNS
6444 * Success: S_OK.
6445 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6446 * E_OUTOFMEMORY, if memory allocation fails.
6448 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6450 ULONG64 ul64 = sIn;
6452 if (sIn < 0)
6454 ul64 = -sIn;
6455 dwFlags |= VAR_NEGATIVE;
6457 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6460 /******************************************************************************
6461 * VarBstrFromI4 (OLEAUT32.110)
6463 * Convert a VT_I4 to a VT_BSTR.
6465 * PARAMS
6466 * lIn [I] Source
6467 * lcid [I] LCID for the conversion
6468 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6469 * pbstrOut [O] Destination
6471 * RETURNS
6472 * Success: S_OK.
6473 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6474 * E_OUTOFMEMORY, if memory allocation fails.
6476 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6478 ULONG64 ul64 = lIn;
6480 if (lIn < 0)
6482 ul64 = -(LONG64)lIn;
6483 dwFlags |= VAR_NEGATIVE;
6485 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6488 static BSTR VARIANT_BstrReplaceDecimal(const WCHAR * buff, LCID lcid, ULONG dwFlags)
6490 BSTR bstrOut;
6491 WCHAR lpDecimalSep[16];
6493 /* Native oleaut32 uses the locale-specific decimal separator even in the
6494 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6495 American locales will see "one thousand and one tenth" as "1000,1"
6496 instead of "1000.1" (notice the comma). The following code checks for
6497 the need to replace the decimal separator, and if so, will prepare an
6498 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6500 GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE),
6501 lpDecimalSep, ARRAY_SIZE(lpDecimalSep));
6502 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6504 /* locale is compatible with English - return original string */
6505 bstrOut = SysAllocString(buff);
6507 else
6509 WCHAR *p;
6510 WCHAR numbuff[256];
6511 WCHAR empty[] = L"";
6512 NUMBERFMTW minFormat;
6514 minFormat.NumDigits = 0;
6515 minFormat.Grouping = 0;
6516 minFormat.lpDecimalSep = lpDecimalSep;
6517 minFormat.lpThousandSep = empty;
6518 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6520 GetLocaleInfoW(lcid, LOCALE_ILZERO | LOCALE_RETURN_NUMBER | (dwFlags & LOCALE_NOUSEROVERRIDE),
6521 (WCHAR *)&minFormat.LeadingZero, sizeof(DWORD)/sizeof(WCHAR) );
6523 /* count number of decimal digits in string */
6524 p = wcschr( buff, '.' );
6525 if (p) minFormat.NumDigits = lstrlenW(p + 1);
6527 numbuff[0] = '\0';
6528 if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, ARRAY_SIZE(numbuff)))
6530 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6531 bstrOut = SysAllocString(buff);
6533 else
6535 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6536 bstrOut = SysAllocString(numbuff);
6539 return bstrOut;
6542 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6543 BSTR* pbstrOut, LPCWSTR lpszFormat)
6545 _locale_t locale;
6546 WCHAR buff[256];
6548 if (!pbstrOut)
6549 return E_INVALIDARG;
6551 if (!(locale = _create_locale(LC_ALL, "C"))) return E_OUTOFMEMORY;
6552 _swprintf_l(buff, ARRAY_SIZE(buff), lpszFormat, locale, dblIn);
6553 _free_locale(locale);
6555 /* Negative zeroes are disallowed (some applications depend on this).
6556 If buff starts with a minus, and then nothing follows but zeroes
6557 and/or a period, it is a negative zero and is replaced with a
6558 canonical zero. This duplicates native oleaut32 behavior.
6560 if (buff[0] == '-')
6562 if (lstrlenW(buff + 1) == wcsspn(buff + 1, L"0."))
6563 { buff[0] = '0'; buff[1] = '\0'; }
6566 TRACE("created string %s\n", debugstr_w(buff));
6567 if (dwFlags & LOCALE_USE_NLS)
6569 WCHAR numbuff[256];
6571 /* Format the number for the locale */
6572 numbuff[0] = '\0';
6573 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6574 buff, NULL, numbuff, ARRAY_SIZE(numbuff));
6575 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6576 *pbstrOut = SysAllocString(numbuff);
6578 else
6580 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6582 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6585 /******************************************************************************
6586 * VarBstrFromR4 (OLEAUT32.111)
6588 * Convert a VT_R4 to a VT_BSTR.
6590 * PARAMS
6591 * fltIn [I] Source
6592 * lcid [I] LCID for the conversion
6593 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6594 * pbstrOut [O] Destination
6596 * RETURNS
6597 * Success: S_OK.
6598 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6599 * E_OUTOFMEMORY, if memory allocation fails.
6601 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6603 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, L"%.7G");
6606 /******************************************************************************
6607 * VarBstrFromR8 (OLEAUT32.112)
6609 * Convert a VT_R8 to a VT_BSTR.
6611 * PARAMS
6612 * dblIn [I] Source
6613 * lcid [I] LCID for the conversion
6614 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6615 * pbstrOut [O] Destination
6617 * RETURNS
6618 * Success: S_OK.
6619 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6620 * E_OUTOFMEMORY, if memory allocation fails.
6622 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6624 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, L"%.15G");
6627 /******************************************************************************
6628 * VarBstrFromCy [OLEAUT32.113]
6630 * Convert a VT_CY to a VT_BSTR.
6632 * PARAMS
6633 * cyIn [I] Source
6634 * lcid [I] LCID for the conversion
6635 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6636 * pbstrOut [O] Destination
6638 * RETURNS
6639 * Success: S_OK.
6640 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6641 * E_OUTOFMEMORY, if memory allocation fails.
6643 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6645 WCHAR buff[256];
6646 VARIANT_DI decVal;
6648 if (!pbstrOut)
6649 return E_INVALIDARG;
6651 decVal.scale = 4;
6652 decVal.sign = 0;
6653 decVal.bitsnum[0] = cyIn.s.Lo;
6654 decVal.bitsnum[1] = cyIn.s.Hi;
6655 if (cyIn.s.Hi & 0x80000000UL) {
6656 DWORD one = 1;
6658 /* Negative number! */
6659 decVal.sign = 1;
6660 decVal.bitsnum[0] = ~decVal.bitsnum[0];
6661 decVal.bitsnum[1] = ~decVal.bitsnum[1];
6662 VARIANT_int_add(decVal.bitsnum, 3, &one, 1);
6664 decVal.bitsnum[2] = 0;
6665 VARIANT_DI_tostringW(&decVal, buff, ARRAY_SIZE(buff));
6667 if (dwFlags & LOCALE_USE_NLS)
6669 WCHAR cybuff[256];
6671 /* Format the currency for the locale */
6672 cybuff[0] = '\0';
6673 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6674 buff, NULL, cybuff, ARRAY_SIZE(cybuff));
6675 *pbstrOut = SysAllocString(cybuff);
6677 else
6678 *pbstrOut = VARIANT_BstrReplaceDecimal(buff,lcid,dwFlags);
6680 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6683 static inline int output_int_len(int o, int min_len, WCHAR *date, int date_len)
6685 int len, tmp;
6687 if(min_len >= date_len)
6688 return -1;
6690 for(len=0, tmp=o; tmp; tmp/=10) len++;
6691 if(!len) len++;
6692 if(len >= date_len)
6693 return -1;
6695 for(tmp=min_len-len; tmp>0; tmp--)
6696 *date++ = '0';
6697 for(tmp=len; tmp>0; tmp--, o/=10)
6698 date[tmp-1] = '0' + o%10;
6699 return min_len>len ? min_len : len;
6702 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6703 BOOL get_date_format(LCID lcid, DWORD flags, const SYSTEMTIME *st,
6704 const WCHAR *fmt, WCHAR *date, int date_len)
6706 static const LCTYPE dayname[] = {
6707 LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
6708 LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6
6710 static const LCTYPE sdayname[] = {
6711 LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
6712 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
6713 LOCALE_SABBREVDAYNAME6
6715 static const LCTYPE monthname[] = {
6716 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
6717 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
6718 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12
6720 static const LCTYPE smonthname[] = {
6721 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
6722 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
6723 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
6724 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12
6727 if(flags & ~(LOCALE_NOUSEROVERRIDE|VAR_DATEVALUEONLY))
6728 FIXME("ignoring flags %lx\n", flags);
6729 flags &= LOCALE_NOUSEROVERRIDE;
6731 while(*fmt && date_len) {
6732 int count = 1;
6734 switch(*fmt) {
6735 case 'd':
6736 case 'M':
6737 case 'y':
6738 case 'g':
6739 while(*fmt == *(fmt+count))
6740 count++;
6741 fmt += count-1;
6744 switch(*fmt) {
6745 case 'd':
6746 if(count >= 4)
6747 count = GetLocaleInfoW(lcid, dayname[st->wDayOfWeek] | flags, date, date_len)-1;
6748 else if(count == 3)
6749 count = GetLocaleInfoW(lcid, sdayname[st->wDayOfWeek] | flags, date, date_len)-1;
6750 else
6751 count = output_int_len(st->wDay, count, date, date_len);
6752 break;
6753 case 'M':
6754 if(count >= 4)
6755 count = GetLocaleInfoW(lcid, monthname[st->wMonth-1] | flags, date, date_len)-1;
6756 else if(count == 3)
6757 count = GetLocaleInfoW(lcid, smonthname[st->wMonth-1] | flags, date, date_len)-1;
6758 else
6759 count = output_int_len(st->wMonth, count, date, date_len);
6760 break;
6761 case 'y':
6762 if(count >= 3)
6763 count = output_int_len(st->wYear, 0, date, date_len);
6764 else
6765 count = output_int_len(st->wYear%100, count, date, date_len);
6766 break;
6767 case 'g':
6768 if(count == 2) {
6769 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6771 *date++ = 'A';
6772 date_len--;
6773 if(date_len)
6774 *date = 'D';
6775 else
6776 count = -1;
6777 break;
6779 /* fall through */
6780 default:
6781 *date = *fmt;
6784 if(count < 0)
6785 break;
6786 fmt++;
6787 date += count;
6788 date_len -= count;
6791 if(!date_len)
6792 return FALSE;
6793 *date++ = 0;
6794 return TRUE;
6797 /******************************************************************************
6798 * VarBstrFromDate [OLEAUT32.114]
6800 * Convert a VT_DATE to a VT_BSTR.
6802 * PARAMS
6803 * dateIn [I] Source
6804 * lcid [I] LCID for the conversion
6805 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6806 * pbstrOut [O] Destination
6808 * RETURNS
6809 * Success: S_OK.
6810 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6811 * E_OUTOFMEMORY, if memory allocation fails.
6813 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6815 SYSTEMTIME st;
6816 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6817 WCHAR date[128], fmt_buff[80], *time;
6819 TRACE("%g, %#lx, %#lx, %p.\n", dateIn, lcid, dwFlags, pbstrOut);
6821 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6822 return E_INVALIDARG;
6824 *pbstrOut = NULL;
6826 if (dwFlags & VAR_CALENDAR_THAI)
6827 st.wYear += 553; /* Use the Thai buddhist calendar year */
6828 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6829 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6831 if (dwFlags & LOCALE_USE_NLS)
6832 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6833 else
6835 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6836 double partial = dateIn - whole;
6838 if (whole == 0.0)
6839 dwFlags |= VAR_TIMEVALUEONLY;
6840 else if (partial > -1e-12 && partial < 1e-12)
6841 dwFlags |= VAR_DATEVALUEONLY;
6844 if (dwFlags & VAR_TIMEVALUEONLY)
6845 date[0] = '\0';
6846 else
6847 if (!GetLocaleInfoW(lcid, LOCALE_SSHORTDATE, fmt_buff, ARRAY_SIZE(fmt_buff)) ||
6848 !get_date_format(lcid, dwFlags, &st, fmt_buff, date, ARRAY_SIZE(date)))
6849 return E_INVALIDARG;
6851 if (!(dwFlags & VAR_DATEVALUEONLY))
6853 time = date + lstrlenW(date);
6854 if (time != date)
6855 *time++ = ' ';
6856 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time, ARRAY_SIZE(date)-(time-date)))
6857 return E_INVALIDARG;
6860 *pbstrOut = SysAllocString(date);
6861 if (*pbstrOut)
6862 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6863 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6866 /******************************************************************************
6867 * VarBstrFromBool (OLEAUT32.116)
6869 * Convert a VT_BOOL to a VT_BSTR.
6871 * PARAMS
6872 * boolIn [I] Source
6873 * lcid [I] LCID for the conversion
6874 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6875 * pbstrOut [O] Destination
6877 * RETURNS
6878 * Success: S_OK.
6879 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6880 * E_OUTOFMEMORY, if memory allocation fails.
6882 * NOTES
6883 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6884 * localised text of "True" or "False". To convert a bool into a
6885 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6887 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6889 WCHAR szBuff[64];
6890 DWORD dwResId = IDS_TRUE;
6891 LANGID langId;
6893 TRACE("%d, %#lx, %#lx, %p.\n", boolIn, lcid, dwFlags, pbstrOut);
6895 if (!pbstrOut)
6896 return E_INVALIDARG;
6898 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6899 * for variant formatting */
6900 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6902 case VAR_BOOLONOFF:
6903 dwResId = IDS_ON;
6904 break;
6905 case VAR_BOOLYESNO:
6906 dwResId = IDS_YES;
6907 break;
6908 case VAR_LOCALBOOL:
6909 break;
6910 default:
6911 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6914 lcid = ConvertDefaultLocale(lcid);
6915 langId = LANGIDFROMLCID(lcid);
6916 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6917 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6919 if (boolIn == VARIANT_FALSE)
6920 dwResId++; /* Use negative form */
6922 VarBstrFromBool_GetLocalised:
6923 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6925 *pbstrOut = SysAllocString(szBuff);
6926 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6929 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6931 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6932 goto VarBstrFromBool_GetLocalised;
6935 /* Should never get here */
6936 WARN("Failed to load bool text!\n");
6937 return E_OUTOFMEMORY;
6940 /******************************************************************************
6941 * VarBstrFromI1 (OLEAUT32.229)
6943 * Convert a VT_I1 to a VT_BSTR.
6945 * PARAMS
6946 * cIn [I] Source
6947 * lcid [I] LCID for the conversion
6948 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6949 * pbstrOut [O] Destination
6951 * RETURNS
6952 * Success: S_OK.
6953 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6954 * E_OUTOFMEMORY, if memory allocation fails.
6956 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6958 ULONG64 ul64 = cIn;
6960 if (cIn < 0)
6962 ul64 = -cIn;
6963 dwFlags |= VAR_NEGATIVE;
6965 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6968 /******************************************************************************
6969 * VarBstrFromUI2 (OLEAUT32.230)
6971 * Convert a VT_UI2 to a VT_BSTR.
6973 * PARAMS
6974 * usIn [I] Source
6975 * lcid [I] LCID for the conversion
6976 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6977 * pbstrOut [O] Destination
6979 * RETURNS
6980 * Success: S_OK.
6981 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6982 * E_OUTOFMEMORY, if memory allocation fails.
6984 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6986 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6989 /******************************************************************************
6990 * VarBstrFromUI4 (OLEAUT32.231)
6992 * Convert a VT_UI4 to a VT_BSTR.
6994 * PARAMS
6995 * ulIn [I] Source
6996 * lcid [I] LCID for the conversion
6997 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6998 * pbstrOut [O] Destination
7000 * RETURNS
7001 * Success: S_OK.
7002 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7003 * E_OUTOFMEMORY, if memory allocation fails.
7005 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7007 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
7010 /******************************************************************************
7011 * VarBstrFromDec (OLEAUT32.232)
7013 * Convert a VT_DECIMAL to a VT_BSTR.
7015 * PARAMS
7016 * pDecIn [I] Source
7017 * lcid [I] LCID for the conversion
7018 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7019 * pbstrOut [O] Destination
7021 * RETURNS
7022 * Success: S_OK.
7023 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7024 * E_OUTOFMEMORY, if memory allocation fails.
7026 HRESULT WINAPI VarBstrFromDec(const DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7028 WCHAR buff[256];
7029 VARIANT_DI temp;
7031 if (!pbstrOut)
7032 return E_INVALIDARG;
7034 VARIANT_DIFromDec(pDecIn, &temp);
7035 VARIANT_DI_tostringW(&temp, buff, 256);
7037 if (dwFlags & LOCALE_USE_NLS)
7039 WCHAR numbuff[256];
7041 /* Format the number for the locale */
7042 numbuff[0] = '\0';
7043 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
7044 buff, NULL, numbuff, ARRAY_SIZE(numbuff));
7045 TRACE("created NLS string %s\n", debugstr_w(numbuff));
7046 *pbstrOut = SysAllocString(numbuff);
7048 else
7050 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
7053 TRACE("returning %s\n", debugstr_w(*pbstrOut));
7054 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
7057 /************************************************************************
7058 * VarBstrFromI8 (OLEAUT32.370)
7060 * Convert a VT_I8 to a VT_BSTR.
7062 * PARAMS
7063 * llIn [I] Source
7064 * lcid [I] LCID for the conversion
7065 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7066 * pbstrOut [O] Destination
7068 * RETURNS
7069 * Success: S_OK.
7070 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7071 * E_OUTOFMEMORY, if memory allocation fails.
7073 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7075 ULONG64 ul64 = llIn;
7077 if (llIn < 0)
7079 ul64 = -llIn;
7080 dwFlags |= VAR_NEGATIVE;
7082 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
7085 /************************************************************************
7086 * VarBstrFromUI8 (OLEAUT32.371)
7088 * Convert a VT_UI8 to a VT_BSTR.
7090 * PARAMS
7091 * ullIn [I] Source
7092 * lcid [I] LCID for the conversion
7093 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7094 * pbstrOut [O] Destination
7096 * RETURNS
7097 * Success: S_OK.
7098 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7099 * E_OUTOFMEMORY, if memory allocation fails.
7101 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7103 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
7106 /************************************************************************
7107 * VarBstrFromDisp (OLEAUT32.115)
7109 * Convert a VT_DISPATCH to a BSTR.
7111 * PARAMS
7112 * pdispIn [I] Source
7113 * lcid [I] LCID for conversion
7114 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7115 * pbstrOut [O] Destination
7117 * RETURNS
7118 * Success: S_OK.
7119 * Failure: E_INVALIDARG, if the source value is invalid
7120 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7122 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7124 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
7127 /**********************************************************************
7128 * VarBstrCat (OLEAUT32.313)
7130 * Concatenate two BSTR values.
7132 * PARAMS
7133 * pbstrLeft [I] Source
7134 * pbstrRight [I] Value to concatenate
7135 * pbstrOut [O] Destination
7137 * RETURNS
7138 * Success: S_OK.
7139 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7140 * E_OUTOFMEMORY, if memory allocation fails.
7142 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
7144 unsigned int lenLeft, lenRight;
7146 TRACE("%s,%s,%p\n",
7147 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7148 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
7150 if (!pbstrOut)
7151 return E_INVALIDARG;
7153 /* use byte length here to properly handle ansi-allocated BSTRs */
7154 lenLeft = pbstrLeft ? SysStringByteLen(pbstrLeft) : 0;
7155 lenRight = pbstrRight ? SysStringByteLen(pbstrRight) : 0;
7157 *pbstrOut = SysAllocStringByteLen(NULL, lenLeft + lenRight);
7158 if (!*pbstrOut)
7159 return E_OUTOFMEMORY;
7161 (*pbstrOut)[0] = '\0';
7163 if (pbstrLeft)
7164 memcpy(*pbstrOut, pbstrLeft, lenLeft);
7166 if (pbstrRight)
7167 memcpy((CHAR*)*pbstrOut + lenLeft, pbstrRight, lenRight);
7169 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
7170 return S_OK;
7173 /**********************************************************************
7174 * VarBstrCmp (OLEAUT32.314)
7176 * Compare two BSTR values.
7178 * PARAMS
7179 * pbstrLeft [I] Source
7180 * pbstrRight [I] Value to compare
7181 * lcid [I] LCID for the comparison
7182 * dwFlags [I] Flags to pass directly to CompareStringW().
7184 * RETURNS
7185 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7186 * than, equal to or greater than pbstrRight respectively.
7188 * NOTES
7189 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7190 * states. A NULL BSTR pointer is equivalent to an empty string.
7191 * If LCID is equal to 0, a byte by byte comparison is performed.
7193 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
7195 HRESULT hres;
7196 int ret;
7198 TRACE("%s, %s, %#lx, %#lx.\n",
7199 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7200 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
7202 if (!pbstrLeft || !*pbstrLeft)
7204 if (pbstrRight && *pbstrRight)
7205 return VARCMP_LT;
7207 else if (!pbstrRight || !*pbstrRight)
7208 return VARCMP_GT;
7210 if (lcid == 0)
7212 unsigned int lenLeft = SysStringByteLen(pbstrLeft);
7213 unsigned int lenRight = SysStringByteLen(pbstrRight);
7214 ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight));
7215 if (ret < 0)
7216 return VARCMP_LT;
7217 if (ret > 0)
7218 return VARCMP_GT;
7219 if (lenLeft < lenRight)
7220 return VARCMP_LT;
7221 if (lenLeft > lenRight)
7222 return VARCMP_GT;
7223 return VARCMP_EQ;
7225 else
7227 unsigned int lenLeft = SysStringLen(pbstrLeft);
7228 unsigned int lenRight = SysStringLen(pbstrRight);
7230 if (lenLeft == 0 || lenRight == 0)
7232 if (lenLeft == 0 && lenRight == 0) return VARCMP_EQ;
7233 return lenLeft < lenRight ? VARCMP_LT : VARCMP_GT;
7236 hres = CompareStringW(lcid, dwFlags, pbstrLeft, lenLeft,
7237 pbstrRight, lenRight) - CSTR_LESS_THAN;
7238 TRACE("%ld\n", hres);
7239 return hres;
7244 * DATE
7247 /******************************************************************************
7248 * VarDateFromUI1 (OLEAUT32.88)
7250 * Convert a VT_UI1 to a VT_DATE.
7252 * PARAMS
7253 * bIn [I] Source
7254 * pdateOut [O] Destination
7256 * RETURNS
7257 * S_OK.
7259 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
7261 return VarR8FromUI1(bIn, pdateOut);
7264 /******************************************************************************
7265 * VarDateFromI2 (OLEAUT32.89)
7267 * Convert a VT_I2 to a VT_DATE.
7269 * PARAMS
7270 * sIn [I] Source
7271 * pdateOut [O] Destination
7273 * RETURNS
7274 * S_OK.
7276 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
7278 return VarR8FromI2(sIn, pdateOut);
7281 /******************************************************************************
7282 * VarDateFromI4 (OLEAUT32.90)
7284 * Convert a VT_I4 to a VT_DATE.
7286 * PARAMS
7287 * lIn [I] Source
7288 * pdateOut [O] Destination
7290 * RETURNS
7291 * S_OK.
7293 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
7295 return VarDateFromR8(lIn, pdateOut);
7298 /******************************************************************************
7299 * VarDateFromR4 (OLEAUT32.91)
7301 * Convert a VT_R4 to a VT_DATE.
7303 * PARAMS
7304 * fltIn [I] Source
7305 * pdateOut [O] Destination
7307 * RETURNS
7308 * S_OK.
7310 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
7312 return VarR8FromR4(fltIn, pdateOut);
7315 /******************************************************************************
7316 * VarDateFromR8 (OLEAUT32.92)
7318 * Convert a VT_R8 to a VT_DATE.
7320 * PARAMS
7321 * dblIn [I] Source
7322 * pdateOut [O] Destination
7324 * RETURNS
7325 * S_OK.
7327 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
7329 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
7330 *pdateOut = (DATE)dblIn;
7331 return S_OK;
7334 /**********************************************************************
7335 * VarDateFromDisp (OLEAUT32.95)
7337 * Convert a VT_DISPATCH to a VT_DATE.
7339 * PARAMS
7340 * pdispIn [I] Source
7341 * lcid [I] LCID for conversion
7342 * pdateOut [O] Destination
7344 * RETURNS
7345 * Success: S_OK.
7346 * Failure: E_INVALIDARG, if the source value is invalid
7347 * DISP_E_OVERFLOW, if the value will not fit in the destination
7348 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7350 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
7352 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
7355 /******************************************************************************
7356 * VarDateFromBool (OLEAUT32.96)
7358 * Convert a VT_BOOL to a VT_DATE.
7360 * PARAMS
7361 * boolIn [I] Source
7362 * pdateOut [O] Destination
7364 * RETURNS
7365 * S_OK.
7367 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
7369 return VarR8FromBool(boolIn, pdateOut);
7372 /**********************************************************************
7373 * VarDateFromCy (OLEAUT32.93)
7375 * Convert a VT_CY to a VT_DATE.
7377 * PARAMS
7378 * lIn [I] Source
7379 * pdateOut [O] Destination
7381 * RETURNS
7382 * S_OK.
7384 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
7386 return VarR8FromCy(cyIn, pdateOut);
7389 /* Date string parsing */
7390 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7391 #define DP_DATESEP 0x02 /* Date separator */
7392 #define DP_MONTH 0x04 /* Month name */
7393 #define DP_AM 0x08 /* AM */
7394 #define DP_PM 0x10 /* PM */
7396 typedef struct tagDATEPARSE
7398 DWORD dwCount; /* Number of fields found so far (maximum 6) */
7399 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
7400 DWORD dwFlags[6]; /* Flags for each field */
7401 DWORD dwValues[6]; /* Value of each field */
7402 } DATEPARSE;
7404 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7406 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7408 /* Determine if a day is valid in a given month of a given year */
7409 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
7411 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7413 if (day && month && month < 13)
7415 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
7416 return TRUE;
7418 return FALSE;
7421 /* Possible orders for 3 numbers making up a date */
7422 #define ORDER_MDY 0x01
7423 #define ORDER_YMD 0x02
7424 #define ORDER_YDM 0x04
7425 #define ORDER_DMY 0x08
7426 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7428 /* Determine a date for a particular locale, from 3 numbers */
7429 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
7430 DWORD offset, SYSTEMTIME *st)
7432 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
7434 if (!dp->dwCount)
7436 v1 = 30; /* Default to (Variant) 0 date part */
7437 v2 = 12;
7438 v3 = 1899;
7439 goto VARIANT_MakeDate_OK;
7442 v1 = dp->dwValues[offset + 0];
7443 v2 = dp->dwValues[offset + 1];
7444 if (dp->dwCount == 2)
7446 SYSTEMTIME current;
7447 GetSystemTime(&current);
7448 v3 = current.wYear;
7450 else
7451 v3 = dp->dwValues[offset + 2];
7453 TRACE("%ld, %ld, %ld, %ld, %ld.\n", v1, v2, v3, iDate, offset);
7455 /* If one number must be a month (Because a month name was given), then only
7456 * consider orders with the month in that position.
7457 * If we took the current year as 'v3', then only allow a year in that position.
7459 if (dp->dwFlags[offset + 0] & DP_MONTH)
7461 dwAllOrders = ORDER_MDY;
7463 else if (dp->dwFlags[offset + 1] & DP_MONTH)
7465 dwAllOrders = ORDER_DMY;
7466 if (dp->dwCount > 2)
7467 dwAllOrders |= ORDER_YMD;
7469 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
7471 dwAllOrders = ORDER_YDM;
7473 else
7475 dwAllOrders = ORDER_MDY|ORDER_DMY;
7476 if (dp->dwCount > 2)
7477 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
7480 VARIANT_MakeDate_Start:
7481 TRACE("dwAllOrders is %#lx\n", dwAllOrders);
7483 while (dwAllOrders)
7485 DWORD dwTemp;
7487 if (dwCount == 0)
7489 /* First: Try the order given by iDate */
7490 switch (iDate)
7492 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
7493 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
7494 default: dwTry = dwAllOrders & ORDER_YMD; break;
7497 else if (dwCount == 1)
7499 /* Second: Try all the orders compatible with iDate */
7500 switch (iDate)
7502 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7503 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YDM|ORDER_MYD); break;
7504 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7507 else
7509 /* Finally: Try any remaining orders */
7510 dwTry = dwAllOrders;
7513 TRACE("Attempt %ld, dwTry is %#lx\n", dwCount, dwTry);
7515 dwCount++;
7516 if (!dwTry)
7517 continue;
7519 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7521 if (dwTry & ORDER_MDY)
7523 if (VARIANT_IsValidMonthDay(v2,v1,v3))
7525 DATE_SWAP(v1,v2);
7526 goto VARIANT_MakeDate_OK;
7528 dwAllOrders &= ~ORDER_MDY;
7530 if (dwTry & ORDER_YMD)
7532 if (VARIANT_IsValidMonthDay(v3,v2,v1))
7534 DATE_SWAP(v1,v3);
7535 goto VARIANT_MakeDate_OK;
7537 dwAllOrders &= ~ORDER_YMD;
7539 if (dwTry & ORDER_YDM)
7541 if (VARIANT_IsValidMonthDay(v2,v3,v1))
7543 DATE_SWAP(v1,v2);
7544 DATE_SWAP(v2,v3);
7545 goto VARIANT_MakeDate_OK;
7547 dwAllOrders &= ~ORDER_YDM;
7549 if (dwTry & ORDER_DMY)
7551 if (VARIANT_IsValidMonthDay(v1,v2,v3))
7552 goto VARIANT_MakeDate_OK;
7553 dwAllOrders &= ~ORDER_DMY;
7555 if (dwTry & ORDER_MYD)
7557 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7558 if (VARIANT_IsValidMonthDay(v3,v1,v2))
7560 DATE_SWAP(v1,v3);
7561 DATE_SWAP(v2,v3);
7562 goto VARIANT_MakeDate_OK;
7564 dwAllOrders &= ~ORDER_MYD;
7568 if (dp->dwCount == 2)
7570 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7571 v3 = 1; /* 1st of the month */
7572 dwAllOrders = ORDER_YMD|ORDER_MYD;
7573 dp->dwCount = 0; /* Don't return to this code path again */
7574 dwCount = 0;
7575 goto VARIANT_MakeDate_Start;
7578 /* No valid dates were able to be constructed */
7579 return DISP_E_TYPEMISMATCH;
7581 VARIANT_MakeDate_OK:
7583 /* Check that the time part is ok */
7584 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
7585 return DISP_E_TYPEMISMATCH;
7587 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7588 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
7589 st->wHour += 12;
7590 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
7591 st->wHour = 0;
7592 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7594 st->wDay = v1;
7595 st->wMonth = v2;
7596 /* FIXME: For 2 digit dates old versions of Windows used 29 but
7597 * Windows 10 1903 and greater use 49. This cutoff may also be modified by
7598 * setting the value as a string for the relevant calendar id in the
7599 * registry.
7601 * For instance to emulate old Windows versions:
7602 * [HKCU\Control Panel\International\Calendars\TwoDigitYearMax]
7603 * "1"="29"
7604 * (also 2, 9, 10, 11 and 12 for the other Gregorian calendars)
7606 * But Wine doesn't have/use that key at the time of writing.
7608 st->wYear = v3 <= 49 ? 2000 + v3 : v3 <= 99 ? 1900 + v3 : v3;
7609 TRACE("Returning date %ld/%ld/%d\n", v1, v2, st->wYear);
7610 return S_OK;
7613 /******************************************************************************
7614 * VarDateFromStr [OLEAUT32.94]
7616 * Convert a VT_BSTR to at VT_DATE.
7618 * PARAMS
7619 * strIn [I] String to convert
7620 * lcid [I] Locale identifier for the conversion
7621 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7622 * pdateOut [O] Destination for the converted value
7624 * RETURNS
7625 * Success: S_OK. pdateOut contains the converted value.
7626 * FAILURE: An HRESULT error code indicating the problem.
7628 * NOTES
7629 * Any date format that can be created using the date formats from lcid
7630 * (Either from kernel Nls functions, variant conversion or formatting) is a
7631 * valid input to this function. In addition, a few more esoteric formats are
7632 * also supported for compatibility with the native version. The date is
7633 * interpreted according to the date settings in the control panel, unless
7634 * the date is invalid in that format, in which the most compatible format
7635 * that produces a valid date will be used.
7637 HRESULT WINAPI VarDateFromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7639 static const USHORT ParseDateTokens[] =
7641 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7642 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7643 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7644 LOCALE_SMONTHNAME13,
7645 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7646 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7647 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7648 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7649 LOCALE_SABBREVMONTHNAME13,
7650 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7651 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7652 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7653 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7654 LOCALE_SABBREVDAYNAME7,
7655 LOCALE_S1159, LOCALE_S2359,
7656 LOCALE_SDATE
7658 static const BYTE ParseDateMonths[] =
7660 1,2,3,4,5,6,7,8,9,10,11,12,13,
7661 1,2,3,4,5,6,7,8,9,10,11,12,13
7663 unsigned int i;
7664 BSTR tokens[ARRAY_SIZE(ParseDateTokens)];
7665 DATEPARSE dp;
7666 DWORD dwDateSeps = 0, iDate = 0;
7667 HRESULT hRet = S_OK;
7669 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7670 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7671 return E_INVALIDARG;
7673 if (!strIn)
7674 return DISP_E_TYPEMISMATCH;
7676 *pdateOut = 0.0;
7678 TRACE("%s, %#lx, %#lx, %p.\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7680 memset(&dp, 0, sizeof(dp));
7682 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7683 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7684 TRACE("iDate is %ld\n", iDate);
7686 /* Get the month/day/am/pm tokens for this locale */
7687 for (i = 0; i < ARRAY_SIZE(tokens); i++)
7689 WCHAR buff[128];
7690 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7692 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7693 * GetAltMonthNames(). We should really cache these strings too.
7695 buff[0] = '\0';
7696 GetLocaleInfoW(lcid, lctype, buff, ARRAY_SIZE(buff));
7697 tokens[i] = SysAllocString(buff);
7698 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7701 /* Parse the string into our structure */
7702 while (*strIn)
7704 if ('0' <= *strIn && *strIn <= '9')
7706 OLECHAR* end;
7707 if (dp.dwCount >= 6)
7709 hRet = DISP_E_TYPEMISMATCH;
7710 break;
7712 dp.dwValues[dp.dwCount] = wcstoul(strIn, &end, 10);
7713 dp.dwCount++;
7714 strIn = end - 1;
7716 else if (iswalpha(*strIn))
7718 BOOL bFound = FALSE;
7720 for (i = 0; i < ARRAY_SIZE(tokens); i++)
7722 DWORD dwLen = lstrlenW(tokens[i]);
7723 if (dwLen && !wcsnicmp(strIn, tokens[i], dwLen))
7725 if (i <= 25)
7727 if (dp.dwCount >= 6)
7728 hRet = DISP_E_TYPEMISMATCH;
7729 else
7731 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7732 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7733 dp.dwCount++;
7736 else if (i > 39 && i < 42)
7738 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7739 hRet = DISP_E_TYPEMISMATCH;
7740 else
7742 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7743 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7746 strIn += (dwLen - 1);
7747 bFound = TRUE;
7748 break;
7752 if (!bFound)
7754 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7755 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7757 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7758 if (*strIn == 'a' || *strIn == 'A')
7760 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7761 dp.dwParseFlags |= DP_AM;
7763 else
7765 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7766 dp.dwParseFlags |= DP_PM;
7768 strIn++;
7770 else
7772 TRACE("No matching token for %s\n", debugstr_w(strIn));
7773 hRet = DISP_E_TYPEMISMATCH;
7774 break;
7778 else if (*strIn == ':' || *strIn == '.')
7780 if (!dp.dwCount || !strIn[1])
7781 hRet = DISP_E_TYPEMISMATCH;
7782 else
7783 if (tokens[42][0] == *strIn)
7785 dwDateSeps++;
7786 if (dwDateSeps > 2)
7787 hRet = DISP_E_TYPEMISMATCH;
7788 else
7789 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7791 else
7792 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7794 else if (*strIn == '-' || *strIn == '/')
7796 dwDateSeps++;
7797 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7798 hRet = DISP_E_TYPEMISMATCH;
7799 else
7800 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7802 else if (*strIn == ',' || iswspace(*strIn))
7804 if (*strIn == ',' && !strIn[1])
7805 hRet = DISP_E_TYPEMISMATCH;
7807 else
7809 hRet = DISP_E_TYPEMISMATCH;
7811 strIn++;
7814 if (!dp.dwCount || dp.dwCount > 6 ||
7815 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7816 hRet = DISP_E_TYPEMISMATCH;
7818 if (SUCCEEDED(hRet))
7820 SYSTEMTIME st;
7821 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7823 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7825 /* Figure out which numbers correspond to which fields.
7827 * This switch statement works based on the fact that native interprets any
7828 * fields that are not joined with a time separator ('.' or ':') as date
7829 * fields. Thus we construct a value from 0-32 where each set bit indicates
7830 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7831 * For valid permutations, we set dwOffset to point to the first date field
7832 * and shorten dp.dwCount by the number of time fields found. The real
7833 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7834 * each date number must represent in the context of iDate.
7836 TRACE("%#lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7838 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7840 case 0x1: /* TT TTDD TTDDD */
7841 if (dp.dwCount > 3 &&
7842 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7843 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7844 hRet = DISP_E_TYPEMISMATCH;
7845 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7846 hRet = DISP_E_TYPEMISMATCH;
7847 st.wHour = dp.dwValues[0];
7848 st.wMinute = dp.dwValues[1];
7849 dp.dwCount -= 2;
7850 dwOffset = 2;
7851 break;
7853 case 0x3: /* TTT TTTDD TTTDDD */
7854 if (dp.dwCount > 4 &&
7855 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7856 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7857 hRet = DISP_E_TYPEMISMATCH;
7858 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7859 hRet = DISP_E_TYPEMISMATCH;
7860 st.wHour = dp.dwValues[0];
7861 st.wMinute = dp.dwValues[1];
7862 st.wSecond = dp.dwValues[2];
7863 dwOffset = 3;
7864 dp.dwCount -= 3;
7865 break;
7867 case 0x4: /* DDTT */
7868 if (dp.dwCount != 4 ||
7869 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7870 hRet = DISP_E_TYPEMISMATCH;
7872 st.wHour = dp.dwValues[2];
7873 st.wMinute = dp.dwValues[3];
7874 dp.dwCount -= 2;
7875 break;
7877 case 0x0: /* T DD DDD TDDD TDDD */
7878 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7880 st.wHour = dp.dwValues[0]; /* T */
7881 dp.dwCount = 0;
7882 break;
7884 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7886 hRet = DISP_E_TYPEMISMATCH;
7888 else if (dp.dwCount == 3)
7890 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7892 dp.dwCount = 2;
7893 st.wHour = dp.dwValues[0];
7894 dwOffset = 1;
7895 break;
7897 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7899 dp.dwCount = 2;
7900 st.wHour = dp.dwValues[2];
7901 break;
7903 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7904 hRet = DISP_E_TYPEMISMATCH;
7906 else if (dp.dwCount == 4)
7908 dp.dwCount = 3;
7909 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7911 st.wHour = dp.dwValues[0];
7912 dwOffset = 1;
7914 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7916 st.wHour = dp.dwValues[3];
7918 else
7919 hRet = DISP_E_TYPEMISMATCH;
7920 break;
7922 /* .. fall through .. */
7924 case 0x8: /* DDDTT */
7925 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7926 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7927 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7928 dp.dwCount == 4 || dp.dwCount == 6)
7929 hRet = DISP_E_TYPEMISMATCH;
7930 st.wHour = dp.dwValues[3];
7931 st.wMinute = dp.dwValues[4];
7932 if (dp.dwCount == 5)
7933 dp.dwCount -= 2;
7934 break;
7936 case 0xC: /* DDTTT */
7937 if (dp.dwCount != 5 ||
7938 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7939 hRet = DISP_E_TYPEMISMATCH;
7940 st.wHour = dp.dwValues[2];
7941 st.wMinute = dp.dwValues[3];
7942 st.wSecond = dp.dwValues[4];
7943 dp.dwCount -= 3;
7944 break;
7946 case 0x18: /* DDDTTT */
7947 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7948 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7949 hRet = DISP_E_TYPEMISMATCH;
7950 st.wHour = dp.dwValues[3];
7951 st.wMinute = dp.dwValues[4];
7952 st.wSecond = dp.dwValues[5];
7953 dp.dwCount -= 3;
7954 break;
7956 default:
7957 hRet = DISP_E_TYPEMISMATCH;
7958 break;
7961 if (SUCCEEDED(hRet))
7963 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7965 if (dwFlags & VAR_TIMEVALUEONLY)
7967 st.wYear = 1899;
7968 st.wMonth = 12;
7969 st.wDay = 30;
7971 else if (dwFlags & VAR_DATEVALUEONLY)
7972 st.wHour = st.wMinute = st.wSecond = 0;
7974 /* Finally, convert the value to a VT_DATE */
7975 if (SUCCEEDED(hRet))
7976 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7980 for (i = 0; i < ARRAY_SIZE(tokens); i++)
7981 SysFreeString(tokens[i]);
7982 return hRet;
7985 /******************************************************************************
7986 * VarDateFromI1 (OLEAUT32.221)
7988 * Convert a VT_I1 to a VT_DATE.
7990 * PARAMS
7991 * cIn [I] Source
7992 * pdateOut [O] Destination
7994 * RETURNS
7995 * S_OK.
7997 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7999 return VarR8FromI1(cIn, pdateOut);
8002 /******************************************************************************
8003 * VarDateFromUI2 (OLEAUT32.222)
8005 * Convert a VT_UI2 to a VT_DATE.
8007 * PARAMS
8008 * uiIn [I] Source
8009 * pdateOut [O] Destination
8011 * RETURNS
8012 * S_OK.
8014 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
8016 return VarR8FromUI2(uiIn, pdateOut);
8019 /******************************************************************************
8020 * VarDateFromUI4 (OLEAUT32.223)
8022 * Convert a VT_UI4 to a VT_DATE.
8024 * PARAMS
8025 * ulIn [I] Source
8026 * pdateOut [O] Destination
8028 * RETURNS
8029 * S_OK.
8031 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
8033 return VarDateFromR8(ulIn, pdateOut);
8036 /**********************************************************************
8037 * VarDateFromDec (OLEAUT32.224)
8039 * Convert a VT_DECIMAL to a VT_DATE.
8041 * PARAMS
8042 * pdecIn [I] Source
8043 * pdateOut [O] Destination
8045 * RETURNS
8046 * S_OK.
8048 HRESULT WINAPI VarDateFromDec(const DECIMAL *pdecIn, DATE* pdateOut)
8050 return VarR8FromDec(pdecIn, pdateOut);
8053 /******************************************************************************
8054 * VarDateFromI8 (OLEAUT32.364)
8056 * Convert a VT_I8 to a VT_DATE.
8058 * PARAMS
8059 * llIn [I] Source
8060 * pdateOut [O] Destination
8062 * RETURNS
8063 * Success: S_OK.
8064 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8066 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
8068 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
8069 *pdateOut = (DATE)llIn;
8070 return S_OK;
8073 /******************************************************************************
8074 * VarDateFromUI8 (OLEAUT32.365)
8076 * Convert a VT_UI8 to a VT_DATE.
8078 * PARAMS
8079 * ullIn [I] Source
8080 * pdateOut [O] Destination
8082 * RETURNS
8083 * Success: S_OK.
8084 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8086 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
8088 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
8089 *pdateOut = (DATE)ullIn;
8090 return S_OK;