gdi32: Fix leak in GdiDeleteSpoolFileHandle.
[wine.git] / dlls / oleaut32 / vartype.c
blob7dd6cb8c4a697c2e9a9ba8bc3bd5a18886d5f4ad
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 #include "wine/debug.h"
23 #include "winbase.h"
24 #include "winuser.h"
25 #include "winnt.h"
26 #include "variant.h"
27 #include "resource.h"
29 #include "locale.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(variant);
33 extern HMODULE hProxyDll;
35 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
36 #define CY_MULTIPLIER_F 10000.0
37 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
38 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
40 /* Copy data from one variant to another. */
41 static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
43 switch (vt)
45 case VT_I1:
46 case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
47 case VT_BOOL:
48 case VT_I2:
49 case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
50 case VT_R4:
51 case VT_INT:
52 case VT_I4:
53 case VT_UINT:
54 case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
55 case VT_R8:
56 case VT_DATE:
57 case VT_CY:
58 case VT_I8:
59 case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break;
60 case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break;
61 case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
62 case VT_BSTR: memcpy(pOut, &V_BSTR(srcVar), sizeof(BSTR)); break;
63 default:
64 FIXME("VT_ type %d unhandled, please report!\n", vt);
68 /* Macro to inline conversion from a float or double to any integer type,
69 * rounding according to the 'dutch' convention.
71 #define VARIANT_DutchRound(typ, value, res) do { \
72 double whole = value < 0 ? ceil(value) : floor(value); \
73 double fract = value - whole; \
74 if (fract > 0.5) res = (typ)whole + (typ)1; \
75 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
76 else if (fract >= 0.0) res = (typ)whole; \
77 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
78 else if (fract > -0.5) res = (typ)whole; \
79 else res = (typ)whole - (typ)1; \
80 } while(0)
83 /* Coerce VT_BSTR to a numeric type */
84 static HRESULT VARIANT_NumberFromBstr(const OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
85 void* pOut, VARTYPE vt)
87 VARIANTARG dstVar;
88 HRESULT hRet;
89 NUMPARSE np;
90 BYTE rgb[1024];
92 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
93 np.cDig = ARRAY_SIZE(rgb);
94 np.dwInFlags = NUMPRS_STD;
96 hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
98 if (SUCCEEDED(hRet))
100 /* 1 << vt gives us the VTBIT constant for the destination number type */
101 hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
102 if (SUCCEEDED(hRet))
103 VARIANT_CopyData(&dstVar, vt, pOut);
105 return hRet;
108 /* Coerce VT_DISPATCH to another type */
109 static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut,
110 VARTYPE vt, DWORD dwFlags)
112 static DISPPARAMS emptyParams = { NULL, NULL, 0, 0 };
113 VARIANTARG srcVar, dstVar;
114 HRESULT hRet;
116 if (!pdispIn)
117 return DISP_E_BADVARTYPE;
119 /* Get the default 'value' property from the IDispatch */
120 VariantInit(&srcVar);
121 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
122 &emptyParams, &srcVar, NULL, NULL);
124 if (SUCCEEDED(hRet))
126 /* Convert the property to the requested type */
127 VariantInit(&dstVar);
128 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt);
129 VariantClear(&srcVar);
131 if (SUCCEEDED(hRet))
132 VARIANT_CopyData(&dstVar, vt, pOut);
134 else
135 hRet = DISP_E_TYPEMISMATCH;
136 return hRet;
139 /* Inline return type */
140 #define RETTYP static inline HRESULT
143 /* Simple compiler cast from one type to another */
144 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
145 *out = in; return S_OK; }
147 /* Compiler cast where input cannot be negative */
148 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
149 if (in < 0) { return DISP_E_OVERFLOW; } *out = in; return S_OK; }
151 /* Compiler cast where input cannot be > some number */
152 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
153 if (in > (dest)tst) { return DISP_E_OVERFLOW; } *out = in; return S_OK; }
155 /* Compiler cast where input cannot be < some number or >= some other number */
156 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
157 if (in < (dest)lo || in > hi) { return DISP_E_OVERFLOW; } *out = in; return S_OK; }
159 /* I1 */
160 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX)
161 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX)
162 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX)
163 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool)
164 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX)
165 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX)
166 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX)
167 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX)
169 /* UI1 */
170 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX)
171 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool)
172 NEGTST(BYTE, signed char, VarUI1FromI1)
173 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX)
174 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX)
175 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX)
176 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX)
177 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX)
179 /* I2 */
180 SIMPLE(SHORT, BYTE, VarI2FromUI1)
181 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX)
182 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool)
183 SIMPLE(SHORT, signed char, VarI2FromI1)
184 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX)
185 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX)
186 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX)
187 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX)
189 /* UI2 */
190 SIMPLE(USHORT, BYTE, VarUI2FromUI1)
191 NEGTST(USHORT, SHORT, VarUI2FromI2)
192 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX)
193 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool)
194 NEGTST(USHORT, signed char, VarUI2FromI1)
195 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX)
196 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX)
197 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX)
199 /* I4 */
200 SIMPLE(LONG, BYTE, VarI4FromUI1)
201 SIMPLE(LONG, SHORT, VarI4FromI2)
202 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool)
203 SIMPLE(LONG, signed char, VarI4FromI1)
204 SIMPLE(LONG, USHORT, VarI4FromUI2)
205 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX)
206 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX)
207 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX)
209 /* UI4 */
210 SIMPLE(ULONG, BYTE, VarUI4FromUI1)
211 NEGTST(ULONG, SHORT, VarUI4FromI2)
212 NEGTST(ULONG, LONG, VarUI4FromI4)
213 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool)
214 NEGTST(ULONG, signed char, VarUI4FromI1)
215 SIMPLE(ULONG, USHORT, VarUI4FromUI2)
216 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX)
217 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX)
219 /* I8 */
220 SIMPLE(LONG64, BYTE, VarI8FromUI1)
221 SIMPLE(LONG64, SHORT, VarI8FromI2)
222 SIMPLE(LONG64, signed char, VarI8FromI1)
223 SIMPLE(LONG64, USHORT, VarI8FromUI2)
224 SIMPLE(LONG64, ULONG, VarI8FromUI4)
225 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX)
227 /* UI8 */
228 SIMPLE(ULONG64, BYTE, VarUI8FromUI1)
229 NEGTST(ULONG64, SHORT, VarUI8FromI2)
230 NEGTST(ULONG64, signed char, VarUI8FromI1)
231 SIMPLE(ULONG64, USHORT, VarUI8FromUI2)
232 SIMPLE(ULONG64, ULONG, VarUI8FromUI4)
233 NEGTST(ULONG64, LONG64, VarUI8FromI8)
235 /* R4 (float) */
236 SIMPLE(float, BYTE, VarR4FromUI1)
237 SIMPLE(float, SHORT, VarR4FromI2)
238 SIMPLE(float, signed char, VarR4FromI1)
239 SIMPLE(float, USHORT, VarR4FromUI2)
240 SIMPLE(float, LONG, VarR4FromI4)
241 SIMPLE(float, ULONG, VarR4FromUI4)
242 SIMPLE(float, LONG64, VarR4FromI8)
243 SIMPLE(float, ULONG64, VarR4FromUI8)
245 /* R8 (double) */
246 SIMPLE(double, BYTE, VarR8FromUI1)
247 SIMPLE(double, SHORT, VarR8FromI2)
248 SIMPLE(double, float, VarR8FromR4)
249 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
250 SIMPLE(double, DATE, VarR8FromDate)
251 SIMPLE(double, signed char, VarR8FromI1)
252 SIMPLE(double, USHORT, VarR8FromUI2)
253 SIMPLE(double, LONG, VarR8FromI4)
254 SIMPLE(double, ULONG, VarR8FromUI4)
255 SIMPLE(double, LONG64, VarR8FromI8)
256 SIMPLE(double, ULONG64, VarR8FromUI8)
259 /* I1
262 /************************************************************************
263 * VarI1FromUI1 (OLEAUT32.244)
265 * Convert a VT_UI1 to a VT_I1.
267 * PARAMS
268 * bIn [I] Source
269 * pcOut [O] Destination
271 * RETURNS
272 * Success: S_OK.
273 * Failure: E_INVALIDARG, if the source value is invalid
274 * DISP_E_OVERFLOW, if the value will not fit in the destination
276 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
278 return _VarI1FromUI1(bIn, pcOut);
281 /************************************************************************
282 * VarI1FromI2 (OLEAUT32.245)
284 * Convert a VT_I2 to a VT_I1.
286 * PARAMS
287 * sIn [I] Source
288 * pcOut [O] Destination
290 * RETURNS
291 * Success: S_OK.
292 * Failure: E_INVALIDARG, if the source value is invalid
293 * DISP_E_OVERFLOW, if the value will not fit in the destination
295 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
297 return _VarI1FromI2(sIn, pcOut);
300 /************************************************************************
301 * VarI1FromI4 (OLEAUT32.246)
303 * Convert a VT_I4 to a VT_I1.
305 * PARAMS
306 * iIn [I] Source
307 * pcOut [O] Destination
309 * RETURNS
310 * Success: S_OK.
311 * Failure: E_INVALIDARG, if the source value is invalid
312 * DISP_E_OVERFLOW, if the value will not fit in the destination
314 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
316 return _VarI1FromI4(iIn, pcOut);
319 /************************************************************************
320 * VarI1FromR4 (OLEAUT32.247)
322 * Convert a VT_R4 to a VT_I1.
324 * PARAMS
325 * fltIn [I] Source
326 * pcOut [O] Destination
328 * RETURNS
329 * Success: S_OK.
330 * Failure: E_INVALIDARG, if the source value is invalid
331 * DISP_E_OVERFLOW, if the value will not fit in the destination
333 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
335 return VarI1FromR8(fltIn, pcOut);
338 /************************************************************************
339 * VarI1FromR8 (OLEAUT32.248)
341 * Convert a VT_R8 to a VT_I1.
343 * PARAMS
344 * dblIn [I] Source
345 * pcOut [O] Destination
347 * RETURNS
348 * Success: S_OK.
349 * Failure: E_INVALIDARG, if the source value is invalid
350 * DISP_E_OVERFLOW, if the value will not fit in the destination
352 * NOTES
353 * See VarI8FromR8() for details concerning rounding.
355 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
357 if (dblIn < I1_MIN - 0.5 || dblIn >= I1_MAX + 0.5)
358 return DISP_E_OVERFLOW;
359 VARIANT_DutchRound(CHAR, dblIn, *pcOut);
360 return S_OK;
363 /************************************************************************
364 * VarI1FromDate (OLEAUT32.249)
366 * Convert a VT_DATE to a VT_I1.
368 * PARAMS
369 * dateIn [I] Source
370 * pcOut [O] Destination
372 * RETURNS
373 * Success: S_OK.
374 * Failure: E_INVALIDARG, if the source value is invalid
375 * DISP_E_OVERFLOW, if the value will not fit in the destination
377 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
379 return VarI1FromR8(dateIn, pcOut);
382 /************************************************************************
383 * VarI1FromCy (OLEAUT32.250)
385 * Convert a VT_CY to a VT_I1.
387 * PARAMS
388 * cyIn [I] Source
389 * pcOut [O] Destination
391 * RETURNS
392 * Success: S_OK.
393 * Failure: E_INVALIDARG, if the source value is invalid
394 * DISP_E_OVERFLOW, if the value will not fit in the destination
396 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
398 LONG i = I1_MAX + 1;
400 VarI4FromCy(cyIn, &i);
401 return _VarI1FromI4(i, pcOut);
404 /************************************************************************
405 * VarI1FromStr (OLEAUT32.251)
407 * Convert a VT_BSTR to a VT_I1.
409 * PARAMS
410 * strIn [I] Source
411 * lcid [I] LCID for the conversion
412 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
413 * pcOut [O] Destination
415 * RETURNS
416 * Success: S_OK.
417 * Failure: E_INVALIDARG, if the source value is invalid
418 * DISP_E_OVERFLOW, if the value will not fit in the destination
419 * DISP_E_TYPEMISMATCH, if the type cannot be converted
421 HRESULT WINAPI VarI1FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
423 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
426 /************************************************************************
427 * VarI1FromDisp (OLEAUT32.252)
429 * Convert a VT_DISPATCH to a VT_I1.
431 * PARAMS
432 * pdispIn [I] Source
433 * lcid [I] LCID for conversion
434 * pcOut [O] Destination
436 * RETURNS
437 * Success: S_OK.
438 * Failure: E_INVALIDARG, if the source value is invalid
439 * DISP_E_OVERFLOW, if the value will not fit in the destination
440 * DISP_E_TYPEMISMATCH, if the type cannot be converted
442 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
444 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0);
447 /************************************************************************
448 * VarI1FromBool (OLEAUT32.253)
450 * Convert a VT_BOOL to a VT_I1.
452 * PARAMS
453 * boolIn [I] Source
454 * pcOut [O] Destination
456 * RETURNS
457 * S_OK.
459 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
461 return _VarI1FromBool(boolIn, pcOut);
464 /************************************************************************
465 * VarI1FromUI2 (OLEAUT32.254)
467 * Convert a VT_UI2 to a VT_I1.
469 * PARAMS
470 * usIn [I] Source
471 * pcOut [O] Destination
473 * RETURNS
474 * Success: S_OK.
475 * Failure: E_INVALIDARG, if the source value is invalid
476 * DISP_E_OVERFLOW, if the value will not fit in the destination
478 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
480 return _VarI1FromUI2(usIn, pcOut);
483 /************************************************************************
484 * VarI1FromUI4 (OLEAUT32.255)
486 * Convert a VT_UI4 to a VT_I1.
488 * PARAMS
489 * ulIn [I] Source
490 * pcOut [O] Destination
492 * RETURNS
493 * Success: S_OK.
494 * Failure: E_INVALIDARG, if the source value is invalid
495 * DISP_E_OVERFLOW, if the value will not fit in the destination
496 * DISP_E_TYPEMISMATCH, if the type cannot be converted
498 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
500 return _VarI1FromUI4(ulIn, pcOut);
503 /************************************************************************
504 * VarI1FromDec (OLEAUT32.256)
506 * Convert a VT_DECIMAL to a VT_I1.
508 * PARAMS
509 * pDecIn [I] Source
510 * pcOut [O] Destination
512 * RETURNS
513 * Success: S_OK.
514 * Failure: E_INVALIDARG, if the source value is invalid
515 * DISP_E_OVERFLOW, if the value will not fit in the destination
517 HRESULT WINAPI VarI1FromDec(const DECIMAL *pdecIn, signed char* pcOut)
519 LONG64 i64;
520 HRESULT hRet;
522 hRet = VarI8FromDec(pdecIn, &i64);
524 if (SUCCEEDED(hRet))
525 hRet = _VarI1FromI8(i64, pcOut);
526 return hRet;
529 /************************************************************************
530 * VarI1FromI8 (OLEAUT32.376)
532 * Convert a VT_I8 to a VT_I1.
534 * PARAMS
535 * llIn [I] Source
536 * pcOut [O] Destination
538 * RETURNS
539 * Success: S_OK.
540 * Failure: E_INVALIDARG, if the source value is invalid
541 * DISP_E_OVERFLOW, if the value will not fit in the destination
543 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
545 return _VarI1FromI8(llIn, pcOut);
548 /************************************************************************
549 * VarI1FromUI8 (OLEAUT32.377)
551 * Convert a VT_UI8 to a VT_I1.
553 * PARAMS
554 * ullIn [I] Source
555 * pcOut [O] Destination
557 * RETURNS
558 * Success: S_OK.
559 * Failure: E_INVALIDARG, if the source value is invalid
560 * DISP_E_OVERFLOW, if the value will not fit in the destination
562 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
564 return _VarI1FromUI8(ullIn, pcOut);
567 /* UI1
570 /************************************************************************
571 * VarUI1FromI2 (OLEAUT32.130)
573 * Convert a VT_I2 to a VT_UI1.
575 * PARAMS
576 * sIn [I] Source
577 * pbOut [O] Destination
579 * RETURNS
580 * Success: S_OK.
581 * Failure: E_INVALIDARG, if the source value is invalid
582 * DISP_E_OVERFLOW, if the value will not fit in the destination
584 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
586 return _VarUI1FromI2(sIn, pbOut);
589 /************************************************************************
590 * VarUI1FromI4 (OLEAUT32.131)
592 * Convert a VT_I4 to a VT_UI1.
594 * PARAMS
595 * iIn [I] Source
596 * pbOut [O] Destination
598 * RETURNS
599 * Success: S_OK.
600 * Failure: E_INVALIDARG, if the source value is invalid
601 * DISP_E_OVERFLOW, if the value will not fit in the destination
603 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
605 return _VarUI1FromI4(iIn, pbOut);
608 /************************************************************************
609 * VarUI1FromR4 (OLEAUT32.132)
611 * Convert a VT_R4 to a VT_UI1.
613 * PARAMS
614 * fltIn [I] Source
615 * pbOut [O] Destination
617 * RETURNS
618 * Success: S_OK.
619 * Failure: E_INVALIDARG, if the source value is invalid
620 * DISP_E_OVERFLOW, if the value will not fit in the destination
621 * DISP_E_TYPEMISMATCH, if the type cannot be converted
623 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
625 return VarUI1FromR8(fltIn, pbOut);
628 /************************************************************************
629 * VarUI1FromR8 (OLEAUT32.133)
631 * Convert a VT_R8 to a VT_UI1.
633 * PARAMS
634 * dblIn [I] Source
635 * pbOut [O] Destination
637 * RETURNS
638 * Success: S_OK.
639 * Failure: E_INVALIDARG, if the source value is invalid
640 * DISP_E_OVERFLOW, if the value will not fit in the destination
642 * NOTES
643 * See VarI8FromR8() for details concerning rounding.
645 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
647 if (dblIn < -0.5 || dblIn >= UI1_MAX + 0.5)
648 return DISP_E_OVERFLOW;
649 VARIANT_DutchRound(BYTE, dblIn, *pbOut);
650 return S_OK;
653 /************************************************************************
654 * VarUI1FromCy (OLEAUT32.134)
656 * Convert a VT_CY to a VT_UI1.
658 * PARAMS
659 * cyIn [I] Source
660 * pbOut [O] Destination
662 * RETURNS
663 * Success: S_OK.
664 * Failure: E_INVALIDARG, if the source value is invalid
665 * DISP_E_OVERFLOW, if the value will not fit in the destination
667 * NOTES
668 * Negative values >= -5000 will be converted to 0.
670 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
672 ULONG i = UI1_MAX + 1;
674 VarUI4FromCy(cyIn, &i);
675 return _VarUI1FromUI4(i, pbOut);
678 /************************************************************************
679 * VarUI1FromDate (OLEAUT32.135)
681 * Convert a VT_DATE to a VT_UI1.
683 * PARAMS
684 * dateIn [I] Source
685 * pbOut [O] Destination
687 * RETURNS
688 * Success: S_OK.
689 * Failure: E_INVALIDARG, if the source value is invalid
690 * DISP_E_OVERFLOW, if the value will not fit in the destination
692 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
694 return VarUI1FromR8(dateIn, pbOut);
697 /************************************************************************
698 * VarUI1FromStr (OLEAUT32.136)
700 * Convert a VT_BSTR to a VT_UI1.
702 * PARAMS
703 * strIn [I] Source
704 * lcid [I] LCID for the conversion
705 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
706 * pbOut [O] Destination
708 * RETURNS
709 * Success: S_OK.
710 * Failure: E_INVALIDARG, if the source value is invalid
711 * DISP_E_OVERFLOW, if the value will not fit in the destination
712 * DISP_E_TYPEMISMATCH, if the type cannot be converted
714 HRESULT WINAPI VarUI1FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
716 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
719 /************************************************************************
720 * VarUI1FromDisp (OLEAUT32.137)
722 * Convert a VT_DISPATCH to a VT_UI1.
724 * PARAMS
725 * pdispIn [I] Source
726 * lcid [I] LCID for conversion
727 * pbOut [O] Destination
729 * RETURNS
730 * Success: S_OK.
731 * Failure: E_INVALIDARG, if the source value is invalid
732 * DISP_E_OVERFLOW, if the value will not fit in the destination
733 * DISP_E_TYPEMISMATCH, if the type cannot be converted
735 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
737 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0);
740 /************************************************************************
741 * VarUI1FromBool (OLEAUT32.138)
743 * Convert a VT_BOOL to a VT_UI1.
745 * PARAMS
746 * boolIn [I] Source
747 * pbOut [O] Destination
749 * RETURNS
750 * S_OK.
752 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
754 return _VarUI1FromBool(boolIn, pbOut);
757 /************************************************************************
758 * VarUI1FromI1 (OLEAUT32.237)
760 * Convert a VT_I1 to a VT_UI1.
762 * PARAMS
763 * cIn [I] Source
764 * pbOut [O] Destination
766 * RETURNS
767 * Success: S_OK.
768 * Failure: E_INVALIDARG, if the source value is invalid
769 * DISP_E_OVERFLOW, if the value will not fit in the destination
771 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
773 return _VarUI1FromI1(cIn, pbOut);
776 /************************************************************************
777 * VarUI1FromUI2 (OLEAUT32.238)
779 * Convert a VT_UI2 to a VT_UI1.
781 * PARAMS
782 * usIn [I] Source
783 * pbOut [O] Destination
785 * RETURNS
786 * Success: S_OK.
787 * Failure: E_INVALIDARG, if the source value is invalid
788 * DISP_E_OVERFLOW, if the value will not fit in the destination
790 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
792 return _VarUI1FromUI2(usIn, pbOut);
795 /************************************************************************
796 * VarUI1FromUI4 (OLEAUT32.239)
798 * Convert a VT_UI4 to a VT_UI1.
800 * PARAMS
801 * ulIn [I] Source
802 * pbOut [O] Destination
804 * RETURNS
805 * Success: S_OK.
806 * Failure: E_INVALIDARG, if the source value is invalid
807 * DISP_E_OVERFLOW, if the value will not fit in the destination
809 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
811 return _VarUI1FromUI4(ulIn, pbOut);
814 /************************************************************************
815 * VarUI1FromDec (OLEAUT32.240)
817 * Convert a VT_DECIMAL to a VT_UI1.
819 * PARAMS
820 * pDecIn [I] Source
821 * pbOut [O] Destination
823 * RETURNS
824 * Success: S_OK.
825 * Failure: E_INVALIDARG, if the source value is invalid
826 * DISP_E_OVERFLOW, if the value will not fit in the destination
828 HRESULT WINAPI VarUI1FromDec(const DECIMAL *pdecIn, BYTE* pbOut)
830 LONG64 i64;
831 HRESULT hRet;
833 hRet = VarI8FromDec(pdecIn, &i64);
835 if (SUCCEEDED(hRet))
836 hRet = _VarUI1FromI8(i64, pbOut);
837 return hRet;
840 /************************************************************************
841 * VarUI1FromI8 (OLEAUT32.372)
843 * Convert a VT_I8 to a VT_UI1.
845 * PARAMS
846 * llIn [I] Source
847 * pbOut [O] Destination
849 * RETURNS
850 * Success: S_OK.
851 * Failure: E_INVALIDARG, if the source value is invalid
852 * DISP_E_OVERFLOW, if the value will not fit in the destination
854 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
856 return _VarUI1FromI8(llIn, pbOut);
859 /************************************************************************
860 * VarUI1FromUI8 (OLEAUT32.373)
862 * Convert a VT_UI8 to a VT_UI1.
864 * PARAMS
865 * ullIn [I] Source
866 * pbOut [O] Destination
868 * RETURNS
869 * Success: S_OK.
870 * Failure: E_INVALIDARG, if the source value is invalid
871 * DISP_E_OVERFLOW, if the value will not fit in the destination
873 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
875 return _VarUI1FromUI8(ullIn, pbOut);
879 /* I2
882 /************************************************************************
883 * VarI2FromUI1 (OLEAUT32.48)
885 * Convert a VT_UI2 to a VT_I2.
887 * PARAMS
888 * bIn [I] Source
889 * psOut [O] Destination
891 * RETURNS
892 * S_OK.
894 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
896 return _VarI2FromUI1(bIn, psOut);
899 /************************************************************************
900 * VarI2FromI4 (OLEAUT32.49)
902 * Convert a VT_I4 to a VT_I2.
904 * PARAMS
905 * iIn [I] Source
906 * psOut [O] Destination
908 * RETURNS
909 * Success: S_OK.
910 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
912 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
914 return _VarI2FromI4(iIn, psOut);
917 /************************************************************************
918 * VarI2FromR4 (OLEAUT32.50)
920 * Convert a VT_R4 to a VT_I2.
922 * PARAMS
923 * fltIn [I] Source
924 * psOut [O] Destination
926 * RETURNS
927 * Success: S_OK.
928 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
930 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
932 return VarI2FromR8(fltIn, psOut);
935 /************************************************************************
936 * VarI2FromR8 (OLEAUT32.51)
938 * Convert a VT_R8 to a VT_I2.
940 * PARAMS
941 * dblIn [I] Source
942 * psOut [O] Destination
944 * RETURNS
945 * Success: S_OK.
946 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
948 * NOTES
949 * See VarI8FromR8() for details concerning rounding.
951 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
953 if (dblIn < I2_MIN - 0.5 || dblIn >= I2_MAX + 0.5)
954 return DISP_E_OVERFLOW;
955 VARIANT_DutchRound(SHORT, dblIn, *psOut);
956 return S_OK;
959 /************************************************************************
960 * VarI2FromCy (OLEAUT32.52)
962 * Convert a VT_CY to a VT_I2.
964 * PARAMS
965 * cyIn [I] Source
966 * psOut [O] Destination
968 * RETURNS
969 * Success: S_OK.
970 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
972 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
974 LONG i = I2_MAX + 1;
976 VarI4FromCy(cyIn, &i);
977 return _VarI2FromI4(i, psOut);
980 /************************************************************************
981 * VarI2FromDate (OLEAUT32.53)
983 * Convert a VT_DATE to a VT_I2.
985 * PARAMS
986 * dateIn [I] Source
987 * psOut [O] Destination
989 * RETURNS
990 * Success: S_OK.
991 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
993 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
995 return VarI2FromR8(dateIn, psOut);
998 /************************************************************************
999 * VarI2FromStr (OLEAUT32.54)
1001 * Convert a VT_BSTR to a VT_I2.
1003 * PARAMS
1004 * strIn [I] Source
1005 * lcid [I] LCID for the conversion
1006 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1007 * psOut [O] Destination
1009 * RETURNS
1010 * Success: S_OK.
1011 * Failure: E_INVALIDARG, if any parameter is invalid
1012 * DISP_E_OVERFLOW, if the value will not fit in the destination
1013 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1015 HRESULT WINAPI VarI2FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
1017 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
1020 /************************************************************************
1021 * VarI2FromDisp (OLEAUT32.55)
1023 * Convert a VT_DISPATCH to a VT_I2.
1025 * PARAMS
1026 * pdispIn [I] Source
1027 * lcid [I] LCID for conversion
1028 * psOut [O] Destination
1030 * RETURNS
1031 * Success: S_OK.
1032 * Failure: E_INVALIDARG, if pdispIn is invalid,
1033 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1034 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1036 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
1038 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0);
1041 /************************************************************************
1042 * VarI2FromBool (OLEAUT32.56)
1044 * Convert a VT_BOOL to a VT_I2.
1046 * PARAMS
1047 * boolIn [I] Source
1048 * psOut [O] Destination
1050 * RETURNS
1051 * S_OK.
1053 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
1055 return _VarI2FromBool(boolIn, psOut);
1058 /************************************************************************
1059 * VarI2FromI1 (OLEAUT32.205)
1061 * Convert a VT_I1 to a VT_I2.
1063 * PARAMS
1064 * cIn [I] Source
1065 * psOut [O] Destination
1067 * RETURNS
1068 * S_OK.
1070 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
1072 return _VarI2FromI1(cIn, psOut);
1075 /************************************************************************
1076 * VarI2FromUI2 (OLEAUT32.206)
1078 * Convert a VT_UI2 to a VT_I2.
1080 * PARAMS
1081 * usIn [I] Source
1082 * psOut [O] Destination
1084 * RETURNS
1085 * Success: S_OK.
1086 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1088 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
1090 return _VarI2FromUI2(usIn, psOut);
1093 /************************************************************************
1094 * VarI2FromUI4 (OLEAUT32.207)
1096 * Convert a VT_UI4 to a VT_I2.
1098 * PARAMS
1099 * ulIn [I] Source
1100 * psOut [O] Destination
1102 * RETURNS
1103 * Success: S_OK.
1104 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1106 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
1108 return _VarI2FromUI4(ulIn, psOut);
1111 /************************************************************************
1112 * VarI2FromDec (OLEAUT32.208)
1114 * Convert a VT_DECIMAL to a VT_I2.
1116 * PARAMS
1117 * pDecIn [I] Source
1118 * psOut [O] Destination
1120 * RETURNS
1121 * Success: S_OK.
1122 * Failure: E_INVALIDARG, if the source value is invalid
1123 * DISP_E_OVERFLOW, if the value will not fit in the destination
1125 HRESULT WINAPI VarI2FromDec(const DECIMAL *pdecIn, SHORT* psOut)
1127 LONG64 i64;
1128 HRESULT hRet;
1130 hRet = VarI8FromDec(pdecIn, &i64);
1132 if (SUCCEEDED(hRet))
1133 hRet = _VarI2FromI8(i64, psOut);
1134 return hRet;
1137 /************************************************************************
1138 * VarI2FromI8 (OLEAUT32.346)
1140 * Convert a VT_I8 to a VT_I2.
1142 * PARAMS
1143 * llIn [I] Source
1144 * psOut [O] Destination
1146 * RETURNS
1147 * Success: S_OK.
1148 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1150 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
1152 return _VarI2FromI8(llIn, psOut);
1155 /************************************************************************
1156 * VarI2FromUI8 (OLEAUT32.347)
1158 * Convert a VT_UI8 to a VT_I2.
1160 * PARAMS
1161 * ullIn [I] Source
1162 * psOut [O] Destination
1164 * RETURNS
1165 * Success: S_OK.
1166 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1168 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
1170 return _VarI2FromUI8(ullIn, psOut);
1173 /* UI2
1176 /************************************************************************
1177 * VarUI2FromUI1 (OLEAUT32.257)
1179 * Convert a VT_UI1 to a VT_UI2.
1181 * PARAMS
1182 * bIn [I] Source
1183 * pusOut [O] Destination
1185 * RETURNS
1186 * S_OK.
1188 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
1190 return _VarUI2FromUI1(bIn, pusOut);
1193 /************************************************************************
1194 * VarUI2FromI2 (OLEAUT32.258)
1196 * Convert a VT_I2 to a VT_UI2.
1198 * PARAMS
1199 * sIn [I] Source
1200 * pusOut [O] Destination
1202 * RETURNS
1203 * Success: S_OK.
1204 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1206 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
1208 return _VarUI2FromI2(sIn, pusOut);
1211 /************************************************************************
1212 * VarUI2FromI4 (OLEAUT32.259)
1214 * Convert a VT_I4 to a VT_UI2.
1216 * PARAMS
1217 * iIn [I] Source
1218 * pusOut [O] Destination
1220 * RETURNS
1221 * Success: S_OK.
1222 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1224 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
1226 return _VarUI2FromI4(iIn, pusOut);
1229 /************************************************************************
1230 * VarUI2FromR4 (OLEAUT32.260)
1232 * Convert a VT_R4 to a VT_UI2.
1234 * PARAMS
1235 * fltIn [I] Source
1236 * pusOut [O] Destination
1238 * RETURNS
1239 * Success: S_OK.
1240 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1242 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
1244 return VarUI2FromR8(fltIn, pusOut);
1247 /************************************************************************
1248 * VarUI2FromR8 (OLEAUT32.261)
1250 * Convert a VT_R8 to a VT_UI2.
1252 * PARAMS
1253 * dblIn [I] Source
1254 * pusOut [O] Destination
1256 * RETURNS
1257 * Success: S_OK.
1258 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1260 * NOTES
1261 * See VarI8FromR8() for details concerning rounding.
1263 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
1265 if (dblIn < -0.5 || dblIn >= UI2_MAX + 0.5)
1266 return DISP_E_OVERFLOW;
1267 VARIANT_DutchRound(USHORT, dblIn, *pusOut);
1268 return S_OK;
1271 /************************************************************************
1272 * VarUI2FromDate (OLEAUT32.262)
1274 * Convert a VT_DATE to a VT_UI2.
1276 * PARAMS
1277 * dateIn [I] Source
1278 * pusOut [O] Destination
1280 * RETURNS
1281 * Success: S_OK.
1282 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1284 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
1286 return VarUI2FromR8(dateIn, pusOut);
1289 /************************************************************************
1290 * VarUI2FromCy (OLEAUT32.263)
1292 * Convert a VT_CY to a VT_UI2.
1294 * PARAMS
1295 * cyIn [I] Source
1296 * pusOut [O] Destination
1298 * RETURNS
1299 * Success: S_OK.
1300 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1302 * NOTES
1303 * Negative values >= -5000 will be converted to 0.
1305 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
1307 ULONG i = UI2_MAX + 1;
1309 VarUI4FromCy(cyIn, &i);
1310 return _VarUI2FromUI4(i, pusOut);
1313 /************************************************************************
1314 * VarUI2FromStr (OLEAUT32.264)
1316 * Convert a VT_BSTR to a VT_UI2.
1318 * PARAMS
1319 * strIn [I] Source
1320 * lcid [I] LCID for the conversion
1321 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1322 * pusOut [O] Destination
1324 * RETURNS
1325 * Success: S_OK.
1326 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1327 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1329 HRESULT WINAPI VarUI2FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
1331 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
1334 /************************************************************************
1335 * VarUI2FromDisp (OLEAUT32.265)
1337 * Convert a VT_DISPATCH to a VT_UI2.
1339 * PARAMS
1340 * pdispIn [I] Source
1341 * lcid [I] LCID for conversion
1342 * pusOut [O] Destination
1344 * RETURNS
1345 * Success: S_OK.
1346 * Failure: E_INVALIDARG, if the source value is invalid
1347 * DISP_E_OVERFLOW, if the value will not fit in the destination
1348 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1350 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
1352 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0);
1355 /************************************************************************
1356 * VarUI2FromBool (OLEAUT32.266)
1358 * Convert a VT_BOOL to a VT_UI2.
1360 * PARAMS
1361 * boolIn [I] Source
1362 * pusOut [O] Destination
1364 * RETURNS
1365 * S_OK.
1367 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
1369 return _VarUI2FromBool(boolIn, pusOut);
1372 /************************************************************************
1373 * VarUI2FromI1 (OLEAUT32.267)
1375 * Convert a VT_I1 to a VT_UI2.
1377 * PARAMS
1378 * cIn [I] Source
1379 * pusOut [O] Destination
1381 * RETURNS
1382 * Success: S_OK.
1383 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1385 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
1387 return _VarUI2FromI1(cIn, pusOut);
1390 /************************************************************************
1391 * VarUI2FromUI4 (OLEAUT32.268)
1393 * Convert a VT_UI4 to a VT_UI2.
1395 * PARAMS
1396 * ulIn [I] Source
1397 * pusOut [O] Destination
1399 * RETURNS
1400 * Success: S_OK.
1401 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1403 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
1405 return _VarUI2FromUI4(ulIn, pusOut);
1408 /************************************************************************
1409 * VarUI2FromDec (OLEAUT32.269)
1411 * Convert a VT_DECIMAL to a VT_UI2.
1413 * PARAMS
1414 * pDecIn [I] Source
1415 * pusOut [O] Destination
1417 * RETURNS
1418 * Success: S_OK.
1419 * Failure: E_INVALIDARG, if the source value is invalid
1420 * DISP_E_OVERFLOW, if the value will not fit in the destination
1422 HRESULT WINAPI VarUI2FromDec(const DECIMAL *pdecIn, USHORT* pusOut)
1424 LONG64 i64;
1425 HRESULT hRet;
1427 hRet = VarI8FromDec(pdecIn, &i64);
1429 if (SUCCEEDED(hRet))
1430 hRet = _VarUI2FromI8(i64, pusOut);
1431 return hRet;
1434 /************************************************************************
1435 * VarUI2FromI8 (OLEAUT32.378)
1437 * Convert a VT_I8 to a VT_UI2.
1439 * PARAMS
1440 * llIn [I] Source
1441 * pusOut [O] Destination
1443 * RETURNS
1444 * Success: S_OK.
1445 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1447 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
1449 return _VarUI2FromI8(llIn, pusOut);
1452 /************************************************************************
1453 * VarUI2FromUI8 (OLEAUT32.379)
1455 * Convert a VT_UI8 to a VT_UI2.
1457 * PARAMS
1458 * ullIn [I] Source
1459 * pusOut [O] Destination
1461 * RETURNS
1462 * Success: S_OK.
1463 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1465 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
1467 return _VarUI2FromUI8(ullIn, pusOut);
1470 /* I4
1473 /************************************************************************
1474 * VarI4FromUI1 (OLEAUT32.58)
1476 * Convert a VT_UI1 to a VT_I4.
1478 * PARAMS
1479 * bIn [I] Source
1480 * piOut [O] Destination
1482 * RETURNS
1483 * S_OK.
1485 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
1487 return _VarI4FromUI1(bIn, piOut);
1490 /************************************************************************
1491 * VarI4FromI2 (OLEAUT32.59)
1493 * Convert a VT_I2 to a VT_I4.
1495 * PARAMS
1496 * sIn [I] Source
1497 * piOut [O] Destination
1499 * RETURNS
1500 * Success: S_OK.
1501 * Failure: E_INVALIDARG, if the source value is invalid
1502 * DISP_E_OVERFLOW, if the value will not fit in the destination
1504 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
1506 return _VarI4FromI2(sIn, piOut);
1509 /************************************************************************
1510 * VarI4FromR4 (OLEAUT32.60)
1512 * Convert a VT_R4 to a VT_I4.
1514 * PARAMS
1515 * fltIn [I] Source
1516 * piOut [O] Destination
1518 * RETURNS
1519 * Success: S_OK.
1520 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1522 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
1524 return VarI4FromR8(fltIn, piOut);
1527 /************************************************************************
1528 * VarI4FromR8 (OLEAUT32.61)
1530 * Convert a VT_R8 to a VT_I4.
1532 * PARAMS
1533 * dblIn [I] Source
1534 * piOut [O] Destination
1536 * RETURNS
1537 * Success: S_OK.
1538 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1540 * NOTES
1541 * See VarI8FromR8() for details concerning rounding.
1543 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
1545 if (dblIn < I4_MIN - 0.5 || dblIn >= I4_MAX + 0.5)
1546 return DISP_E_OVERFLOW;
1547 VARIANT_DutchRound(LONG, dblIn, *piOut);
1548 return S_OK;
1551 /************************************************************************
1552 * VarI4FromCy (OLEAUT32.62)
1554 * Convert a VT_CY to a VT_I4.
1556 * PARAMS
1557 * cyIn [I] Source
1558 * piOut [O] Destination
1560 * RETURNS
1561 * Success: S_OK.
1562 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1564 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
1566 double d = cyIn.int64 / CY_MULTIPLIER_F;
1567 return VarI4FromR8(d, piOut);
1570 /************************************************************************
1571 * VarI4FromDate (OLEAUT32.63)
1573 * Convert a VT_DATE to a VT_I4.
1575 * PARAMS
1576 * dateIn [I] Source
1577 * piOut [O] Destination
1579 * RETURNS
1580 * Success: S_OK.
1581 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1583 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
1585 return VarI4FromR8(dateIn, piOut);
1588 /************************************************************************
1589 * VarI4FromStr (OLEAUT32.64)
1591 * Convert a VT_BSTR to a VT_I4.
1593 * PARAMS
1594 * strIn [I] Source
1595 * lcid [I] LCID for the conversion
1596 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1597 * piOut [O] Destination
1599 * RETURNS
1600 * Success: S_OK.
1601 * Failure: E_INVALIDARG, if any parameter is invalid
1602 * DISP_E_OVERFLOW, if the value will not fit in the destination
1603 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1605 HRESULT WINAPI VarI4FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
1607 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
1610 /************************************************************************
1611 * VarI4FromDisp (OLEAUT32.65)
1613 * Convert a VT_DISPATCH to a VT_I4.
1615 * PARAMS
1616 * pdispIn [I] Source
1617 * lcid [I] LCID for conversion
1618 * piOut [O] Destination
1620 * RETURNS
1621 * Success: S_OK.
1622 * Failure: E_INVALIDARG, if the source value is invalid
1623 * DISP_E_OVERFLOW, if the value will not fit in the destination
1624 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1626 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
1628 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0);
1631 /************************************************************************
1632 * VarI4FromBool (OLEAUT32.66)
1634 * Convert a VT_BOOL to a VT_I4.
1636 * PARAMS
1637 * boolIn [I] Source
1638 * piOut [O] Destination
1640 * RETURNS
1641 * S_OK.
1643 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
1645 return _VarI4FromBool(boolIn, piOut);
1648 /************************************************************************
1649 * VarI4FromI1 (OLEAUT32.209)
1651 * Convert a VT_I1 to a VT_I4.
1653 * PARAMS
1654 * cIn [I] Source
1655 * piOut [O] Destination
1657 * RETURNS
1658 * S_OK.
1660 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
1662 return _VarI4FromI1(cIn, piOut);
1665 /************************************************************************
1666 * VarI4FromUI2 (OLEAUT32.210)
1668 * Convert a VT_UI2 to a VT_I4.
1670 * PARAMS
1671 * usIn [I] Source
1672 * piOut [O] Destination
1674 * RETURNS
1675 * S_OK.
1677 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
1679 return _VarI4FromUI2(usIn, piOut);
1682 /************************************************************************
1683 * VarI4FromUI4 (OLEAUT32.211)
1685 * Convert a VT_UI4 to a VT_I4.
1687 * PARAMS
1688 * ulIn [I] Source
1689 * piOut [O] Destination
1691 * RETURNS
1692 * Success: S_OK.
1693 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1695 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
1697 return _VarI4FromUI4(ulIn, piOut);
1700 /************************************************************************
1701 * VarI4FromDec (OLEAUT32.212)
1703 * Convert a VT_DECIMAL to a VT_I4.
1705 * PARAMS
1706 * pDecIn [I] Source
1707 * piOut [O] Destination
1709 * RETURNS
1710 * Success: S_OK.
1711 * Failure: E_INVALIDARG, if pdecIn is invalid
1712 * DISP_E_OVERFLOW, if the value will not fit in the destination
1714 HRESULT WINAPI VarI4FromDec(const DECIMAL *pdecIn, LONG *piOut)
1716 LONG64 i64;
1717 HRESULT hRet;
1719 hRet = VarI8FromDec(pdecIn, &i64);
1721 if (SUCCEEDED(hRet))
1722 hRet = _VarI4FromI8(i64, piOut);
1723 return hRet;
1726 /************************************************************************
1727 * VarI4FromI8 (OLEAUT32.348)
1729 * Convert a VT_I8 to a VT_I4.
1731 * PARAMS
1732 * llIn [I] Source
1733 * piOut [O] Destination
1735 * RETURNS
1736 * Success: S_OK.
1737 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1739 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
1741 return _VarI4FromI8(llIn, piOut);
1744 /************************************************************************
1745 * VarI4FromUI8 (OLEAUT32.349)
1747 * Convert a VT_UI8 to a VT_I4.
1749 * PARAMS
1750 * ullIn [I] Source
1751 * piOut [O] Destination
1753 * RETURNS
1754 * Success: S_OK.
1755 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1757 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
1759 return _VarI4FromUI8(ullIn, piOut);
1762 /* UI4
1765 /************************************************************************
1766 * VarUI4FromUI1 (OLEAUT32.270)
1768 * Convert a VT_UI1 to a VT_UI4.
1770 * PARAMS
1771 * bIn [I] Source
1772 * pulOut [O] Destination
1774 * RETURNS
1775 * S_OK.
1777 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
1779 return _VarUI4FromUI1(bIn, pulOut);
1782 /************************************************************************
1783 * VarUI4FromI2 (OLEAUT32.271)
1785 * Convert a VT_I2 to a VT_UI4.
1787 * PARAMS
1788 * sIn [I] Source
1789 * pulOut [O] Destination
1791 * RETURNS
1792 * Success: S_OK.
1793 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1795 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
1797 return _VarUI4FromI2(sIn, pulOut);
1800 /************************************************************************
1801 * VarUI4FromI4 (OLEAUT32.272)
1803 * Convert a VT_I4 to a VT_UI4.
1805 * PARAMS
1806 * iIn [I] Source
1807 * pulOut [O] Destination
1809 * RETURNS
1810 * Success: S_OK.
1811 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1813 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
1815 return _VarUI4FromI4(iIn, pulOut);
1818 /************************************************************************
1819 * VarUI4FromR4 (OLEAUT32.273)
1821 * Convert a VT_R4 to a VT_UI4.
1823 * PARAMS
1824 * fltIn [I] Source
1825 * pulOut [O] Destination
1827 * RETURNS
1828 * Success: S_OK.
1829 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1831 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
1833 return VarUI4FromR8(fltIn, pulOut);
1836 /************************************************************************
1837 * VarUI4FromR8 (OLEAUT32.274)
1839 * Convert a VT_R8 to a VT_UI4.
1841 * PARAMS
1842 * dblIn [I] Source
1843 * pulOut [O] Destination
1845 * RETURNS
1846 * Success: S_OK.
1847 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1849 * NOTES
1850 * See VarI8FromR8() for details concerning rounding.
1852 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
1854 if (dblIn < -0.5 || dblIn >= UI4_MAX + 0.5)
1855 return DISP_E_OVERFLOW;
1856 VARIANT_DutchRound(ULONG, dblIn, *pulOut);
1857 return S_OK;
1860 /************************************************************************
1861 * VarUI4FromDate (OLEAUT32.275)
1863 * Convert a VT_DATE to a VT_UI4.
1865 * PARAMS
1866 * dateIn [I] Source
1867 * pulOut [O] Destination
1869 * RETURNS
1870 * Success: S_OK.
1871 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1873 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
1875 return VarUI4FromR8(dateIn, pulOut);
1878 /************************************************************************
1879 * VarUI4FromCy (OLEAUT32.276)
1881 * Convert a VT_CY to a VT_UI4.
1883 * PARAMS
1884 * cyIn [I] Source
1885 * pulOut [O] Destination
1887 * RETURNS
1888 * Success: S_OK.
1889 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1891 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
1893 double d = cyIn.int64 / CY_MULTIPLIER_F;
1894 return VarUI4FromR8(d, pulOut);
1897 /************************************************************************
1898 * VarUI4FromStr (OLEAUT32.277)
1900 * Convert a VT_BSTR to a VT_UI4.
1902 * PARAMS
1903 * strIn [I] Source
1904 * lcid [I] LCID for the conversion
1905 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1906 * pulOut [O] Destination
1908 * RETURNS
1909 * Success: S_OK.
1910 * Failure: E_INVALIDARG, if any parameter is invalid
1911 * DISP_E_OVERFLOW, if the value will not fit in the destination
1912 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1914 HRESULT WINAPI VarUI4FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
1916 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
1919 /************************************************************************
1920 * VarUI4FromDisp (OLEAUT32.278)
1922 * Convert a VT_DISPATCH to a VT_UI4.
1924 * PARAMS
1925 * pdispIn [I] Source
1926 * lcid [I] LCID for conversion
1927 * pulOut [O] Destination
1929 * RETURNS
1930 * Success: S_OK.
1931 * Failure: E_INVALIDARG, if the source value is invalid
1932 * DISP_E_OVERFLOW, if the value will not fit in the destination
1933 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1935 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
1937 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0);
1940 /************************************************************************
1941 * VarUI4FromBool (OLEAUT32.279)
1943 * Convert a VT_BOOL to a VT_UI4.
1945 * PARAMS
1946 * boolIn [I] Source
1947 * pulOut [O] Destination
1949 * RETURNS
1950 * S_OK.
1952 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
1954 return _VarUI4FromBool(boolIn, pulOut);
1957 /************************************************************************
1958 * VarUI4FromI1 (OLEAUT32.280)
1960 * Convert a VT_I1 to a VT_UI4.
1962 * PARAMS
1963 * cIn [I] Source
1964 * pulOut [O] Destination
1966 * RETURNS
1967 * Success: S_OK.
1968 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1970 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
1972 return _VarUI4FromI1(cIn, pulOut);
1975 /************************************************************************
1976 * VarUI4FromUI2 (OLEAUT32.281)
1978 * Convert a VT_UI2 to a VT_UI4.
1980 * PARAMS
1981 * usIn [I] Source
1982 * pulOut [O] Destination
1984 * RETURNS
1985 * S_OK.
1987 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
1989 return _VarUI4FromUI2(usIn, pulOut);
1992 /************************************************************************
1993 * VarUI4FromDec (OLEAUT32.282)
1995 * Convert a VT_DECIMAL to a VT_UI4.
1997 * PARAMS
1998 * pDecIn [I] Source
1999 * pulOut [O] Destination
2001 * RETURNS
2002 * Success: S_OK.
2003 * Failure: E_INVALIDARG, if pdecIn is invalid
2004 * DISP_E_OVERFLOW, if the value will not fit in the destination
2006 HRESULT WINAPI VarUI4FromDec(const DECIMAL *pdecIn, ULONG *pulOut)
2008 LONG64 i64;
2009 HRESULT hRet;
2011 hRet = VarI8FromDec(pdecIn, &i64);
2013 if (SUCCEEDED(hRet))
2014 hRet = _VarUI4FromI8(i64, pulOut);
2015 return hRet;
2018 /************************************************************************
2019 * VarUI4FromI8 (OLEAUT32.425)
2021 * Convert a VT_I8 to a VT_UI4.
2023 * PARAMS
2024 * llIn [I] Source
2025 * pulOut [O] Destination
2027 * RETURNS
2028 * Success: S_OK.
2029 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2031 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
2033 return _VarUI4FromI8(llIn, pulOut);
2036 /************************************************************************
2037 * VarUI4FromUI8 (OLEAUT32.426)
2039 * Convert a VT_UI8 to a VT_UI4.
2041 * PARAMS
2042 * ullIn [I] Source
2043 * pulOut [O] Destination
2045 * RETURNS
2046 * Success: S_OK.
2047 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2049 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
2051 return _VarUI4FromUI8(ullIn, pulOut);
2054 /* I8
2057 /************************************************************************
2058 * VarI8FromUI1 (OLEAUT32.333)
2060 * Convert a VT_UI1 to a VT_I8.
2062 * PARAMS
2063 * bIn [I] Source
2064 * pi64Out [O] Destination
2066 * RETURNS
2067 * S_OK.
2069 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
2071 return _VarI8FromUI1(bIn, pi64Out);
2075 /************************************************************************
2076 * VarI8FromI2 (OLEAUT32.334)
2078 * Convert a VT_I2 to a VT_I8.
2080 * PARAMS
2081 * sIn [I] Source
2082 * pi64Out [O] Destination
2084 * RETURNS
2085 * S_OK.
2087 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
2089 return _VarI8FromI2(sIn, pi64Out);
2092 /************************************************************************
2093 * VarI8FromR4 (OLEAUT32.335)
2095 * Convert a VT_R4 to a VT_I8.
2097 * PARAMS
2098 * fltIn [I] Source
2099 * pi64Out [O] Destination
2101 * RETURNS
2102 * Success: S_OK.
2103 * Failure: E_INVALIDARG, if the source value is invalid
2104 * DISP_E_OVERFLOW, if the value will not fit in the destination
2106 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
2108 return VarI8FromR8(fltIn, pi64Out);
2111 /************************************************************************
2112 * VarI8FromR8 (OLEAUT32.336)
2114 * Convert a VT_R8 to a VT_I8.
2116 * PARAMS
2117 * dblIn [I] Source
2118 * pi64Out [O] Destination
2120 * RETURNS
2121 * Success: S_OK.
2122 * Failure: E_INVALIDARG, if the source value is invalid
2123 * DISP_E_OVERFLOW, if the value will not fit in the destination
2125 * NOTES
2126 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2127 * very high or low values will not be accurately converted.
2129 * Numbers are rounded using Dutch rounding, as follows:
2131 *| Fractional Part Sign Direction Example
2132 *| --------------- ---- --------- -------
2133 *| < 0.5 + Down 0.4 -> 0.0
2134 *| < 0.5 - Up -0.4 -> 0.0
2135 *| > 0.5 + Up 0.6 -> 1.0
2136 *| < 0.5 - Up -0.6 -> -1.0
2137 *| = 0.5 + Up/Down Down if even, Up if odd
2138 *| = 0.5 - Up/Down Up if even, Down if odd
2140 * This system is often used in supermarkets.
2142 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
2144 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
2145 return DISP_E_OVERFLOW;
2146 VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
2147 return S_OK;
2150 /************************************************************************
2151 * VarI8FromCy (OLEAUT32.337)
2153 * Convert a VT_CY to a VT_I8.
2155 * PARAMS
2156 * cyIn [I] Source
2157 * pi64Out [O] Destination
2159 * RETURNS
2160 * S_OK.
2162 * NOTES
2163 * All negative numbers are rounded down by 1, including those that are
2164 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2165 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2166 * for details.
2168 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
2170 *pi64Out = cyIn.int64 / CY_MULTIPLIER;
2172 if (cyIn.int64 < 0)
2173 (*pi64Out)--; /* Mimic Win32 bug */
2174 else
2176 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.Lo now holds fractional remainder */
2178 if (cyIn.Lo > CY_HALF || (cyIn.Lo == CY_HALF && (*pi64Out & 0x1)))
2179 (*pi64Out)++;
2181 return S_OK;
2184 /************************************************************************
2185 * VarI8FromDate (OLEAUT32.338)
2187 * Convert a VT_DATE to a VT_I8.
2189 * PARAMS
2190 * dateIn [I] Source
2191 * pi64Out [O] Destination
2193 * RETURNS
2194 * Success: S_OK.
2195 * Failure: E_INVALIDARG, if the source value is invalid
2196 * DISP_E_OVERFLOW, if the value will not fit in the destination
2197 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2199 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
2201 return VarI8FromR8(dateIn, pi64Out);
2204 /************************************************************************
2205 * VarI8FromStr (OLEAUT32.339)
2207 * Convert a VT_BSTR to a VT_I8.
2209 * PARAMS
2210 * strIn [I] Source
2211 * lcid [I] LCID for the conversion
2212 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2213 * pi64Out [O] Destination
2215 * RETURNS
2216 * Success: S_OK.
2217 * Failure: E_INVALIDARG, if the source value is invalid
2218 * DISP_E_OVERFLOW, if the value will not fit in the destination
2219 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2221 HRESULT WINAPI VarI8FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
2223 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
2226 /************************************************************************
2227 * VarI8FromDisp (OLEAUT32.340)
2229 * Convert a VT_DISPATCH to a VT_I8.
2231 * PARAMS
2232 * pdispIn [I] Source
2233 * lcid [I] LCID for conversion
2234 * pi64Out [O] Destination
2236 * RETURNS
2237 * Success: S_OK.
2238 * Failure: E_INVALIDARG, if the source value is invalid
2239 * DISP_E_OVERFLOW, if the value will not fit in the destination
2240 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2242 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
2244 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0);
2247 /************************************************************************
2248 * VarI8FromBool (OLEAUT32.341)
2250 * Convert a VT_BOOL to a VT_I8.
2252 * PARAMS
2253 * boolIn [I] Source
2254 * pi64Out [O] Destination
2256 * RETURNS
2257 * S_OK.
2259 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
2261 return VarI8FromI2(boolIn, pi64Out);
2264 /************************************************************************
2265 * VarI8FromI1 (OLEAUT32.342)
2267 * Convert a VT_I1 to a VT_I8.
2269 * PARAMS
2270 * cIn [I] Source
2271 * pi64Out [O] Destination
2273 * RETURNS
2274 * S_OK.
2276 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
2278 return _VarI8FromI1(cIn, pi64Out);
2281 /************************************************************************
2282 * VarI8FromUI2 (OLEAUT32.343)
2284 * Convert a VT_UI2 to a VT_I8.
2286 * PARAMS
2287 * usIn [I] Source
2288 * pi64Out [O] Destination
2290 * RETURNS
2291 * S_OK.
2293 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
2295 return _VarI8FromUI2(usIn, pi64Out);
2298 /************************************************************************
2299 * VarI8FromUI4 (OLEAUT32.344)
2301 * Convert a VT_UI4 to a VT_I8.
2303 * PARAMS
2304 * ulIn [I] Source
2305 * pi64Out [O] Destination
2307 * RETURNS
2308 * S_OK.
2310 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
2312 return _VarI8FromUI4(ulIn, pi64Out);
2315 /************************************************************************
2316 * VarI8FromDec (OLEAUT32.345)
2318 * Convert a VT_DECIMAL to a VT_I8.
2320 * PARAMS
2321 * pDecIn [I] Source
2322 * pi64Out [O] Destination
2324 * RETURNS
2325 * Success: S_OK.
2326 * Failure: E_INVALIDARG, if the source value is invalid
2327 * DISP_E_OVERFLOW, if the value will not fit in the destination
2329 HRESULT WINAPI VarI8FromDec(const DECIMAL *pdecIn, LONG64* pi64Out)
2331 if (!pdecIn->scale)
2333 /* This decimal is just a 96 bit integer */
2334 if (pdecIn->sign & ~DECIMAL_NEG)
2335 return E_INVALIDARG;
2337 if (pdecIn->Hi32 || pdecIn->Mid32 & 0x80000000)
2338 return DISP_E_OVERFLOW;
2340 if (pdecIn->sign)
2341 *pi64Out = -pdecIn->Lo64;
2342 else
2343 *pi64Out = pdecIn->Lo64;
2344 return S_OK;
2346 else
2348 /* Decimal contains a floating point number */
2349 HRESULT hRet;
2350 double dbl;
2352 hRet = VarR8FromDec(pdecIn, &dbl);
2353 if (SUCCEEDED(hRet))
2354 hRet = VarI8FromR8(dbl, pi64Out);
2355 return hRet;
2359 /************************************************************************
2360 * VarI8FromUI8 (OLEAUT32.427)
2362 * Convert a VT_UI8 to a VT_I8.
2364 * PARAMS
2365 * ullIn [I] Source
2366 * pi64Out [O] Destination
2368 * RETURNS
2369 * Success: S_OK.
2370 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2372 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
2374 return _VarI8FromUI8(ullIn, pi64Out);
2377 /* UI8
2380 /************************************************************************
2381 * VarUI8FromI8 (OLEAUT32.428)
2383 * Convert a VT_I8 to a VT_UI8.
2385 * PARAMS
2386 * ulIn [I] Source
2387 * pui64Out [O] Destination
2389 * RETURNS
2390 * Success: S_OK.
2391 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2393 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
2395 return _VarUI8FromI8(llIn, pui64Out);
2398 /************************************************************************
2399 * VarUI8FromUI1 (OLEAUT32.429)
2401 * Convert a VT_UI1 to a VT_UI8.
2403 * PARAMS
2404 * bIn [I] Source
2405 * pui64Out [O] Destination
2407 * RETURNS
2408 * S_OK.
2410 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
2412 return _VarUI8FromUI1(bIn, pui64Out);
2415 /************************************************************************
2416 * VarUI8FromI2 (OLEAUT32.430)
2418 * Convert a VT_I2 to a VT_UI8.
2420 * PARAMS
2421 * sIn [I] Source
2422 * pui64Out [O] Destination
2424 * RETURNS
2425 * S_OK.
2427 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
2429 return _VarUI8FromI2(sIn, pui64Out);
2432 /************************************************************************
2433 * VarUI8FromR4 (OLEAUT32.431)
2435 * Convert a VT_R4 to a VT_UI8.
2437 * PARAMS
2438 * fltIn [I] Source
2439 * pui64Out [O] Destination
2441 * RETURNS
2442 * Success: S_OK.
2443 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2445 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
2447 return VarUI8FromR8(fltIn, pui64Out);
2450 /************************************************************************
2451 * VarUI8FromR8 (OLEAUT32.432)
2453 * Convert a VT_R8 to a VT_UI8.
2455 * PARAMS
2456 * dblIn [I] Source
2457 * pui64Out [O] Destination
2459 * RETURNS
2460 * Success: S_OK.
2461 * Failure: E_INVALIDARG, if the source value is invalid
2462 * DISP_E_OVERFLOW, if the value will not fit in the destination
2464 * NOTES
2465 * See VarI8FromR8() for details concerning rounding.
2467 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
2469 if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
2470 return DISP_E_OVERFLOW;
2471 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
2472 return S_OK;
2475 /************************************************************************
2476 * VarUI8FromCy (OLEAUT32.433)
2478 * Convert a VT_CY to a VT_UI8.
2480 * PARAMS
2481 * cyIn [I] Source
2482 * pui64Out [O] Destination
2484 * RETURNS
2485 * Success: S_OK.
2486 * Failure: E_INVALIDARG, if the source value is invalid
2487 * DISP_E_OVERFLOW, if the value will not fit in the destination
2489 * NOTES
2490 * Negative values >= -5000 will be converted to 0.
2492 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
2494 if (cyIn.int64 < 0)
2496 if (cyIn.int64 < -CY_HALF)
2497 return DISP_E_OVERFLOW;
2498 *pui64Out = 0;
2500 else
2502 *pui64Out = cyIn.int64 / CY_MULTIPLIER;
2504 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.Lo now holds fractional remainder */
2506 if (cyIn.Lo > CY_HALF || (cyIn.Lo == CY_HALF && (*pui64Out & 0x1)))
2507 (*pui64Out)++;
2509 return S_OK;
2512 /************************************************************************
2513 * VarUI8FromDate (OLEAUT32.434)
2515 * Convert a VT_DATE to a VT_UI8.
2517 * PARAMS
2518 * dateIn [I] Source
2519 * pui64Out [O] Destination
2521 * RETURNS
2522 * Success: S_OK.
2523 * Failure: E_INVALIDARG, if the source value is invalid
2524 * DISP_E_OVERFLOW, if the value will not fit in the destination
2525 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2527 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
2529 return VarUI8FromR8(dateIn, pui64Out);
2532 /************************************************************************
2533 * VarUI8FromStr (OLEAUT32.435)
2535 * Convert a VT_BSTR to a VT_UI8.
2537 * PARAMS
2538 * strIn [I] Source
2539 * lcid [I] LCID for the conversion
2540 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2541 * pui64Out [O] Destination
2543 * RETURNS
2544 * Success: S_OK.
2545 * Failure: E_INVALIDARG, if the source value is invalid
2546 * DISP_E_OVERFLOW, if the value will not fit in the destination
2547 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2549 HRESULT WINAPI VarUI8FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
2551 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
2554 /************************************************************************
2555 * VarUI8FromDisp (OLEAUT32.436)
2557 * Convert a VT_DISPATCH to a VT_UI8.
2559 * PARAMS
2560 * pdispIn [I] Source
2561 * lcid [I] LCID for conversion
2562 * pui64Out [O] Destination
2564 * RETURNS
2565 * Success: S_OK.
2566 * Failure: E_INVALIDARG, if the source value is invalid
2567 * DISP_E_OVERFLOW, if the value will not fit in the destination
2568 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2570 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
2572 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0);
2575 /************************************************************************
2576 * VarUI8FromBool (OLEAUT32.437)
2578 * Convert a VT_BOOL to a VT_UI8.
2580 * PARAMS
2581 * boolIn [I] Source
2582 * pui64Out [O] Destination
2584 * RETURNS
2585 * Success: S_OK.
2586 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2588 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
2590 return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
2592 /************************************************************************
2593 * VarUI8FromI1 (OLEAUT32.438)
2595 * Convert a VT_I1 to a VT_UI8.
2597 * PARAMS
2598 * cIn [I] Source
2599 * pui64Out [O] Destination
2601 * RETURNS
2602 * Success: S_OK.
2603 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2605 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
2607 return _VarUI8FromI1(cIn, pui64Out);
2610 /************************************************************************
2611 * VarUI8FromUI2 (OLEAUT32.439)
2613 * Convert a VT_UI2 to a VT_UI8.
2615 * PARAMS
2616 * usIn [I] Source
2617 * pui64Out [O] Destination
2619 * RETURNS
2620 * S_OK.
2622 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
2624 return _VarUI8FromUI2(usIn, pui64Out);
2627 /************************************************************************
2628 * VarUI8FromUI4 (OLEAUT32.440)
2630 * Convert a VT_UI4 to a VT_UI8.
2632 * PARAMS
2633 * ulIn [I] Source
2634 * pui64Out [O] Destination
2636 * RETURNS
2637 * S_OK.
2639 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
2641 return _VarUI8FromUI4(ulIn, pui64Out);
2644 /************************************************************************
2645 * VarUI8FromDec (OLEAUT32.441)
2647 * Convert a VT_DECIMAL to a VT_UI8.
2649 * PARAMS
2650 * pDecIn [I] Source
2651 * pui64Out [O] Destination
2653 * RETURNS
2654 * Success: S_OK.
2655 * Failure: E_INVALIDARG, if the source value is invalid
2656 * DISP_E_OVERFLOW, if the value will not fit in the destination
2658 * NOTES
2659 * Under native Win32, if the source value has a scale of 0, its sign is
2660 * ignored, i.e. this function takes the absolute value rather than fail
2661 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2662 * (use VarAbs() on pDecIn first if you really want this behaviour).
2664 HRESULT WINAPI VarUI8FromDec(const DECIMAL *pdecIn, ULONG64* pui64Out)
2666 if (!pdecIn->scale)
2668 /* This decimal is just a 96 bit integer */
2669 if (pdecIn->sign & ~DECIMAL_NEG)
2670 return E_INVALIDARG;
2672 if (pdecIn->Hi32)
2673 return DISP_E_OVERFLOW;
2675 if (pdecIn->sign)
2677 WARN("Sign would be ignored under Win32!\n");
2678 return DISP_E_OVERFLOW;
2681 *pui64Out = pdecIn->Lo64;
2682 return S_OK;
2684 else
2686 /* Decimal contains a floating point number */
2687 HRESULT hRet;
2688 double dbl;
2690 hRet = VarR8FromDec(pdecIn, &dbl);
2691 if (SUCCEEDED(hRet))
2692 hRet = VarUI8FromR8(dbl, pui64Out);
2693 return hRet;
2697 /* R4
2700 /************************************************************************
2701 * VarR4FromUI1 (OLEAUT32.68)
2703 * Convert a VT_UI1 to a VT_R4.
2705 * PARAMS
2706 * bIn [I] Source
2707 * pFltOut [O] Destination
2709 * RETURNS
2710 * S_OK.
2712 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
2714 return _VarR4FromUI1(bIn, pFltOut);
2717 /************************************************************************
2718 * VarR4FromI2 (OLEAUT32.69)
2720 * Convert a VT_I2 to a VT_R4.
2722 * PARAMS
2723 * sIn [I] Source
2724 * pFltOut [O] Destination
2726 * RETURNS
2727 * S_OK.
2729 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
2731 return _VarR4FromI2(sIn, pFltOut);
2734 /************************************************************************
2735 * VarR4FromI4 (OLEAUT32.70)
2737 * Convert a VT_I4 to a VT_R4.
2739 * PARAMS
2740 * sIn [I] Source
2741 * pFltOut [O] Destination
2743 * RETURNS
2744 * S_OK.
2746 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
2748 return _VarR4FromI4(lIn, pFltOut);
2751 /************************************************************************
2752 * VarR4FromR8 (OLEAUT32.71)
2754 * Convert a VT_R8 to a VT_R4.
2756 * PARAMS
2757 * dblIn [I] Source
2758 * pFltOut [O] Destination
2760 * RETURNS
2761 * Success: S_OK.
2762 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2764 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
2766 double d = dblIn < 0.0 ? -dblIn : dblIn;
2767 if (d > R4_MAX) return DISP_E_OVERFLOW;
2768 *pFltOut = dblIn;
2769 return S_OK;
2772 /************************************************************************
2773 * VarR4FromCy (OLEAUT32.72)
2775 * Convert a VT_CY to a VT_R4.
2777 * PARAMS
2778 * cyIn [I] Source
2779 * pFltOut [O] Destination
2781 * RETURNS
2782 * S_OK.
2784 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
2786 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
2787 return S_OK;
2790 /************************************************************************
2791 * VarR4FromDate (OLEAUT32.73)
2793 * Convert a VT_DATE to a VT_R4.
2795 * PARAMS
2796 * dateIn [I] Source
2797 * pFltOut [O] Destination
2799 * RETURNS
2800 * Success: S_OK.
2801 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2803 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
2805 return VarR4FromR8(dateIn, pFltOut);
2808 /************************************************************************
2809 * VarR4FromStr (OLEAUT32.74)
2811 * Convert a VT_BSTR to a VT_R4.
2813 * PARAMS
2814 * strIn [I] Source
2815 * lcid [I] LCID for the conversion
2816 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2817 * pFltOut [O] Destination
2819 * RETURNS
2820 * Success: S_OK.
2821 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2822 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2824 HRESULT WINAPI VarR4FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
2826 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
2829 /************************************************************************
2830 * VarR4FromDisp (OLEAUT32.75)
2832 * Convert a VT_DISPATCH to a VT_R4.
2834 * PARAMS
2835 * pdispIn [I] Source
2836 * lcid [I] LCID for conversion
2837 * pFltOut [O] Destination
2839 * RETURNS
2840 * Success: S_OK.
2841 * Failure: E_INVALIDARG, if the source value is invalid
2842 * DISP_E_OVERFLOW, if the value will not fit in the destination
2843 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2845 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
2847 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0);
2850 /************************************************************************
2851 * VarR4FromBool (OLEAUT32.76)
2853 * Convert a VT_BOOL to a VT_R4.
2855 * PARAMS
2856 * boolIn [I] Source
2857 * pFltOut [O] Destination
2859 * RETURNS
2860 * S_OK.
2862 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2864 return VarR4FromI2(boolIn, pFltOut);
2867 /************************************************************************
2868 * VarR4FromI1 (OLEAUT32.213)
2870 * Convert a VT_I1 to a VT_R4.
2872 * PARAMS
2873 * cIn [I] Source
2874 * pFltOut [O] Destination
2876 * RETURNS
2877 * Success: S_OK.
2878 * Failure: E_INVALIDARG, if the source value is invalid
2879 * DISP_E_OVERFLOW, if the value will not fit in the destination
2880 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2882 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2884 return _VarR4FromI1(cIn, pFltOut);
2887 /************************************************************************
2888 * VarR4FromUI2 (OLEAUT32.214)
2890 * Convert a VT_UI2 to a VT_R4.
2892 * PARAMS
2893 * usIn [I] Source
2894 * pFltOut [O] Destination
2896 * RETURNS
2897 * Success: S_OK.
2898 * Failure: E_INVALIDARG, if the source value is invalid
2899 * DISP_E_OVERFLOW, if the value will not fit in the destination
2900 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2902 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2904 return _VarR4FromUI2(usIn, pFltOut);
2907 /************************************************************************
2908 * VarR4FromUI4 (OLEAUT32.215)
2910 * Convert a VT_UI4 to a VT_R4.
2912 * PARAMS
2913 * ulIn [I] Source
2914 * pFltOut [O] Destination
2916 * RETURNS
2917 * Success: S_OK.
2918 * Failure: E_INVALIDARG, if the source value is invalid
2919 * DISP_E_OVERFLOW, if the value will not fit in the destination
2920 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2922 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2924 return _VarR4FromUI4(ulIn, pFltOut);
2927 /************************************************************************
2928 * VarR4FromDec (OLEAUT32.216)
2930 * Convert a VT_DECIMAL to a VT_R4.
2932 * PARAMS
2933 * pDecIn [I] Source
2934 * pFltOut [O] Destination
2936 * RETURNS
2937 * Success: S_OK.
2938 * Failure: E_INVALIDARG, if the source value is invalid.
2940 HRESULT WINAPI VarR4FromDec(const DECIMAL* pDecIn, float *pFltOut)
2942 BYTE scale = pDecIn->scale;
2943 double divisor = 1.0;
2944 double highPart;
2946 if (scale > DEC_MAX_SCALE || pDecIn->sign & ~DECIMAL_NEG)
2947 return E_INVALIDARG;
2949 while (scale--)
2950 divisor *= 10.0;
2952 if (pDecIn->sign)
2953 divisor = -divisor;
2955 if (pDecIn->Hi32)
2957 highPart = (double)pDecIn->Hi32 / divisor;
2958 highPart *= 4294967296.0F;
2959 highPart *= 4294967296.0F;
2961 else
2962 highPart = 0.0;
2964 *pFltOut = (double)pDecIn->Lo64 / divisor + highPart;
2965 return S_OK;
2968 /************************************************************************
2969 * VarR4FromI8 (OLEAUT32.360)
2971 * Convert a VT_I8 to a VT_R4.
2973 * PARAMS
2974 * ullIn [I] Source
2975 * pFltOut [O] Destination
2977 * RETURNS
2978 * S_OK.
2980 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2982 return _VarR4FromI8(llIn, pFltOut);
2985 /************************************************************************
2986 * VarR4FromUI8 (OLEAUT32.361)
2988 * Convert a VT_UI8 to a VT_R4.
2990 * PARAMS
2991 * ullIn [I] Source
2992 * pFltOut [O] Destination
2994 * RETURNS
2995 * S_OK.
2997 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
2999 return _VarR4FromUI8(ullIn, pFltOut);
3002 /************************************************************************
3003 * VarR4CmpR8 (OLEAUT32.316)
3005 * Compare a VT_R4 to a VT_R8.
3007 * PARAMS
3008 * fltLeft [I] Source
3009 * dblRight [I] Value to compare
3011 * RETURNS
3012 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3013 * equal to or greater than dblRight respectively.
3015 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3017 if (fltLeft < dblRight)
3018 return VARCMP_LT;
3019 else if (fltLeft > dblRight)
3020 return VARCMP_GT;
3021 return VARCMP_EQ;
3024 /* R8
3027 /************************************************************************
3028 * VarR8FromUI1 (OLEAUT32.78)
3030 * Convert a VT_UI1 to a VT_R8.
3032 * PARAMS
3033 * bIn [I] Source
3034 * pDblOut [O] Destination
3036 * RETURNS
3037 * S_OK.
3039 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3041 return _VarR8FromUI1(bIn, pDblOut);
3044 /************************************************************************
3045 * VarR8FromI2 (OLEAUT32.79)
3047 * Convert a VT_I2 to a VT_R8.
3049 * PARAMS
3050 * sIn [I] Source
3051 * pDblOut [O] Destination
3053 * RETURNS
3054 * S_OK.
3056 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3058 return _VarR8FromI2(sIn, pDblOut);
3061 /************************************************************************
3062 * VarR8FromI4 (OLEAUT32.80)
3064 * Convert a VT_I4 to a VT_R8.
3066 * PARAMS
3067 * sIn [I] Source
3068 * pDblOut [O] Destination
3070 * RETURNS
3071 * S_OK.
3073 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3075 return _VarR8FromI4(lIn, pDblOut);
3078 /************************************************************************
3079 * VarR8FromR4 (OLEAUT32.81)
3081 * Convert a VT_R4 to a VT_R8.
3083 * PARAMS
3084 * fltIn [I] Source
3085 * pDblOut [O] Destination
3087 * RETURNS
3088 * S_OK.
3090 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3092 return _VarR8FromR4(fltIn, pDblOut);
3095 /************************************************************************
3096 * VarR8FromCy (OLEAUT32.82)
3098 * Convert a VT_CY to a VT_R8.
3100 * PARAMS
3101 * cyIn [I] Source
3102 * pDblOut [O] Destination
3104 * RETURNS
3105 * S_OK.
3107 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3109 return _VarR8FromCy(cyIn, pDblOut);
3112 /************************************************************************
3113 * VarR8FromDate (OLEAUT32.83)
3115 * Convert a VT_DATE to a VT_R8.
3117 * PARAMS
3118 * dateIn [I] Source
3119 * pDblOut [O] Destination
3121 * RETURNS
3122 * S_OK.
3124 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3126 return _VarR8FromDate(dateIn, pDblOut);
3129 /************************************************************************
3130 * VarR8FromStr (OLEAUT32.84)
3132 * Convert a VT_BSTR to a VT_R8.
3134 * PARAMS
3135 * strIn [I] Source
3136 * lcid [I] LCID for the conversion
3137 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3138 * pDblOut [O] Destination
3140 * RETURNS
3141 * Success: S_OK.
3142 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3143 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3145 HRESULT WINAPI VarR8FromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3147 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3150 /************************************************************************
3151 * VarR8FromDisp (OLEAUT32.85)
3153 * Convert a VT_DISPATCH to a VT_R8.
3155 * PARAMS
3156 * pdispIn [I] Source
3157 * lcid [I] LCID for conversion
3158 * pDblOut [O] Destination
3160 * RETURNS
3161 * Success: S_OK.
3162 * Failure: E_INVALIDARG, if the source value is invalid
3163 * DISP_E_OVERFLOW, if the value will not fit in the destination
3164 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3166 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3168 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0);
3171 /************************************************************************
3172 * VarR8FromBool (OLEAUT32.86)
3174 * Convert a VT_BOOL to a VT_R8.
3176 * PARAMS
3177 * boolIn [I] Source
3178 * pDblOut [O] Destination
3180 * RETURNS
3181 * S_OK.
3183 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3185 return VarR8FromI2(boolIn, pDblOut);
3188 /************************************************************************
3189 * VarR8FromI1 (OLEAUT32.217)
3191 * Convert a VT_I1 to a VT_R8.
3193 * PARAMS
3194 * cIn [I] Source
3195 * pDblOut [O] Destination
3197 * RETURNS
3198 * Success: S_OK.
3199 * Failure: E_INVALIDARG, if the source value is invalid
3200 * DISP_E_OVERFLOW, if the value will not fit in the destination
3201 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3203 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3205 return _VarR8FromI1(cIn, pDblOut);
3208 /************************************************************************
3209 * VarR8FromUI2 (OLEAUT32.218)
3211 * Convert a VT_UI2 to a VT_R8.
3213 * PARAMS
3214 * usIn [I] Source
3215 * pDblOut [O] Destination
3217 * RETURNS
3218 * Success: S_OK.
3219 * Failure: E_INVALIDARG, if the source value is invalid
3220 * DISP_E_OVERFLOW, if the value will not fit in the destination
3221 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3223 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3225 return _VarR8FromUI2(usIn, pDblOut);
3228 /************************************************************************
3229 * VarR8FromUI4 (OLEAUT32.219)
3231 * Convert a VT_UI4 to a VT_R8.
3233 * PARAMS
3234 * ulIn [I] Source
3235 * pDblOut [O] Destination
3237 * RETURNS
3238 * Success: S_OK.
3239 * Failure: E_INVALIDARG, if the source value is invalid
3240 * DISP_E_OVERFLOW, if the value will not fit in the destination
3241 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3243 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3245 return _VarR8FromUI4(ulIn, pDblOut);
3248 /************************************************************************
3249 * VarR8FromDec (OLEAUT32.220)
3251 * Convert a VT_DECIMAL to a VT_R8.
3253 * PARAMS
3254 * pDecIn [I] Source
3255 * pDblOut [O] Destination
3257 * RETURNS
3258 * Success: S_OK.
3259 * Failure: E_INVALIDARG, if the source value is invalid.
3261 HRESULT WINAPI VarR8FromDec(const DECIMAL* pDecIn, double *pDblOut)
3263 BYTE scale = pDecIn->scale;
3264 double divisor = 1.0, highPart;
3266 if (scale > DEC_MAX_SCALE || pDecIn->sign & ~DECIMAL_NEG)
3267 return E_INVALIDARG;
3269 while (scale--)
3270 divisor *= 10;
3272 if (pDecIn->sign)
3273 divisor = -divisor;
3275 if (pDecIn->Hi32)
3277 highPart = (double)pDecIn->Hi32 / divisor;
3278 highPart *= 4294967296.0F;
3279 highPart *= 4294967296.0F;
3281 else
3282 highPart = 0.0;
3284 *pDblOut = (double)pDecIn->Lo64 / divisor + highPart;
3285 return S_OK;
3288 /************************************************************************
3289 * VarR8FromI8 (OLEAUT32.362)
3291 * Convert a VT_I8 to a VT_R8.
3293 * PARAMS
3294 * ullIn [I] Source
3295 * pDblOut [O] Destination
3297 * RETURNS
3298 * S_OK.
3300 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3302 return _VarR8FromI8(llIn, pDblOut);
3305 /************************************************************************
3306 * VarR8FromUI8 (OLEAUT32.363)
3308 * Convert a VT_UI8 to a VT_R8.
3310 * PARAMS
3311 * ullIn [I] Source
3312 * pDblOut [O] Destination
3314 * RETURNS
3315 * S_OK.
3317 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3319 return _VarR8FromUI8(ullIn, pDblOut);
3322 /************************************************************************
3323 * VarR8Pow (OLEAUT32.315)
3325 * Raise a VT_R8 to a power.
3327 * PARAMS
3328 * dblLeft [I] Source
3329 * dblPow [I] Power to raise dblLeft by
3330 * pDblOut [O] Destination
3332 * RETURNS
3333 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3335 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3337 *pDblOut = pow(dblLeft, dblPow);
3338 return S_OK;
3341 /************************************************************************
3342 * VarR8Round (OLEAUT32.317)
3344 * Round a VT_R8 to a given number of decimal points.
3346 * PARAMS
3347 * dblIn [I] Source
3348 * nDig [I] Number of decimal points to round to
3349 * pDblOut [O] Destination for rounded number
3351 * RETURNS
3352 * Success: S_OK. pDblOut is rounded to nDig digits.
3353 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3355 * NOTES
3356 * The native version of this function rounds using the internal
3357 * binary representation of the number. Wine uses the dutch rounding
3358 * convention, so therefore small differences can occur in the value returned.
3359 * MSDN says that you should use your own rounding function if you want
3360 * rounding to be predictable in your application.
3362 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3364 double scale, whole, fract;
3366 if (nDig < 0)
3367 return E_INVALIDARG;
3369 scale = pow(10.0, nDig);
3371 dblIn *= scale;
3372 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3373 fract = dblIn - whole;
3375 if (fract > 0.5)
3376 dblIn = whole + 1.0;
3377 else if (fract == 0.5)
3378 dblIn = whole + fmod(whole, 2.0);
3379 else if (fract >= 0.0)
3380 dblIn = whole;
3381 else if (fract == -0.5)
3382 dblIn = whole - fmod(whole, 2.0);
3383 else if (fract > -0.5)
3384 dblIn = whole;
3385 else
3386 dblIn = whole - 1.0;
3388 *pDblOut = dblIn / scale;
3389 return S_OK;
3392 /* CY
3395 /* Powers of 10 from 0..4 D.P. */
3396 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3397 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3399 /************************************************************************
3400 * VarCyFromUI1 (OLEAUT32.98)
3402 * Convert a VT_UI1 to a VT_CY.
3404 * PARAMS
3405 * bIn [I] Source
3406 * pCyOut [O] Destination
3408 * RETURNS
3409 * Success: S_OK.
3410 * Failure: E_INVALIDARG, if the source value is invalid
3411 * DISP_E_OVERFLOW, if the value will not fit in the destination
3412 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3414 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3416 pCyOut->int64 = (ULONG64)bIn * CY_MULTIPLIER;
3417 return S_OK;
3420 /************************************************************************
3421 * VarCyFromI2 (OLEAUT32.99)
3423 * Convert a VT_I2 to a VT_CY.
3425 * PARAMS
3426 * sIn [I] Source
3427 * pCyOut [O] Destination
3429 * RETURNS
3430 * Success: S_OK.
3431 * Failure: E_INVALIDARG, if the source value is invalid
3432 * DISP_E_OVERFLOW, if the value will not fit in the destination
3433 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3435 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3437 pCyOut->int64 = (LONG64)sIn * CY_MULTIPLIER;
3438 return S_OK;
3441 /************************************************************************
3442 * VarCyFromI4 (OLEAUT32.100)
3444 * Convert a VT_I4 to a VT_CY.
3446 * PARAMS
3447 * sIn [I] Source
3448 * pCyOut [O] Destination
3450 * RETURNS
3451 * Success: S_OK.
3452 * Failure: E_INVALIDARG, if the source value is invalid
3453 * DISP_E_OVERFLOW, if the value will not fit in the destination
3454 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3456 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3458 pCyOut->int64 = (LONG64)lIn * CY_MULTIPLIER;
3459 return S_OK;
3462 /************************************************************************
3463 * VarCyFromR4 (OLEAUT32.101)
3465 * Convert a VT_R4 to a VT_CY.
3467 * PARAMS
3468 * fltIn [I] Source
3469 * pCyOut [O] Destination
3471 * RETURNS
3472 * Success: S_OK.
3473 * Failure: E_INVALIDARG, if the source value is invalid
3474 * DISP_E_OVERFLOW, if the value will not fit in the destination
3475 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3477 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3479 return VarCyFromR8(fltIn, pCyOut);
3482 /************************************************************************
3483 * VarCyFromR8 (OLEAUT32.102)
3485 * Convert a VT_R8 to a VT_CY.
3487 * PARAMS
3488 * dblIn [I] Source
3489 * pCyOut [O] Destination
3491 * RETURNS
3492 * Success: S_OK.
3493 * Failure: E_INVALIDARG, if the source value is invalid
3494 * DISP_E_OVERFLOW, if the value will not fit in the destination
3495 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3497 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3499 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3500 /* This code gives identical results to Win32 on Intel.
3501 * Here we use fp exceptions to catch overflows when storing the value.
3503 static const unsigned short r8_fpcontrol = 0x137f;
3504 static const double r8_multiplier = CY_MULTIPLIER_F;
3505 unsigned short old_fpcontrol, result_fpstatus;
3507 /* Clear exceptions, save the old fp state and load the new state */
3508 __asm__ __volatile__( "fnclex" );
3509 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3510 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3511 /* Perform the conversion. */
3512 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3513 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3514 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3515 /* Save the resulting fp state, load the old state and clear exceptions */
3516 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3517 __asm__ __volatile__( "fnclex" );
3518 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3520 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3521 return DISP_E_OVERFLOW;
3522 #else
3523 /* This version produces slightly different results for boundary cases */
3524 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3525 return DISP_E_OVERFLOW;
3526 dblIn *= CY_MULTIPLIER_F;
3527 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3528 #endif
3529 return S_OK;
3532 /************************************************************************
3533 * VarCyFromDate (OLEAUT32.103)
3535 * Convert a VT_DATE to a VT_CY.
3537 * PARAMS
3538 * dateIn [I] Source
3539 * pCyOut [O] Destination
3541 * RETURNS
3542 * Success: S_OK.
3543 * Failure: E_INVALIDARG, if the source value is invalid
3544 * DISP_E_OVERFLOW, if the value will not fit in the destination
3545 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3547 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3549 return VarCyFromR8(dateIn, pCyOut);
3552 /************************************************************************
3553 * VarCyFromStr (OLEAUT32.104)
3555 * Convert a VT_BSTR to a VT_CY.
3557 * PARAMS
3558 * strIn [I] Source
3559 * lcid [I] LCID for the conversion
3560 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3561 * pCyOut [O] Destination
3563 * RETURNS
3564 * Success: S_OK.
3565 * Failure: E_INVALIDARG, if the source value is invalid
3566 * DISP_E_OVERFLOW, if the value will not fit in the destination
3567 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3569 HRESULT WINAPI VarCyFromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3571 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3574 /************************************************************************
3575 * VarCyFromDisp (OLEAUT32.105)
3577 * Convert a VT_DISPATCH to a VT_CY.
3579 * PARAMS
3580 * pdispIn [I] Source
3581 * lcid [I] LCID for conversion
3582 * pCyOut [O] Destination
3584 * RETURNS
3585 * Success: S_OK.
3586 * Failure: E_INVALIDARG, if the source value is invalid
3587 * DISP_E_OVERFLOW, if the value will not fit in the destination
3588 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3590 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3592 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0);
3595 /************************************************************************
3596 * VarCyFromBool (OLEAUT32.106)
3598 * Convert a VT_BOOL to a VT_CY.
3600 * PARAMS
3601 * boolIn [I] Source
3602 * pCyOut [O] Destination
3604 * RETURNS
3605 * Success: S_OK.
3606 * Failure: E_INVALIDARG, if the source value is invalid
3607 * DISP_E_OVERFLOW, if the value will not fit in the destination
3608 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3610 * NOTES
3611 * While the sign of the boolean is stored in the currency, the value is
3612 * converted to either 0 or 1.
3614 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3616 pCyOut->int64 = (LONG64)boolIn * CY_MULTIPLIER;
3617 return S_OK;
3620 /************************************************************************
3621 * VarCyFromI1 (OLEAUT32.225)
3623 * Convert a VT_I1 to a VT_CY.
3625 * PARAMS
3626 * cIn [I] Source
3627 * pCyOut [O] Destination
3629 * RETURNS
3630 * Success: S_OK.
3631 * Failure: E_INVALIDARG, if the source value is invalid
3632 * DISP_E_OVERFLOW, if the value will not fit in the destination
3633 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3635 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3637 pCyOut->int64 = (LONG64)cIn * CY_MULTIPLIER;
3638 return S_OK;
3641 /************************************************************************
3642 * VarCyFromUI2 (OLEAUT32.226)
3644 * Convert a VT_UI2 to a VT_CY.
3646 * PARAMS
3647 * usIn [I] Source
3648 * pCyOut [O] Destination
3650 * RETURNS
3651 * Success: S_OK.
3652 * Failure: E_INVALIDARG, if the source value is invalid
3653 * DISP_E_OVERFLOW, if the value will not fit in the destination
3654 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3656 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3658 pCyOut->int64 = (ULONG64)usIn * CY_MULTIPLIER;
3659 return S_OK;
3662 /************************************************************************
3663 * VarCyFromUI4 (OLEAUT32.227)
3665 * Convert a VT_UI4 to a VT_CY.
3667 * PARAMS
3668 * ulIn [I] Source
3669 * pCyOut [O] Destination
3671 * RETURNS
3672 * Success: S_OK.
3673 * Failure: E_INVALIDARG, if the source value is invalid
3674 * DISP_E_OVERFLOW, if the value will not fit in the destination
3675 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3677 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3679 pCyOut->int64 = (ULONG64)ulIn * CY_MULTIPLIER;
3680 return S_OK;
3683 /************************************************************************
3684 * VarCyFromDec (OLEAUT32.228)
3686 * Convert a VT_DECIMAL to a VT_CY.
3688 * PARAMS
3689 * pdecIn [I] Source
3690 * pCyOut [O] Destination
3692 * RETURNS
3693 * Success: S_OK.
3694 * Failure: E_INVALIDARG, if the source value is invalid
3695 * DISP_E_OVERFLOW, if the value will not fit in the destination
3696 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3698 HRESULT WINAPI VarCyFromDec(const DECIMAL* pdecIn, CY* pCyOut)
3700 DECIMAL rounded;
3701 HRESULT hRet;
3703 hRet = VarDecRound(pdecIn, 4, &rounded);
3705 if (SUCCEEDED(hRet))
3707 double d;
3709 if (rounded.Hi32)
3710 return DISP_E_OVERFLOW;
3712 /* Note: Without the casts this promotes to int64 which loses precision */
3713 d = (double)rounded.Lo64 / (double)CY_Divisors[rounded.scale];
3714 if (rounded.sign)
3715 d = -d;
3716 return VarCyFromR8(d, pCyOut);
3718 return hRet;
3721 /************************************************************************
3722 * VarCyFromI8 (OLEAUT32.366)
3724 * Convert a VT_I8 to a VT_CY.
3726 * PARAMS
3727 * ullIn [I] Source
3728 * pCyOut [O] Destination
3730 * RETURNS
3731 * Success: S_OK.
3732 * Failure: E_INVALIDARG, if the source value is invalid
3733 * DISP_E_OVERFLOW, if the value will not fit in the destination
3734 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3736 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3738 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3739 pCyOut->int64 = llIn * CY_MULTIPLIER;
3740 return S_OK;
3743 /************************************************************************
3744 * VarCyFromUI8 (OLEAUT32.375)
3746 * Convert a VT_UI8 to a VT_CY.
3748 * PARAMS
3749 * ullIn [I] Source
3750 * pCyOut [O] Destination
3752 * RETURNS
3753 * Success: S_OK.
3754 * Failure: E_INVALIDARG, if the source value is invalid
3755 * DISP_E_OVERFLOW, if the value will not fit in the destination
3756 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3758 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3760 if (ullIn > (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3761 pCyOut->int64 = ullIn * CY_MULTIPLIER;
3762 return S_OK;
3765 /************************************************************************
3766 * VarCyAdd (OLEAUT32.299)
3768 * Add one CY to another.
3770 * PARAMS
3771 * cyLeft [I] Source
3772 * cyRight [I] Value to add
3773 * pCyOut [O] Destination
3775 * RETURNS
3776 * Success: S_OK.
3777 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3779 HRESULT WINAPI VarCyAdd(CY cyLeft, CY cyRight, CY* pCyOut)
3781 double l,r;
3782 _VarR8FromCy(cyLeft, &l);
3783 _VarR8FromCy(cyRight, &r);
3784 l = l + r;
3785 return VarCyFromR8(l, pCyOut);
3788 /************************************************************************
3789 * VarCyMul (OLEAUT32.303)
3791 * Multiply one CY by another.
3793 * PARAMS
3794 * cyLeft [I] Source
3795 * cyRight [I] Value to multiply by
3796 * pCyOut [O] Destination
3798 * RETURNS
3799 * Success: S_OK.
3800 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3802 HRESULT WINAPI VarCyMul(CY cyLeft, CY cyRight, CY* pCyOut)
3804 double l,r;
3805 _VarR8FromCy(cyLeft, &l);
3806 _VarR8FromCy(cyRight, &r);
3807 l = l * r;
3808 return VarCyFromR8(l, pCyOut);
3811 /************************************************************************
3812 * VarCyMulI4 (OLEAUT32.304)
3814 * Multiply one CY by a VT_I4.
3816 * PARAMS
3817 * cyLeft [I] Source
3818 * lRight [I] Value to multiply by
3819 * pCyOut [O] Destination
3821 * RETURNS
3822 * Success: S_OK.
3823 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3825 HRESULT WINAPI VarCyMulI4(CY cyLeft, LONG lRight, CY* pCyOut)
3827 double d;
3829 _VarR8FromCy(cyLeft, &d);
3830 d = d * lRight;
3831 return VarCyFromR8(d, pCyOut);
3834 /************************************************************************
3835 * VarCySub (OLEAUT32.305)
3837 * Subtract one CY from another.
3839 * PARAMS
3840 * cyLeft [I] Source
3841 * cyRight [I] Value to subtract
3842 * pCyOut [O] Destination
3844 * RETURNS
3845 * Success: S_OK.
3846 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3848 HRESULT WINAPI VarCySub(CY cyLeft, CY cyRight, CY* pCyOut)
3850 double l,r;
3851 _VarR8FromCy(cyLeft, &l);
3852 _VarR8FromCy(cyRight, &r);
3853 l = l - r;
3854 return VarCyFromR8(l, pCyOut);
3857 /************************************************************************
3858 * VarCyAbs (OLEAUT32.306)
3860 * Convert a VT_CY into its absolute value.
3862 * PARAMS
3863 * cyIn [I] Source
3864 * pCyOut [O] Destination
3866 * RETURNS
3867 * Success: S_OK. pCyOut contains the absolute value.
3868 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3870 HRESULT WINAPI VarCyAbs(CY cyIn, CY* pCyOut)
3872 if (cyIn.Hi == 0x80000000 && !cyIn.Lo)
3873 return DISP_E_OVERFLOW;
3875 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3876 return S_OK;
3879 /************************************************************************
3880 * VarCyFix (OLEAUT32.307)
3882 * Return the integer part of a VT_CY.
3884 * PARAMS
3885 * cyIn [I] Source
3886 * pCyOut [O] Destination
3888 * RETURNS
3889 * Success: S_OK.
3890 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3892 * NOTES
3893 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3894 * negative numbers away from 0, while this function rounds them towards zero.
3896 HRESULT WINAPI VarCyFix(CY cyIn, CY* pCyOut)
3898 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3899 pCyOut->int64 *= CY_MULTIPLIER;
3900 return S_OK;
3903 /************************************************************************
3904 * VarCyInt (OLEAUT32.308)
3906 * Return the integer part of a VT_CY.
3908 * PARAMS
3909 * cyIn [I] Source
3910 * pCyOut [O] Destination
3912 * RETURNS
3913 * Success: S_OK.
3914 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3916 * NOTES
3917 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3918 * negative numbers towards 0, while this function rounds them away from zero.
3920 HRESULT WINAPI VarCyInt(CY cyIn, CY* pCyOut)
3922 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3923 pCyOut->int64 *= CY_MULTIPLIER;
3925 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3927 pCyOut->int64 -= CY_MULTIPLIER;
3929 return S_OK;
3932 /************************************************************************
3933 * VarCyNeg (OLEAUT32.309)
3935 * Change the sign of a VT_CY.
3937 * PARAMS
3938 * cyIn [I] Source
3939 * pCyOut [O] Destination
3941 * RETURNS
3942 * Success: S_OK.
3943 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3945 HRESULT WINAPI VarCyNeg(CY cyIn, CY* pCyOut)
3947 if (cyIn.Hi == 0x80000000 && !cyIn.Lo)
3948 return DISP_E_OVERFLOW;
3950 pCyOut->int64 = -cyIn.int64;
3951 return S_OK;
3954 /************************************************************************
3955 * VarCyRound (OLEAUT32.310)
3957 * Change the precision of a VT_CY.
3959 * PARAMS
3960 * cyIn [I] Source
3961 * cDecimals [I] New number of decimals to keep
3962 * pCyOut [O] Destination
3964 * RETURNS
3965 * Success: S_OK.
3966 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3968 HRESULT WINAPI VarCyRound(CY cyIn, int cDecimals, CY* pCyOut)
3970 if (cDecimals < 0)
3971 return E_INVALIDARG;
3973 if (cDecimals > 3)
3975 /* Rounding to more precision than we have */
3976 *pCyOut = cyIn;
3977 return S_OK;
3979 else
3981 double d, div = CY_Divisors[cDecimals];
3983 _VarR8FromCy(cyIn, &d);
3984 d = d * div;
3985 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3986 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3987 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3988 return S_OK;
3992 /************************************************************************
3993 * VarCyCmp (OLEAUT32.311)
3995 * Compare two VT_CY values.
3997 * PARAMS
3998 * cyLeft [I] Source
3999 * cyRight [I] Value to compare
4001 * RETURNS
4002 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4003 * compare is less, equal or greater than source respectively.
4004 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4006 HRESULT WINAPI VarCyCmp(CY cyLeft, CY cyRight)
4008 HRESULT hRet;
4009 CY result;
4011 /* Subtract right from left, and compare the result to 0 */
4012 hRet = VarCySub(cyLeft, cyRight, &result);
4014 if (SUCCEEDED(hRet))
4016 if (result.int64 < 0)
4017 hRet = (HRESULT)VARCMP_LT;
4018 else if (result.int64 > 0)
4019 hRet = (HRESULT)VARCMP_GT;
4020 else
4021 hRet = (HRESULT)VARCMP_EQ;
4023 return hRet;
4026 /************************************************************************
4027 * VarCyCmpR8 (OLEAUT32.312)
4029 * Compare a VT_CY to a double
4031 * PARAMS
4032 * cyLeft [I] Currency Source
4033 * dblRight [I] double to compare to cyLeft
4035 * RETURNS
4036 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4037 * less than, equal to or greater than cyLeft respectively.
4038 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4040 HRESULT WINAPI VarCyCmpR8(CY cyLeft, double dblRight)
4042 HRESULT hRet;
4043 CY cyRight;
4045 hRet = VarCyFromR8(dblRight, &cyRight);
4047 if (SUCCEEDED(hRet))
4048 hRet = VarCyCmp(cyLeft, cyRight);
4050 return hRet;
4053 /************************************************************************
4054 * VarCyMulI8 (OLEAUT32.329)
4056 * Multiply a VT_CY by a VT_I8.
4058 * PARAMS
4059 * cyLeft [I] Source
4060 * llRight [I] Value to multiply by
4061 * pCyOut [O] Destination
4063 * RETURNS
4064 * Success: S_OK.
4065 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4067 HRESULT WINAPI VarCyMulI8(CY cyLeft, LONG64 llRight, CY* pCyOut)
4069 double d;
4071 _VarR8FromCy(cyLeft, &d);
4072 d = d * (double)llRight;
4073 return VarCyFromR8(d, pCyOut);
4076 /* DECIMAL
4079 /************************************************************************
4080 * VarDecFromUI1 (OLEAUT32.190)
4082 * Convert a VT_UI1 to a DECIMAL.
4084 * PARAMS
4085 * bIn [I] Source
4086 * pDecOut [O] Destination
4088 * RETURNS
4089 * S_OK.
4091 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4093 return VarDecFromUI4(bIn, pDecOut);
4096 /************************************************************************
4097 * VarDecFromI2 (OLEAUT32.191)
4099 * Convert a VT_I2 to a DECIMAL.
4101 * PARAMS
4102 * sIn [I] Source
4103 * pDecOut [O] Destination
4105 * RETURNS
4106 * S_OK.
4108 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4110 return VarDecFromI4(sIn, pDecOut);
4113 /************************************************************************
4114 * VarDecFromI4 (OLEAUT32.192)
4116 * Convert a VT_I4 to a DECIMAL.
4118 * PARAMS
4119 * sIn [I] Source
4120 * pDecOut [O] Destination
4122 * RETURNS
4123 * S_OK.
4125 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4127 pDecOut->Hi32 = 0;
4128 pDecOut->Mid32 = 0;
4129 pDecOut->scale = 0;
4131 if (lIn < 0)
4133 pDecOut->sign = DECIMAL_NEG;
4134 pDecOut->Lo32 = -lIn;
4136 else
4138 pDecOut->sign = DECIMAL_POS;
4139 pDecOut->Lo32 = lIn;
4141 return S_OK;
4144 /* internal representation of the value stored in a DECIMAL. The bytes are
4145 stored from LSB at index 0 to MSB at index 11
4147 typedef struct DECIMAL_internal
4149 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4150 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4151 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4152 } VARIANT_DI;
4154 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest);
4155 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest);
4156 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to);
4157 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to);
4158 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor);
4159 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n);
4161 /************************************************************************
4162 * VarDecFromR4 (OLEAUT32.193)
4164 * Convert a VT_R4 to a DECIMAL.
4166 * PARAMS
4167 * fltIn [I] Source
4168 * pDecOut [O] Destination
4170 * RETURNS
4171 * S_OK.
4173 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4175 VARIANT_DI di;
4176 HRESULT hres;
4178 hres = VARIANT_DI_FromR4(fltIn, &di);
4179 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4180 return hres;
4183 /************************************************************************
4184 * VarDecFromR8 (OLEAUT32.194)
4186 * Convert a VT_R8 to a DECIMAL.
4188 * PARAMS
4189 * dblIn [I] Source
4190 * pDecOut [O] Destination
4192 * RETURNS
4193 * S_OK.
4195 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4197 VARIANT_DI di;
4198 HRESULT hres;
4200 hres = VARIANT_DI_FromR8(dblIn, &di);
4201 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4202 return hres;
4205 /************************************************************************
4206 * VarDecFromDate (OLEAUT32.195)
4208 * Convert a VT_DATE to a DECIMAL.
4210 * PARAMS
4211 * dateIn [I] Source
4212 * pDecOut [O] Destination
4214 * RETURNS
4215 * S_OK.
4217 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4219 return VarDecFromR8(dateIn, pDecOut);
4222 /************************************************************************
4223 * VarDecFromCy (OLEAUT32.196)
4225 * Convert a VT_CY to a DECIMAL.
4227 * PARAMS
4228 * cyIn [I] Source
4229 * pDecOut [O] Destination
4231 * RETURNS
4232 * S_OK.
4234 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4236 pDecOut->Hi32 = 0;
4237 pDecOut->scale = 4;
4239 if (cyIn.int64 < 0)
4241 pDecOut->sign = DECIMAL_NEG;
4242 pDecOut->Lo64 = -cyIn.int64;
4244 else
4246 pDecOut->sign = DECIMAL_POS;
4247 pDecOut->Lo64 = cyIn.int64;
4249 return S_OK;
4252 /************************************************************************
4253 * VarDecFromStr (OLEAUT32.197)
4255 * Convert a VT_BSTR to a DECIMAL.
4257 * PARAMS
4258 * strIn [I] Source
4259 * lcid [I] LCID for the conversion
4260 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4261 * pDecOut [O] Destination
4263 * RETURNS
4264 * Success: S_OK.
4265 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4267 HRESULT WINAPI VarDecFromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4269 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4272 /************************************************************************
4273 * VarDecFromDisp (OLEAUT32.198)
4275 * Convert a VT_DISPATCH to a DECIMAL.
4277 * PARAMS
4278 * pdispIn [I] Source
4279 * lcid [I] LCID for conversion
4280 * pDecOut [O] Destination
4282 * RETURNS
4283 * Success: S_OK.
4284 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4286 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4288 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0);
4291 /************************************************************************
4292 * VarDecFromBool (OLEAUT32.199)
4294 * Convert a VT_BOOL to a DECIMAL.
4296 * PARAMS
4297 * bIn [I] Source
4298 * pDecOut [O] Destination
4300 * RETURNS
4301 * S_OK.
4303 * NOTES
4304 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4306 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4308 pDecOut->Hi32 = 0;
4309 pDecOut->scale = 0;
4310 if (bIn)
4312 pDecOut->sign = DECIMAL_NEG;
4313 pDecOut->Lo64 = 1;
4315 else
4317 pDecOut->sign = DECIMAL_POS;
4318 pDecOut->Lo64 = 0;
4320 return S_OK;
4323 /************************************************************************
4324 * VarDecFromI1 (OLEAUT32.241)
4326 * Convert a VT_I1 to a DECIMAL.
4328 * PARAMS
4329 * cIn [I] Source
4330 * pDecOut [O] Destination
4332 * RETURNS
4333 * S_OK.
4335 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4337 return VarDecFromI4(cIn, pDecOut);
4340 /************************************************************************
4341 * VarDecFromUI2 (OLEAUT32.242)
4343 * Convert a VT_UI2 to a DECIMAL.
4345 * PARAMS
4346 * usIn [I] Source
4347 * pDecOut [O] Destination
4349 * RETURNS
4350 * S_OK.
4352 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4354 return VarDecFromUI4(usIn, pDecOut);
4357 /************************************************************************
4358 * VarDecFromUI4 (OLEAUT32.243)
4360 * Convert a VT_UI4 to a DECIMAL.
4362 * PARAMS
4363 * ulIn [I] Source
4364 * pDecOut [O] Destination
4366 * RETURNS
4367 * S_OK.
4369 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4371 pDecOut->sign = DECIMAL_POS;
4372 pDecOut->scale = 0;
4373 pDecOut->Hi32 = 0;
4374 pDecOut->Lo64 = ulIn;
4375 return S_OK;
4378 /************************************************************************
4379 * VarDecFromI8 (OLEAUT32.374)
4381 * Convert a VT_I8 to a DECIMAL.
4383 * PARAMS
4384 * llIn [I] Source
4385 * pDecOut [O] Destination
4387 * RETURNS
4388 * S_OK.
4390 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4392 pDecOut->Hi32 = 0;
4393 pDecOut->scale = 0;
4395 if (llIn < 0)
4397 pDecOut->sign = DECIMAL_NEG;
4398 pDecOut->Lo64 = -llIn;
4400 else
4402 pDecOut->sign = DECIMAL_POS;
4403 pDecOut->Lo64 = llIn;
4405 return S_OK;
4408 /************************************************************************
4409 * VarDecFromUI8 (OLEAUT32.375)
4411 * Convert a VT_UI8 to a DECIMAL.
4413 * PARAMS
4414 * ullIn [I] Source
4415 * pDecOut [O] Destination
4417 * RETURNS
4418 * S_OK.
4420 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4422 pDecOut->sign = DECIMAL_POS;
4423 pDecOut->scale = 0;
4424 pDecOut->Hi32 = 0;
4425 pDecOut->Lo64 = ullIn;
4426 return S_OK;
4429 /* Make two DECIMALS the same scale; used by math functions below */
4430 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4431 const DECIMAL** ppDecRight,
4432 DECIMAL pDecOut[2])
4434 static DECIMAL scaleFactor;
4435 unsigned char remainder;
4436 DECIMAL decTemp;
4437 VARIANT_DI di;
4438 int scaleAmount, i;
4440 if ((*ppDecLeft)->sign & ~DECIMAL_NEG || (*ppDecRight)->sign & ~DECIMAL_NEG)
4441 return E_INVALIDARG;
4443 scaleFactor.Lo32 = 10;
4445 i = scaleAmount = (*ppDecLeft)->scale - (*ppDecRight)->scale;
4447 if (!scaleAmount)
4448 return S_OK; /* Same scale */
4450 if (scaleAmount > 0)
4452 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4453 *ppDecRight = &pDecOut[0];
4455 else
4457 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4458 *ppDecLeft = &pDecOut[0];
4459 i = -scaleAmount;
4462 /* Multiply up the value to be scaled by the correct amount (if possible) */
4463 while (i > 0 && SUCCEEDED(VarDecMul(&decTemp, &scaleFactor, &pDecOut[0])))
4465 decTemp = pDecOut[0];
4466 i--;
4469 if (!i)
4471 pDecOut[0].scale += (scaleAmount > 0) ? scaleAmount : (-scaleAmount);
4472 return S_OK; /* Same scale */
4475 /* Scaling further not possible, reduce accuracy of other argument */
4476 pDecOut[0] = decTemp;
4477 if (scaleAmount > 0)
4479 pDecOut[0].scale += scaleAmount - i;
4480 VARIANT_DIFromDec(*ppDecLeft, &di);
4481 *ppDecLeft = &pDecOut[1];
4483 else
4485 pDecOut[0].scale += (-scaleAmount) - i;
4486 VARIANT_DIFromDec(*ppDecRight, &di);
4487 *ppDecRight = &pDecOut[1];
4490 di.scale -= i;
4491 remainder = 0;
4492 while (i-- > 0 && !VARIANT_int_iszero(di.bitsnum, ARRAY_SIZE(di.bitsnum)))
4494 remainder = VARIANT_int_divbychar(di.bitsnum, ARRAY_SIZE(di.bitsnum), 10);
4495 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4498 /* round up the result - native oleaut32 does this */
4499 if (remainder >= 5) {
4500 for (remainder = 1, i = 0; i < ARRAY_SIZE(di.bitsnum) && remainder; i++) {
4501 ULONGLONG digit = di.bitsnum[i] + 1;
4502 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4503 di.bitsnum[i] = digit & 0xFFFFFFFF;
4507 VARIANT_DecFromDI(&di, &pDecOut[1]);
4508 return S_OK;
4511 /* Add two unsigned 32 bit values with overflow */
4512 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4514 ULARGE_INTEGER ul64;
4516 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4517 *pulHigh = ul64.HighPart;
4518 return ul64.LowPart;
4521 /* Subtract two unsigned 32 bit values with underflow */
4522 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4524 BOOL invert = FALSE;
4525 ULARGE_INTEGER ul64;
4527 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4528 if (ulLeft < ulRight)
4529 invert = TRUE;
4531 if (ul64.QuadPart > (ULONG64)*pulHigh)
4532 ul64.QuadPart -= (ULONG64)*pulHigh;
4533 else
4535 ul64.QuadPart -= (ULONG64)*pulHigh;
4536 invert = TRUE;
4538 if (invert)
4539 ul64.HighPart = -ul64.HighPart ;
4541 *pulHigh = ul64.HighPart;
4542 return ul64.LowPart;
4545 /* Multiply two unsigned 32 bit values with overflow */
4546 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4548 ULARGE_INTEGER ul64;
4550 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4551 *pulHigh = ul64.HighPart;
4552 return ul64.LowPart;
4555 /* Compare two decimals that have the same scale */
4556 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4558 if ( pDecLeft->Hi32 < pDecRight->Hi32 ||
4559 (pDecLeft->Hi32 <= pDecRight->Hi32 && pDecLeft->Lo64 < pDecRight->Lo64))
4560 return -1;
4561 else if (pDecLeft->Hi32 == pDecRight->Hi32 && pDecLeft->Lo64 == pDecRight->Lo64)
4562 return 0;
4563 return 1;
4566 /************************************************************************
4567 * VarDecAdd (OLEAUT32.177)
4569 * Add one DECIMAL to another.
4571 * PARAMS
4572 * pDecLeft [I] Source
4573 * pDecRight [I] Value to add
4574 * pDecOut [O] Destination
4576 * RETURNS
4577 * Success: S_OK.
4578 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4580 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4582 HRESULT hRet;
4583 DECIMAL scaled[2];
4585 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, scaled);
4587 if (SUCCEEDED(hRet))
4589 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4590 ULONG overflow = 0;
4591 BYTE sign = DECIMAL_POS;
4592 int cmp;
4594 /* Correct for the sign of the result */
4595 if (pDecLeft->sign && pDecRight->sign)
4597 /* -x + -y : Negative */
4598 sign = DECIMAL_NEG;
4599 goto VarDecAdd_AsPositive;
4601 else if (pDecLeft->sign && !pDecRight->sign)
4603 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4605 /* -x + y : Negative if x > y */
4606 if (cmp > 0)
4608 sign = DECIMAL_NEG;
4609 VarDecAdd_AsNegative:
4610 pDecOut->Lo32 = VARIANT_Sub(pDecLeft->Lo32, pDecRight->Lo32, &overflow);
4611 pDecOut->Mid32 = VARIANT_Sub(pDecLeft->Mid32, pDecRight->Mid32, &overflow);
4612 pDecOut->Hi32 = VARIANT_Sub(pDecLeft->Hi32, pDecRight->Hi32, &overflow);
4614 else
4616 VarDecAdd_AsInvertedNegative:
4617 pDecOut->Lo32 = VARIANT_Sub(pDecRight->Lo32, pDecLeft->Lo32, &overflow);
4618 pDecOut->Mid32 = VARIANT_Sub(pDecRight->Mid32, pDecLeft->Mid32, &overflow);
4619 pDecOut->Hi32 = VARIANT_Sub(pDecRight->Hi32, pDecLeft->Hi32, &overflow);
4622 else if (!pDecLeft->sign && pDecRight->sign)
4624 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4626 /* x + -y : Negative if x <= y */
4627 if (cmp <= 0)
4629 sign = DECIMAL_NEG;
4630 goto VarDecAdd_AsInvertedNegative;
4632 goto VarDecAdd_AsNegative;
4634 else
4636 /* x + y : Positive */
4637 VarDecAdd_AsPositive:
4638 pDecOut->Lo32 = VARIANT_Add(pDecLeft->Lo32, pDecRight->Lo32, &overflow);
4639 pDecOut->Mid32 = VARIANT_Add(pDecLeft->Mid32, pDecRight->Mid32, &overflow);
4640 pDecOut->Hi32 = VARIANT_Add(pDecLeft->Hi32, pDecRight->Hi32, &overflow);
4642 if (overflow)
4644 int i;
4645 DWORD n[4];
4646 unsigned char remainder;
4648 if (!pDecLeft->scale)
4649 return DISP_E_OVERFLOW;
4651 pDecOut->scale = pDecLeft->scale - 1;
4652 pDecOut->sign = sign;
4654 n[0] = pDecOut->Lo32;
4655 n[1] = pDecOut->Mid32;
4656 n[2] = pDecOut->Hi32;
4657 n[3] = overflow;
4659 remainder = VARIANT_int_divbychar(n,4,10);
4661 /* round up the result */
4662 if (remainder >= 5)
4664 for (remainder = 1, i = 0; i < ARRAY_SIZE(n) && remainder; i++)
4666 ULONGLONG digit = n[i] + 1;
4667 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4668 n[i] = digit & 0xFFFFFFFF;
4672 pDecOut->Lo32 = n[0] ;
4673 pDecOut->Mid32 = n[1];
4674 pDecOut->Hi32 = n[2];
4676 return S_OK;
4680 if (overflow)
4681 return DISP_E_OVERFLOW; /* overflowed */
4683 pDecOut->scale = pDecLeft->scale;
4684 pDecOut->sign = sign;
4686 return hRet;
4689 /* translate from external DECIMAL format into an internal representation */
4690 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4692 to->scale = from->scale;
4693 to->sign = from->sign ? 1 : 0;
4695 to->bitsnum[0] = from->Lo32;
4696 to->bitsnum[1] = from->Mid32;
4697 to->bitsnum[2] = from->Hi32;
4700 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to)
4702 to->sign = from->sign ? DECIMAL_NEG : DECIMAL_POS;
4703 to->scale = from->scale;
4704 to->Lo32 = from->bitsnum[0];
4705 to->Mid32 = from->bitsnum[1];
4706 to->Hi32 = from->bitsnum[2];
4709 /* clear an internal representation of a DECIMAL */
4710 static void VARIANT_DI_clear(VARIANT_DI * i)
4712 memset(i, 0, sizeof(VARIANT_DI));
4715 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4716 size is supported. The value in p is replaced by the quotient of the division, and
4717 the remainder is returned as a result. This routine is most often used with a divisor
4718 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4720 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4722 if (divisor == 0) {
4723 /* division by 0 */
4724 return 0xFF;
4725 } else if (divisor == 1) {
4726 /* dividend remains unchanged */
4727 return 0;
4728 } else {
4729 unsigned char remainder = 0;
4730 ULONGLONG iTempDividend;
4731 signed int i;
4733 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4734 for (; i >= 0; i--) {
4735 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4736 remainder = iTempDividend % divisor;
4737 p[i] = iTempDividend / divisor;
4740 return remainder;
4744 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4745 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n)
4747 for (; n > 0; n--) if (*p++ != 0) return FALSE;
4748 return TRUE;
4751 /* multiply two DECIMALS, without changing either one, and place result in third
4752 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4753 digits when scale > 0 in order to fit an overflowing result. Final overflow
4754 flag is returned.
4756 static int VARIANT_DI_mul(const VARIANT_DI * a, const VARIANT_DI * b, VARIANT_DI * result)
4758 BOOL r_overflow = FALSE;
4759 DWORD running[6];
4760 signed int mulstart;
4762 VARIANT_DI_clear(result);
4763 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4765 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4766 of the result is formed by adding the scales of the operands.
4768 result->scale = a->scale + b->scale;
4769 memset(running, 0, sizeof(running));
4771 /* count number of leading zero-bytes in operand A */
4772 for (mulstart = ARRAY_SIZE(a->bitsnum) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4773 if (mulstart < 0) {
4774 /* result is 0, because operand A is 0 */
4775 result->scale = 0;
4776 result->sign = 0;
4777 } else {
4778 unsigned char remainder = 0;
4779 int iA;
4781 /* perform actual multiplication */
4782 for (iA = 0; iA <= mulstart; iA++) {
4783 ULONG iOverflowMul;
4784 int iB;
4786 for (iOverflowMul = 0, iB = 0; iB < ARRAY_SIZE(b->bitsnum); iB++) {
4787 ULONG iRV;
4788 int iR;
4790 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4791 iR = iA + iB;
4792 do {
4793 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4794 iR++;
4795 } while (iRV);
4799 /* Too bad - native oleaut does not do this, so we should not either */
4800 #if 0
4801 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4802 This operation should not lose significant digits, and gives an
4803 opportunity to reduce the possibility of overflows in future
4804 operations issued by the application.
4806 while (result->scale > 0) {
4807 memcpy(quotient, running, sizeof(quotient));
4808 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4809 if (remainder > 0) break;
4810 memcpy(running, quotient, sizeof(quotient));
4811 result->scale--;
4813 #endif
4814 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4815 This operation *will* lose significant digits of the result because
4816 all the factors of 10 were consumed by the previous operation.
4818 while (result->scale > 0 && !VARIANT_int_iszero(running + ARRAY_SIZE(result->bitsnum),
4819 ARRAY_SIZE(running) - ARRAY_SIZE(result->bitsnum))) {
4821 remainder = VARIANT_int_divbychar(running, ARRAY_SIZE(running), 10);
4822 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4823 result->scale--;
4826 /* round up the result - native oleaut32 does this */
4827 if (remainder >= 5) {
4828 unsigned int i;
4829 for (remainder = 1, i = 0; i < ARRAY_SIZE(running) && remainder; i++) {
4830 ULONGLONG digit = running[i] + 1;
4831 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4832 running[i] = digit & 0xFFFFFFFF;
4836 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4837 and copy result bits into result structure
4839 r_overflow = !VARIANT_int_iszero(running + ARRAY_SIZE(result->bitsnum),
4840 ARRAY_SIZE(running) - ARRAY_SIZE(result->bitsnum));
4841 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4843 return r_overflow;
4846 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4847 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4848 success, FALSE if insufficient space in output buffer.
4850 static BOOL VARIANT_DI_tostringW(const VARIANT_DI * a, WCHAR * s, unsigned int n)
4852 BOOL overflow = FALSE;
4853 DWORD quotient[3];
4854 unsigned char remainder;
4855 unsigned int i;
4857 /* place negative sign */
4858 if (!VARIANT_int_iszero(a->bitsnum, ARRAY_SIZE(a->bitsnum)) && a->sign) {
4859 if (n > 0) {
4860 *s++ = '-';
4861 n--;
4863 else overflow = TRUE;
4866 /* prepare initial 0 */
4867 if (!overflow) {
4868 if (n >= 2) {
4869 s[0] = '0';
4870 s[1] = '\0';
4871 } else overflow = TRUE;
4874 i = 0;
4875 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4876 while (!overflow && !VARIANT_int_iszero(quotient, ARRAY_SIZE(quotient))) {
4877 remainder = VARIANT_int_divbychar(quotient, ARRAY_SIZE(quotient), 10);
4878 if (i + 2 > n) {
4879 overflow = TRUE;
4880 } else {
4881 s[i++] = '0' + remainder;
4882 s[i] = '\0';
4886 if (!overflow && !VARIANT_int_iszero(a->bitsnum, ARRAY_SIZE(a->bitsnum))) {
4888 /* reverse order of digits */
4889 WCHAR * x = s; WCHAR * y = s + i - 1;
4890 while (x < y) {
4891 *x ^= *y;
4892 *y ^= *x;
4893 *x++ ^= *y--;
4896 /* check for decimal point. "i" now has string length */
4897 if (i <= a->scale) {
4898 unsigned int numzeroes = a->scale + 1 - i;
4899 if (i + 1 + numzeroes >= n) {
4900 overflow = TRUE;
4901 } else {
4902 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4903 i += numzeroes;
4904 while (numzeroes > 0) {
4905 s[--numzeroes] = '0';
4910 /* place decimal point */
4911 if (a->scale > 0) {
4912 unsigned int periodpos = i - a->scale;
4913 if (i + 2 >= n) {
4914 overflow = TRUE;
4915 } else {
4916 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4917 s[periodpos] = '.'; i++;
4919 /* remove extra zeros at the end, if any */
4920 while (s[i - 1] == '0') s[--i] = '\0';
4921 if (s[i - 1] == '.') s[--i] = '\0';
4926 return !overflow;
4929 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4930 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4932 DWORD shifted;
4933 unsigned int i;
4935 /* shift whole DWORDs to the left */
4936 while (shift >= 32)
4938 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4939 *p = 0; shift -= 32;
4942 /* shift remainder (1..31 bits) */
4943 shifted = 0;
4944 if (shift > 0) for (i = 0; i < n; i++)
4946 DWORD b;
4947 b = p[i] >> (32 - shift);
4948 p[i] = (p[i] << shift) | shifted;
4949 shifted = b;
4953 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4954 Value at v is incremented by the value at p. Any size is supported, provided
4955 that v is not shorter than p. Any unapplied carry is returned as a result.
4957 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, const DWORD * p,
4958 unsigned int np)
4960 unsigned char carry = 0;
4962 if (nv >= np) {
4963 ULONGLONG sum;
4964 unsigned int i;
4966 for (i = 0; i < np; i++) {
4967 sum = (ULONGLONG)v[i]
4968 + (ULONGLONG)p[i]
4969 + (ULONGLONG)carry;
4970 v[i] = sum & 0xffffffff;
4971 carry = sum >> 32;
4973 for (; i < nv && carry; i++) {
4974 sum = (ULONGLONG)v[i]
4975 + (ULONGLONG)carry;
4976 v[i] = sum & 0xffffffff;
4977 carry = sum >> 32;
4980 return carry;
4983 /* perform integral division with operand p as dividend. Parameter n indicates
4984 number of available DWORDs in divisor p, but available space in p must be
4985 actually at least 2 * n DWORDs, because the remainder of the integral
4986 division is built in the next n DWORDs past the start of the quotient. This
4987 routine replaces the dividend in p with the quotient, and appends n
4988 additional DWORDs for the remainder.
4990 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4991 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4992 source code to the VLI (Very Large Integer) division operator. This algorithm
4993 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4994 variably-scaled integers such as the MS DECIMAL representation.
4996 static void VARIANT_int_div(DWORD * p, unsigned int n, const DWORD * divisor,
4997 unsigned int dn)
4999 unsigned int i;
5000 DWORD tempsub[8];
5001 DWORD * negdivisor = tempsub + n;
5003 /* build 2s-complement of divisor */
5004 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
5005 p[n] = 1;
5006 VARIANT_int_add(negdivisor, n, p + n, 1);
5007 memset(p + n, 0, n * sizeof(DWORD));
5009 /* skip all leading zero DWORDs in quotient */
5010 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
5011 /* i is now number of DWORDs left to process */
5012 for (i <<= 5; i < (n << 5); i++) {
5013 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
5015 /* trial subtraction */
5016 memcpy(tempsub, p + n, n * sizeof(DWORD));
5017 VARIANT_int_add(tempsub, n, negdivisor, n);
5019 /* check whether result of subtraction was negative */
5020 if ((tempsub[n - 1] & 0x80000000) == 0) {
5021 memcpy(p + n, tempsub, n * sizeof(DWORD));
5022 p[0] |= 1;
5027 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
5028 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
5030 unsigned int i;
5031 ULONG iOverflowMul;
5033 for (iOverflowMul = 0, i = 0; i < n; i++)
5034 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
5035 return (unsigned char)iOverflowMul;
5038 /* increment value in A by the value indicated in B, with scale adjusting.
5039 Modifies parameters by adjusting scales. Returns 0 if addition was
5040 successful, nonzero if a parameter underflowed before it could be
5041 successfully used in the addition.
5043 static int VARIANT_int_addlossy(
5044 DWORD * a, int * ascale, unsigned int an,
5045 DWORD * b, int * bscale, unsigned int bn)
5047 int underflow = 0;
5049 if (VARIANT_int_iszero(a, an)) {
5050 /* if A is zero, copy B into A, after removing digits */
5051 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
5052 VARIANT_int_divbychar(b, bn, 10);
5053 (*bscale)--;
5055 memcpy(a, b, an * sizeof(DWORD));
5056 *ascale = *bscale;
5057 } else if (!VARIANT_int_iszero(b, bn)) {
5058 unsigned int tn = an + 1;
5059 DWORD t[5];
5061 if (bn + 1 > tn) tn = bn + 1;
5062 if (*ascale != *bscale) {
5063 /* first (optimistic) try - try to scale down the one with the bigger
5064 scale, while this number is divisible by 10 */
5065 DWORD * digitchosen;
5066 unsigned int nchosen;
5067 int * scalechosen;
5068 int targetscale;
5070 if (*ascale < *bscale) {
5071 targetscale = *ascale;
5072 scalechosen = bscale;
5073 digitchosen = b;
5074 nchosen = bn;
5075 } else {
5076 targetscale = *bscale;
5077 scalechosen = ascale;
5078 digitchosen = a;
5079 nchosen = an;
5081 memset(t, 0, tn * sizeof(DWORD));
5082 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5084 /* divide by 10 until target scale is reached */
5085 while (*scalechosen > targetscale) {
5086 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5087 if (!remainder) {
5088 (*scalechosen)--;
5089 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5090 } else break;
5094 if (*ascale != *bscale) {
5095 DWORD * digitchosen;
5096 unsigned int nchosen;
5097 int * scalechosen;
5098 int targetscale;
5100 /* try to scale up the one with the smaller scale */
5101 if (*ascale > *bscale) {
5102 targetscale = *ascale;
5103 scalechosen = bscale;
5104 digitchosen = b;
5105 nchosen = bn;
5106 } else {
5107 targetscale = *bscale;
5108 scalechosen = ascale;
5109 digitchosen = a;
5110 nchosen = an;
5112 memset(t, 0, tn * sizeof(DWORD));
5113 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5115 /* multiply by 10 until target scale is reached, or
5116 significant bytes overflow the number
5118 while (*scalechosen < targetscale && t[nchosen] == 0) {
5119 VARIANT_int_mulbychar(t, tn, 10);
5120 if (t[nchosen] == 0) {
5121 /* still does not overflow */
5122 (*scalechosen)++;
5123 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5128 if (*ascale != *bscale) {
5129 /* still different? try to scale down the one with the bigger scale
5130 (this *will* lose significant digits) */
5131 DWORD * digitchosen;
5132 unsigned int nchosen;
5133 int * scalechosen;
5134 int targetscale;
5136 if (*ascale < *bscale) {
5137 targetscale = *ascale;
5138 scalechosen = bscale;
5139 digitchosen = b;
5140 nchosen = bn;
5141 } else {
5142 targetscale = *bscale;
5143 scalechosen = ascale;
5144 digitchosen = a;
5145 nchosen = an;
5147 memset(t, 0, tn * sizeof(DWORD));
5148 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5150 /* divide by 10 until target scale is reached */
5151 while (*scalechosen > targetscale) {
5152 VARIANT_int_divbychar(t, tn, 10);
5153 (*scalechosen)--;
5154 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5158 /* check whether any of the operands still has significant digits
5159 (underflow case 1)
5161 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5162 underflow = 1;
5163 } else {
5164 /* at this step, both numbers have the same scale and can be added
5165 as integers. However, the result might not fit in A, so further
5166 scaling down might be necessary.
5168 while (!underflow) {
5169 memset(t, 0, tn * sizeof(DWORD));
5170 memcpy(t, a, an * sizeof(DWORD));
5172 VARIANT_int_add(t, tn, b, bn);
5173 if (VARIANT_int_iszero(t + an, tn - an)) {
5174 /* addition was successful */
5175 memcpy(a, t, an * sizeof(DWORD));
5176 break;
5177 } else {
5178 /* addition overflowed - remove significant digits
5179 from both operands and try again */
5180 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5181 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5182 /* check whether any operand keeps significant digits after
5183 scaledown (underflow case 2)
5185 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5190 return underflow;
5193 /* perform complete DECIMAL division in the internal representation. Returns
5194 0 if the division was completed (even if quotient is set to 0), or nonzero
5195 in case of quotient overflow.
5197 static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * divisor,
5198 VARIANT_DI * quotient, BOOL round_remainder)
5200 HRESULT r_overflow = S_OK;
5202 if (VARIANT_int_iszero(divisor->bitsnum, ARRAY_SIZE(divisor->bitsnum))) {
5203 /* division by 0 */
5204 r_overflow = DISP_E_DIVBYZERO;
5205 } else if (VARIANT_int_iszero(dividend->bitsnum, ARRAY_SIZE(dividend->bitsnum))) {
5206 VARIANT_DI_clear(quotient);
5207 } else {
5208 int quotientscale, remainderscale, tempquotientscale;
5209 DWORD remainderplusquotient[8];
5210 int underflow;
5212 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5213 tempquotientscale = quotientscale;
5214 VARIANT_DI_clear(quotient);
5215 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5217 /* The following strategy is used for division
5218 1) if there was a nonzero remainder from previous iteration, use it as
5219 dividend for this iteration, else (for first iteration) use intended
5220 dividend
5221 2) perform integer division in temporary buffer, develop quotient in
5222 low-order part, remainder in high-order part
5223 3) add quotient from step 2 to final result, with possible loss of
5224 significant digits
5225 4) multiply integer part of remainder by 10, while incrementing the
5226 scale of the remainder. This operation preserves the intended value
5227 of the remainder.
5228 5) loop to step 1 until one of the following is true:
5229 a) remainder is zero (exact division achieved)
5230 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5232 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5233 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5234 do {
5235 VARIANT_int_div(remainderplusquotient, 4, divisor->bitsnum, ARRAY_SIZE(divisor->bitsnum));
5236 underflow = VARIANT_int_addlossy( quotient->bitsnum, &quotientscale,
5237 ARRAY_SIZE(quotient->bitsnum), remainderplusquotient, &tempquotientscale, 4);
5238 if (round_remainder) {
5239 if(remainderplusquotient[4] >= 5){
5240 unsigned int i;
5241 unsigned char remainder = 1;
5242 for (i = 0; i < ARRAY_SIZE(quotient->bitsnum) && remainder; i++) {
5243 ULONGLONG digit = quotient->bitsnum[i] + 1;
5244 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5245 quotient->bitsnum[i] = digit & 0xFFFFFFFF;
5248 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5249 } else {
5250 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5251 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5253 tempquotientscale = ++remainderscale;
5254 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5256 /* quotient scale might now be negative (extremely big number). If, so, try
5257 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5258 until scale is 0. If this cannot be done, it is a real overflow.
5260 while (r_overflow == S_OK && quotientscale < 0) {
5261 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5262 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5263 VARIANT_int_mulbychar(remainderplusquotient, ARRAY_SIZE(remainderplusquotient), 10);
5264 if (VARIANT_int_iszero(remainderplusquotient + ARRAY_SIZE(quotient->bitsnum),
5265 ARRAY_SIZE(remainderplusquotient) - ARRAY_SIZE(quotient->bitsnum))) {
5266 quotientscale++;
5267 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5268 } else r_overflow = DISP_E_OVERFLOW;
5270 if (r_overflow == S_OK) {
5271 if (quotientscale <= 255) quotient->scale = quotientscale;
5272 else VARIANT_DI_clear(quotient);
5275 return r_overflow;
5278 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5279 with an undefined scale, which will be assigned to (if possible). It also
5280 receives an exponent of 2. This procedure will then manipulate the mantissa
5281 and calculate a corresponding scale, so that the exponent2 value is assimilated
5282 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5283 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5284 a DECIMAL. */
5285 static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, BOOL isDouble)
5287 HRESULT hres = S_OK;
5288 int exponent5, exponent10;
5290 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5291 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5292 exponent10 might be used to set the VARIANT_DI scale directly. However,
5293 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5294 exponent5 = -exponent2;
5295 exponent10 = exponent2;
5297 /* Handle exponent5 > 0 */
5298 while (exponent5 > 0) {
5299 char bPrevCarryBit;
5300 char bCurrCarryBit;
5302 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5303 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5304 somehow the mantissa should be divided by 2. */
5305 if ((val->bitsnum[0] & 1) == 0) {
5306 /* The mantissa is divisible by 2. Therefore the division can be done
5307 without losing significant digits. */
5308 exponent10++; exponent5--;
5310 /* Shift right */
5311 bPrevCarryBit = val->bitsnum[2] & 1;
5312 val->bitsnum[2] >>= 1;
5313 bCurrCarryBit = val->bitsnum[1] & 1;
5314 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5315 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5316 } else {
5317 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5318 be multiplied by 5, unless the multiplication overflows. */
5319 DWORD temp_bitsnum[3];
5321 exponent5--;
5323 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5324 if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) {
5325 /* Multiplication succeeded without overflow, so copy result back
5326 into VARIANT_DI */
5327 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5329 /* Mask out 3 extraneous bits introduced by the multiply */
5330 } else {
5331 /* Multiplication by 5 overflows. The mantissa should be divided
5332 by 2, and therefore will lose significant digits. */
5333 exponent10++;
5335 /* Shift right */
5336 bPrevCarryBit = val->bitsnum[2] & 1;
5337 val->bitsnum[2] >>= 1;
5338 bCurrCarryBit = val->bitsnum[1] & 1;
5339 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5340 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5345 /* Handle exponent5 < 0 */
5346 while (exponent5 < 0) {
5347 /* In order to divide the value represented by the VARIANT_DI by 5, it
5348 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5349 and the mantissa should be multiplied by 2 */
5350 if ((val->bitsnum[2] & 0x80000000) == 0) {
5351 /* The mantissa can withstand a shift-left without overflowing */
5352 exponent10--; exponent5++;
5353 VARIANT_int_shiftleft(val->bitsnum, 3, 1);
5354 } else {
5355 /* The mantissa would overflow if shifted. Therefore it should be
5356 directly divided by 5. This will lose significant digits, unless
5357 by chance the mantissa happens to be divisible by 5 */
5358 exponent5++;
5359 VARIANT_int_divbychar(val->bitsnum, 3, 5);
5363 /* At this point, the mantissa has assimilated the exponent5, but the
5364 exponent10 might not be suitable for assignment. The exponent10 must be
5365 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5366 down appropriately. */
5367 while (hres == S_OK && exponent10 > 0) {
5368 /* In order to bring exponent10 down to 0, the mantissa should be
5369 multiplied by 10 to compensate. If the exponent10 is too big, this
5370 will cause the mantissa to overflow. */
5371 if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) {
5372 exponent10--;
5373 } else {
5374 hres = DISP_E_OVERFLOW;
5377 while (exponent10 < -DEC_MAX_SCALE) {
5378 int rem10;
5379 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5380 be divided by 10 to compensate. If the exponent10 is too small, this
5381 will cause the mantissa to underflow and become 0 */
5382 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5383 exponent10++;
5384 if (VARIANT_int_iszero(val->bitsnum, 3)) {
5385 /* Underflow, unable to keep dividing */
5386 exponent10 = 0;
5387 } else if (rem10 >= 5) {
5388 DWORD x = 1;
5389 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5392 /* This step is required in order to remove excess bits of precision from the
5393 end of the bit representation, down to the precision guaranteed by the
5394 floating point number. */
5395 if (isDouble) {
5396 while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[1] & 0xFFE00000) != 0)) {
5397 int rem10;
5399 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5400 exponent10++;
5401 if (rem10 >= 5) {
5402 DWORD x = 1;
5403 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5406 } else {
5407 while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 ||
5408 (val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) {
5409 int rem10;
5411 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5412 exponent10++;
5413 if (rem10 >= 5) {
5414 DWORD x = 1;
5415 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5419 /* Remove multiples of 10 from the representation */
5420 while (exponent10 < 0) {
5421 DWORD temp_bitsnum[3];
5423 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5424 if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) {
5425 exponent10++;
5426 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5427 } else break;
5430 /* Scale assignment */
5431 if (hres == S_OK) val->scale = -exponent10;
5433 return hres;
5436 typedef union
5438 struct
5440 unsigned int m : 23;
5441 unsigned int exp_bias : 8;
5442 unsigned int sign : 1;
5443 } i;
5444 float f;
5445 } R4_FIELDS;
5447 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5448 intermediate string step. */
5449 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest)
5451 HRESULT hres = S_OK;
5452 R4_FIELDS fx;
5454 fx.f = source;
5456 /* Detect special cases */
5457 if (fx.i.m == 0 && fx.i.exp_bias == 0) {
5458 /* Floating-point zero */
5459 VARIANT_DI_clear(dest);
5460 } else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) {
5461 /* Floating-point infinity */
5462 hres = DISP_E_OVERFLOW;
5463 } else if (fx.i.exp_bias == 0xFF) {
5464 /* Floating-point NaN */
5465 hres = DISP_E_BADVARTYPE;
5466 } else {
5467 int exponent2;
5468 VARIANT_DI_clear(dest);
5470 exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */
5471 dest->sign = fx.i.sign; /* Sign is simply copied */
5473 /* Copy significant bits to VARIANT_DI mantissa */
5474 dest->bitsnum[0] = fx.i.m;
5475 dest->bitsnum[0] &= 0x007FFFFF;
5476 if (fx.i.exp_bias == 0) {
5477 /* Denormalized number - correct exponent */
5478 exponent2++;
5479 } else {
5480 /* Add hidden bit to mantissa */
5481 dest->bitsnum[0] |= 0x00800000;
5484 /* The act of copying a FP mantissa as integer bits is equivalent to
5485 shifting left the mantissa 23 bits. The exponent2 is reduced to
5486 compensate. */
5487 exponent2 -= 23;
5489 hres = VARIANT_DI_normalize(dest, exponent2, FALSE);
5492 return hres;
5495 typedef union
5497 struct
5499 unsigned int m_lo : 32; /* 52 bits of precision */
5500 unsigned int m_hi : 20;
5501 unsigned int exp_bias : 11; /* bias == 1023 */
5502 unsigned int sign : 1;
5503 } i;
5504 double d;
5505 } R8_FIELDS;
5507 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5508 intermediate string step. */
5509 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest)
5511 HRESULT hres = S_OK;
5512 R8_FIELDS fx;
5514 fx.d = source;
5516 /* Detect special cases */
5517 if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) {
5518 /* Floating-point zero */
5519 VARIANT_DI_clear(dest);
5520 } else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) {
5521 /* Floating-point infinity */
5522 hres = DISP_E_OVERFLOW;
5523 } else if (fx.i.exp_bias == 0x7FF) {
5524 /* Floating-point NaN */
5525 hres = DISP_E_BADVARTYPE;
5526 } else {
5527 int exponent2;
5528 VARIANT_DI_clear(dest);
5530 exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */
5531 dest->sign = fx.i.sign; /* Sign is simply copied */
5533 /* Copy significant bits to VARIANT_DI mantissa */
5534 dest->bitsnum[0] = fx.i.m_lo;
5535 dest->bitsnum[1] = fx.i.m_hi;
5536 dest->bitsnum[1] &= 0x000FFFFF;
5537 if (fx.i.exp_bias == 0) {
5538 /* Denormalized number - correct exponent */
5539 exponent2++;
5540 } else {
5541 /* Add hidden bit to mantissa */
5542 dest->bitsnum[1] |= 0x00100000;
5545 /* The act of copying a FP mantissa as integer bits is equivalent to
5546 shifting left the mantissa 52 bits. The exponent2 is reduced to
5547 compensate. */
5548 exponent2 -= 52;
5550 hres = VARIANT_DI_normalize(dest, exponent2, TRUE);
5553 return hres;
5556 static HRESULT VARIANT_do_division(const DECIMAL *pDecLeft, const DECIMAL *pDecRight, DECIMAL *pDecOut,
5557 BOOL round)
5559 HRESULT hRet = S_OK;
5560 VARIANT_DI di_left, di_right, di_result;
5561 HRESULT divresult;
5563 VARIANT_DIFromDec(pDecLeft, &di_left);
5564 VARIANT_DIFromDec(pDecRight, &di_right);
5565 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result, round);
5566 if (divresult != S_OK)
5568 /* division actually overflowed */
5569 hRet = divresult;
5571 else
5573 hRet = S_OK;
5575 if (di_result.scale > DEC_MAX_SCALE)
5577 unsigned char remainder = 0;
5579 /* division underflowed. In order to comply with the MSDN
5580 specifications for DECIMAL ranges, some significant digits
5581 must be removed
5583 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5584 di_result.scale);
5585 while (di_result.scale > DEC_MAX_SCALE &&
5586 !VARIANT_int_iszero(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum)))
5588 remainder = VARIANT_int_divbychar(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum), 10);
5589 di_result.scale--;
5591 if (di_result.scale > DEC_MAX_SCALE)
5593 WARN("result underflowed, setting to 0\n");
5594 di_result.scale = 0;
5595 di_result.sign = 0;
5597 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5599 unsigned int i;
5600 for (remainder = 1, i = 0; i < ARRAY_SIZE(di_result.bitsnum) && remainder; i++) {
5601 ULONGLONG digit = di_result.bitsnum[i] + 1;
5602 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5603 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5607 VARIANT_DecFromDI(&di_result, pDecOut);
5609 return hRet;
5612 /************************************************************************
5613 * VarDecDiv (OLEAUT32.178)
5615 * Divide one DECIMAL by another.
5617 * PARAMS
5618 * pDecLeft [I] Source
5619 * pDecRight [I] Value to divide by
5620 * pDecOut [O] Destination
5622 * RETURNS
5623 * Success: S_OK.
5624 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5626 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5628 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5630 return VARIANT_do_division(pDecLeft, pDecRight, pDecOut, FALSE);
5633 /************************************************************************
5634 * VarDecMul (OLEAUT32.179)
5636 * Multiply one DECIMAL by another.
5638 * PARAMS
5639 * pDecLeft [I] Source
5640 * pDecRight [I] Value to multiply by
5641 * pDecOut [O] Destination
5643 * RETURNS
5644 * Success: S_OK.
5645 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5647 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5649 HRESULT hRet = S_OK;
5650 VARIANT_DI di_left, di_right, di_result;
5651 int mulresult;
5653 VARIANT_DIFromDec(pDecLeft, &di_left);
5654 VARIANT_DIFromDec(pDecRight, &di_right);
5655 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5656 if (mulresult)
5658 /* multiplication actually overflowed */
5659 hRet = DISP_E_OVERFLOW;
5661 else
5663 if (di_result.scale > DEC_MAX_SCALE)
5665 /* multiplication underflowed. In order to comply with the MSDN
5666 specifications for DECIMAL ranges, some significant digits
5667 must be removed
5669 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5670 di_result.scale);
5671 while (di_result.scale > DEC_MAX_SCALE &&
5672 !VARIANT_int_iszero(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum)))
5674 VARIANT_int_divbychar(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum), 10);
5675 di_result.scale--;
5677 if (di_result.scale > DEC_MAX_SCALE)
5679 WARN("result underflowed, setting to 0\n");
5680 di_result.scale = 0;
5681 di_result.sign = 0;
5684 VARIANT_DecFromDI(&di_result, pDecOut);
5686 return hRet;
5689 /************************************************************************
5690 * VarDecSub (OLEAUT32.181)
5692 * Subtract one DECIMAL from another.
5694 * PARAMS
5695 * pDecLeft [I] Source
5696 * pDecRight [I] DECIMAL to subtract from pDecLeft
5697 * pDecOut [O] Destination
5699 * RETURNS
5700 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5702 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5704 DECIMAL decRight;
5706 /* Implement as addition of the negative */
5707 VarDecNeg(pDecRight, &decRight);
5708 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5711 /************************************************************************
5712 * VarDecAbs (OLEAUT32.182)
5714 * Convert a DECIMAL into its absolute value.
5716 * PARAMS
5717 * pDecIn [I] Source
5718 * pDecOut [O] Destination
5720 * RETURNS
5721 * S_OK. This function does not fail.
5723 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5725 *pDecOut = *pDecIn;
5726 pDecOut->sign &= ~DECIMAL_NEG;
5727 return S_OK;
5730 /************************************************************************
5731 * VarDecFix (OLEAUT32.187)
5733 * Return the integer portion of a DECIMAL.
5735 * PARAMS
5736 * pDecIn [I] Source
5737 * pDecOut [O] Destination
5739 * RETURNS
5740 * Success: S_OK.
5741 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5743 * NOTES
5744 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5745 * negative numbers away from 0, while this function rounds them towards zero.
5747 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5749 double dbl;
5750 HRESULT hr;
5752 if (pDecIn->sign & ~DECIMAL_NEG)
5753 return E_INVALIDARG;
5755 if (!pDecIn->scale)
5757 *pDecOut = *pDecIn; /* Already an integer */
5758 return S_OK;
5761 hr = VarR8FromDec(pDecIn, &dbl);
5762 if (SUCCEEDED(hr)) {
5763 LONGLONG rounded = dbl;
5765 hr = VarDecFromI8(rounded, pDecOut);
5767 return hr;
5770 /************************************************************************
5771 * VarDecInt (OLEAUT32.188)
5773 * Return the integer portion of a DECIMAL.
5775 * PARAMS
5776 * pDecIn [I] Source
5777 * pDecOut [O] Destination
5779 * RETURNS
5780 * Success: S_OK.
5781 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5783 * NOTES
5784 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5785 * negative numbers towards 0, while this function rounds them away from zero.
5787 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5789 double dbl;
5790 HRESULT hr;
5792 if (pDecIn->sign & ~DECIMAL_NEG)
5793 return E_INVALIDARG;
5795 if (!(pDecIn->sign & DECIMAL_NEG) || !pDecIn->scale)
5796 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5798 hr = VarR8FromDec(pDecIn, &dbl);
5799 if (SUCCEEDED(hr)) {
5800 LONGLONG rounded = dbl >= 0.0 ? dbl + 0.5 : dbl - 0.5;
5802 hr = VarDecFromI8(rounded, pDecOut);
5804 return hr;
5807 /************************************************************************
5808 * VarDecNeg (OLEAUT32.189)
5810 * Change the sign of a DECIMAL.
5812 * PARAMS
5813 * pDecIn [I] Source
5814 * pDecOut [O] Destination
5816 * RETURNS
5817 * S_OK. This function does not fail.
5819 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5821 *pDecOut = *pDecIn;
5822 pDecOut->sign ^= DECIMAL_NEG;
5823 return S_OK;
5826 /************************************************************************
5827 * VarDecRound (OLEAUT32.203)
5829 * Change the precision of a DECIMAL.
5831 * PARAMS
5832 * pDecIn [I] Source
5833 * cDecimals [I] New number of decimals to keep
5834 * pDecOut [O] Destination
5836 * RETURNS
5837 * Success: S_OK. pDecOut contains the rounded value.
5838 * Failure: E_INVALIDARG if any argument is invalid.
5840 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5842 DECIMAL divisor, tmp;
5843 HRESULT hr;
5844 unsigned int i;
5846 if (cDecimals < 0 || (pDecIn->sign & ~DECIMAL_NEG) || pDecIn->scale > DEC_MAX_SCALE)
5847 return E_INVALIDARG;
5849 if (cDecimals >= pDecIn->scale)
5851 *pDecOut = *pDecIn; /* More precision than we have */
5852 return S_OK;
5855 /* truncate significant digits and rescale */
5856 memset(&divisor, 0, sizeof(divisor));
5857 divisor.Lo64 = 1;
5859 memset(&tmp, 0, sizeof(tmp));
5860 tmp.Lo64 = 10;
5861 for (i = 0; i < pDecIn->scale - cDecimals; ++i)
5863 hr = VarDecMul(&divisor, &tmp, &divisor);
5864 if (FAILED(hr))
5865 return hr;
5868 hr = VARIANT_do_division(pDecIn, &divisor, pDecOut, TRUE);
5869 if (FAILED(hr))
5870 return hr;
5872 pDecOut->scale = cDecimals;
5874 return S_OK;
5877 /************************************************************************
5878 * VarDecCmp (OLEAUT32.204)
5880 * Compare two DECIMAL values.
5882 * PARAMS
5883 * pDecLeft [I] Source
5884 * pDecRight [I] Value to compare
5886 * RETURNS
5887 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5888 * is less than, equal to or greater than pDecRight respectively.
5889 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5891 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5893 HRESULT hRet;
5894 DECIMAL result;
5896 if (!pDecLeft || !pDecRight)
5897 return VARCMP_NULL;
5899 if ((!(pDecLeft->sign & DECIMAL_NEG)) && (pDecRight->sign & DECIMAL_NEG) &&
5900 (pDecLeft->Hi32 || pDecLeft->Lo64))
5901 return VARCMP_GT;
5902 else if ((pDecLeft->sign & DECIMAL_NEG) && (!(pDecRight->sign & DECIMAL_NEG)) &&
5903 (pDecLeft->Hi32 || pDecLeft->Lo64))
5904 return VARCMP_LT;
5906 /* Subtract right from left, and compare the result to 0 */
5907 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5909 if (SUCCEEDED(hRet))
5911 int non_zero = result.Hi32 || result.Lo64;
5913 if ((result.sign & DECIMAL_NEG) && non_zero)
5914 hRet = (HRESULT)VARCMP_LT;
5915 else if (non_zero)
5916 hRet = (HRESULT)VARCMP_GT;
5917 else
5918 hRet = (HRESULT)VARCMP_EQ;
5920 return hRet;
5923 /************************************************************************
5924 * VarDecCmpR8 (OLEAUT32.298)
5926 * Compare a DECIMAL to a double
5928 * PARAMS
5929 * pDecLeft [I] DECIMAL Source
5930 * dblRight [I] double to compare to pDecLeft
5932 * RETURNS
5933 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5934 * is less than, equal to or greater than pDecLeft respectively.
5935 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5937 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5939 HRESULT hRet;
5940 DECIMAL decRight;
5942 hRet = VarDecFromR8(dblRight, &decRight);
5944 if (SUCCEEDED(hRet))
5945 hRet = VarDecCmp(pDecLeft, &decRight);
5947 return hRet;
5950 /* BOOL
5953 /************************************************************************
5954 * VarBoolFromUI1 (OLEAUT32.118)
5956 * Convert a VT_UI1 to a VT_BOOL.
5958 * PARAMS
5959 * bIn [I] Source
5960 * pBoolOut [O] Destination
5962 * RETURNS
5963 * S_OK.
5965 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5967 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5968 return S_OK;
5971 /************************************************************************
5972 * VarBoolFromI2 (OLEAUT32.119)
5974 * Convert a VT_I2 to a VT_BOOL.
5976 * PARAMS
5977 * sIn [I] Source
5978 * pBoolOut [O] Destination
5980 * RETURNS
5981 * S_OK.
5983 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5985 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5986 return S_OK;
5989 /************************************************************************
5990 * VarBoolFromI4 (OLEAUT32.120)
5992 * Convert a VT_I4 to a VT_BOOL.
5994 * PARAMS
5995 * sIn [I] Source
5996 * pBoolOut [O] Destination
5998 * RETURNS
5999 * S_OK.
6001 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
6003 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
6004 return S_OK;
6007 /************************************************************************
6008 * VarBoolFromR4 (OLEAUT32.121)
6010 * Convert a VT_R4 to a VT_BOOL.
6012 * PARAMS
6013 * fltIn [I] Source
6014 * pBoolOut [O] Destination
6016 * RETURNS
6017 * S_OK.
6019 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
6021 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
6022 return S_OK;
6025 /************************************************************************
6026 * VarBoolFromR8 (OLEAUT32.122)
6028 * Convert a VT_R8 to a VT_BOOL.
6030 * PARAMS
6031 * dblIn [I] Source
6032 * pBoolOut [O] Destination
6034 * RETURNS
6035 * S_OK.
6037 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
6039 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
6040 return S_OK;
6043 /************************************************************************
6044 * VarBoolFromDate (OLEAUT32.123)
6046 * Convert a VT_DATE to a VT_BOOL.
6048 * PARAMS
6049 * dateIn [I] Source
6050 * pBoolOut [O] Destination
6052 * RETURNS
6053 * S_OK.
6055 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
6057 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
6058 return S_OK;
6061 /************************************************************************
6062 * VarBoolFromCy (OLEAUT32.124)
6064 * Convert a VT_CY to a VT_BOOL.
6066 * PARAMS
6067 * cyIn [I] Source
6068 * pBoolOut [O] Destination
6070 * RETURNS
6071 * S_OK.
6073 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
6075 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
6076 return S_OK;
6079 /************************************************************************
6080 * VARIANT_GetLocalisedText [internal]
6082 * Get a localized string from the resources
6085 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
6087 HRSRC hrsrc;
6089 hrsrc = FindResourceExW( hProxyDll, (LPWSTR)RT_STRING,
6090 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
6091 if (hrsrc)
6093 HGLOBAL hmem = LoadResource( hProxyDll, hrsrc );
6095 if (hmem)
6097 const WCHAR *p;
6098 unsigned int i;
6100 p = LockResource( hmem );
6101 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
6103 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
6104 lpszDest[*p] = '\0';
6105 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
6106 return TRUE;
6109 return FALSE;
6112 /************************************************************************
6113 * VarBoolFromStr (OLEAUT32.125)
6115 * Convert a VT_BSTR to a VT_BOOL.
6117 * PARAMS
6118 * strIn [I] Source
6119 * lcid [I] LCID for the conversion
6120 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6121 * pBoolOut [O] Destination
6123 * RETURNS
6124 * Success: S_OK.
6125 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6126 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6128 * NOTES
6129 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6130 * it may contain (in any case mapping) the text "true" or "false".
6131 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6132 * localised text of "True" or "False" in the language specified by lcid.
6133 * - If none of these matches occur, the string is treated as a numeric string
6134 * and the boolean pBoolOut will be set according to whether the number is zero
6135 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6136 * - If the text is not numeric and does not match any of the above, then
6137 * DISP_E_TYPEMISMATCH is returned.
6139 HRESULT WINAPI VarBoolFromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
6141 WCHAR szBuff[64];
6142 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6143 HRESULT hRes = S_OK;
6145 if (!strIn || !pBoolOut)
6146 return DISP_E_TYPEMISMATCH;
6148 /* Check if we should be comparing against localised text */
6149 if (dwFlags & VAR_LOCALBOOL)
6151 /* Convert our LCID into a usable value */
6152 lcid = ConvertDefaultLocale(lcid);
6154 langId = LANGIDFROMLCID(lcid);
6156 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6157 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6159 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6160 * I don't think this is needed unless any of the localised text strings
6161 * contain characters that can be so mapped. In the event that this is
6162 * true for a given language (possibly some Asian languages), then strIn
6163 * should be mapped here _only_ if langId is an Id for which this can occur.
6167 /* Note that if we are not comparing against localised strings, langId
6168 * will have its default value of LANG_ENGLISH. This allows us to mimic
6169 * the native behaviour of always checking against English strings even
6170 * after we've checked for localised ones.
6172 VarBoolFromStr_CheckLocalised:
6173 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
6175 /* Compare against localised strings, ignoring case */
6176 if (!wcsicmp(strIn, szBuff))
6178 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
6179 return hRes;
6181 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
6182 if (!wcsicmp(strIn, szBuff))
6184 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
6185 return hRes;
6189 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6191 /* We have checked the localised text, now check English */
6192 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6193 goto VarBoolFromStr_CheckLocalised;
6196 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6197 if (!wcscmp(strIn, L"#FALSE#"))
6198 *pBoolOut = VARIANT_FALSE;
6199 else if (!wcscmp(strIn, L"#TRUE#"))
6200 *pBoolOut = VARIANT_TRUE;
6201 else
6203 double d;
6205 /* If this string is a number, convert it as one */
6206 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
6207 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
6209 return hRes;
6212 /************************************************************************
6213 * VarBoolFromDisp (OLEAUT32.126)
6215 * Convert a VT_DISPATCH to a VT_BOOL.
6217 * PARAMS
6218 * pdispIn [I] Source
6219 * lcid [I] LCID for conversion
6220 * pBoolOut [O] Destination
6222 * RETURNS
6223 * Success: S_OK.
6224 * Failure: E_INVALIDARG, if the source value is invalid
6225 * DISP_E_OVERFLOW, if the value will not fit in the destination
6226 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6228 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
6230 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
6233 /************************************************************************
6234 * VarBoolFromI1 (OLEAUT32.233)
6236 * Convert a VT_I1 to a VT_BOOL.
6238 * PARAMS
6239 * cIn [I] Source
6240 * pBoolOut [O] Destination
6242 * RETURNS
6243 * S_OK.
6245 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
6247 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
6248 return S_OK;
6251 /************************************************************************
6252 * VarBoolFromUI2 (OLEAUT32.234)
6254 * Convert a VT_UI2 to a VT_BOOL.
6256 * PARAMS
6257 * usIn [I] Source
6258 * pBoolOut [O] Destination
6260 * RETURNS
6261 * S_OK.
6263 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
6265 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
6266 return S_OK;
6269 /************************************************************************
6270 * VarBoolFromUI4 (OLEAUT32.235)
6272 * Convert a VT_UI4 to a VT_BOOL.
6274 * PARAMS
6275 * ulIn [I] Source
6276 * pBoolOut [O] Destination
6278 * RETURNS
6279 * S_OK.
6281 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
6283 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
6284 return S_OK;
6287 /************************************************************************
6288 * VarBoolFromDec (OLEAUT32.236)
6290 * Convert a VT_DECIMAL to a VT_BOOL.
6292 * PARAMS
6293 * pDecIn [I] Source
6294 * pBoolOut [O] Destination
6296 * RETURNS
6297 * Success: S_OK.
6298 * Failure: E_INVALIDARG, if pDecIn is invalid.
6300 HRESULT WINAPI VarBoolFromDec(const DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
6302 if (pDecIn->scale > DEC_MAX_SCALE || (pDecIn->sign & ~DECIMAL_NEG))
6303 return E_INVALIDARG;
6305 if (pDecIn->Hi32 || pDecIn->Lo64)
6306 *pBoolOut = VARIANT_TRUE;
6307 else
6308 *pBoolOut = VARIANT_FALSE;
6309 return S_OK;
6312 /************************************************************************
6313 * VarBoolFromI8 (OLEAUT32.370)
6315 * Convert a VT_I8 to a VT_BOOL.
6317 * PARAMS
6318 * ullIn [I] Source
6319 * pBoolOut [O] Destination
6321 * RETURNS
6322 * S_OK.
6324 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
6326 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
6327 return S_OK;
6330 /************************************************************************
6331 * VarBoolFromUI8 (OLEAUT32.371)
6333 * Convert a VT_UI8 to a VT_BOOL.
6335 * PARAMS
6336 * ullIn [I] Source
6337 * pBoolOut [O] Destination
6339 * RETURNS
6340 * S_OK.
6342 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
6344 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
6345 return S_OK;
6348 /* BSTR
6351 /* Write a number from a UI8 and sign */
6352 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
6356 WCHAR ulNextDigit = ulVal % 10;
6358 *szOut-- = '0' + ulNextDigit;
6359 ulVal = (ulVal - ulNextDigit) / 10;
6360 } while (ulVal);
6362 szOut++;
6363 return szOut;
6366 /* Create a (possibly localised) BSTR from a UI8 and sign */
6367 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
6369 WCHAR szConverted[256];
6371 if (dwFlags & VAR_NEGATIVE)
6372 *--szOut = '-';
6374 if (dwFlags & LOCALE_USE_NLS)
6376 /* Format the number for the locale */
6377 szConverted[0] = '\0';
6378 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6379 szOut, NULL, szConverted, ARRAY_SIZE(szConverted));
6380 szOut = szConverted;
6382 return SysAllocStringByteLen((LPCSTR)szOut, lstrlenW(szOut) * sizeof(WCHAR));
6385 /* Create a (possibly localised) BSTR from a UI8 and sign */
6386 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
6388 WCHAR szBuff[64], *szOut = szBuff + ARRAY_SIZE(szBuff) - 1;
6390 if (!pbstrOut)
6391 return E_INVALIDARG;
6393 /* Create the basic number string */
6394 *szOut-- = '\0';
6395 szOut = VARIANT_WriteNumber(ulVal, szOut);
6397 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
6398 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6399 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6402 /******************************************************************************
6403 * VarBstrFromUI1 (OLEAUT32.108)
6405 * Convert a VT_UI1 to a VT_BSTR.
6407 * PARAMS
6408 * bIn [I] Source
6409 * lcid [I] LCID for the conversion
6410 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6411 * pbstrOut [O] Destination
6413 * RETURNS
6414 * Success: S_OK.
6415 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6416 * E_OUTOFMEMORY, if memory allocation fails.
6418 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6420 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6423 /******************************************************************************
6424 * VarBstrFromI2 (OLEAUT32.109)
6426 * Convert a VT_I2 to a VT_BSTR.
6428 * PARAMS
6429 * sIn [I] Source
6430 * lcid [I] LCID for the conversion
6431 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6432 * pbstrOut [O] Destination
6434 * RETURNS
6435 * Success: S_OK.
6436 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6437 * E_OUTOFMEMORY, if memory allocation fails.
6439 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6441 ULONG64 ul64 = sIn;
6443 if (sIn < 0)
6445 ul64 = -sIn;
6446 dwFlags |= VAR_NEGATIVE;
6448 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6451 /******************************************************************************
6452 * VarBstrFromI4 (OLEAUT32.110)
6454 * Convert a VT_I4 to a VT_BSTR.
6456 * PARAMS
6457 * lIn [I] Source
6458 * lcid [I] LCID for the conversion
6459 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6460 * pbstrOut [O] Destination
6462 * RETURNS
6463 * Success: S_OK.
6464 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6465 * E_OUTOFMEMORY, if memory allocation fails.
6467 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6469 ULONG64 ul64 = lIn;
6471 if (lIn < 0)
6473 ul64 = -(LONG64)lIn;
6474 dwFlags |= VAR_NEGATIVE;
6476 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6479 static BSTR VARIANT_BstrReplaceDecimal(const WCHAR * buff, LCID lcid, ULONG dwFlags)
6481 BSTR bstrOut;
6482 WCHAR lpDecimalSep[16];
6484 /* Native oleaut32 uses the locale-specific decimal separator even in the
6485 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6486 American locales will see "one thousand and one tenth" as "1000,1"
6487 instead of "1000.1" (notice the comma). The following code checks for
6488 the need to replace the decimal separator, and if so, will prepare an
6489 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6491 GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE),
6492 lpDecimalSep, ARRAY_SIZE(lpDecimalSep));
6493 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6495 /* locale is compatible with English - return original string */
6496 bstrOut = SysAllocString(buff);
6498 else
6500 WCHAR *p;
6501 WCHAR numbuff[256];
6502 WCHAR empty[] = L"";
6503 NUMBERFMTW minFormat;
6505 minFormat.NumDigits = 0;
6506 minFormat.Grouping = 0;
6507 minFormat.lpDecimalSep = lpDecimalSep;
6508 minFormat.lpThousandSep = empty;
6509 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6511 GetLocaleInfoW(lcid, LOCALE_ILZERO | LOCALE_RETURN_NUMBER | (dwFlags & LOCALE_NOUSEROVERRIDE),
6512 (WCHAR *)&minFormat.LeadingZero, sizeof(DWORD)/sizeof(WCHAR) );
6514 /* count number of decimal digits in string */
6515 p = wcschr( buff, '.' );
6516 if (p) minFormat.NumDigits = lstrlenW(p + 1);
6518 numbuff[0] = '\0';
6519 if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, ARRAY_SIZE(numbuff)))
6521 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6522 bstrOut = SysAllocString(buff);
6524 else
6526 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6527 bstrOut = SysAllocString(numbuff);
6530 return bstrOut;
6533 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6534 BSTR* pbstrOut, LPCWSTR lpszFormat)
6536 _locale_t locale;
6537 WCHAR buff[256];
6539 if (!pbstrOut)
6540 return E_INVALIDARG;
6542 if (!(locale = _create_locale(LC_ALL, "C"))) return E_OUTOFMEMORY;
6543 _swprintf_l(buff, ARRAY_SIZE(buff), lpszFormat, locale, dblIn);
6544 _free_locale(locale);
6546 /* Negative zeroes are disallowed (some applications depend on this).
6547 If buff starts with a minus, and then nothing follows but zeroes
6548 and/or a period, it is a negative zero and is replaced with a
6549 canonical zero. This duplicates native oleaut32 behavior.
6551 if (buff[0] == '-')
6553 if (lstrlenW(buff + 1) == wcsspn(buff + 1, L"0."))
6554 { buff[0] = '0'; buff[1] = '\0'; }
6557 TRACE("created string %s\n", debugstr_w(buff));
6558 if (dwFlags & LOCALE_USE_NLS)
6560 WCHAR numbuff[256];
6562 /* Format the number for the locale */
6563 numbuff[0] = '\0';
6564 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6565 buff, NULL, numbuff, ARRAY_SIZE(numbuff));
6566 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6567 *pbstrOut = SysAllocString(numbuff);
6569 else
6571 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6573 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6576 /******************************************************************************
6577 * VarBstrFromR4 (OLEAUT32.111)
6579 * Convert a VT_R4 to a VT_BSTR.
6581 * PARAMS
6582 * fltIn [I] Source
6583 * lcid [I] LCID for the conversion
6584 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6585 * pbstrOut [O] Destination
6587 * RETURNS
6588 * Success: S_OK.
6589 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6590 * E_OUTOFMEMORY, if memory allocation fails.
6592 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6594 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, L"%.7G");
6597 /******************************************************************************
6598 * VarBstrFromR8 (OLEAUT32.112)
6600 * Convert a VT_R8 to a VT_BSTR.
6602 * PARAMS
6603 * dblIn [I] Source
6604 * lcid [I] LCID for the conversion
6605 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6606 * pbstrOut [O] Destination
6608 * RETURNS
6609 * Success: S_OK.
6610 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6611 * E_OUTOFMEMORY, if memory allocation fails.
6613 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6615 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, L"%.15G");
6618 /******************************************************************************
6619 * VarBstrFromCy [OLEAUT32.113]
6621 * Convert a VT_CY to a VT_BSTR.
6623 * PARAMS
6624 * cyIn [I] Source
6625 * lcid [I] LCID for the conversion
6626 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6627 * pbstrOut [O] Destination
6629 * RETURNS
6630 * Success: S_OK.
6631 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6632 * E_OUTOFMEMORY, if memory allocation fails.
6634 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6636 WCHAR buff[256];
6637 VARIANT_DI decVal;
6639 if (!pbstrOut)
6640 return E_INVALIDARG;
6642 decVal.scale = 4;
6643 decVal.sign = 0;
6644 decVal.bitsnum[0] = cyIn.Lo;
6645 decVal.bitsnum[1] = cyIn.Hi;
6646 if (cyIn.Hi & 0x80000000UL) {
6647 DWORD one = 1;
6649 /* Negative number! */
6650 decVal.sign = 1;
6651 decVal.bitsnum[0] = ~decVal.bitsnum[0];
6652 decVal.bitsnum[1] = ~decVal.bitsnum[1];
6653 VARIANT_int_add(decVal.bitsnum, 3, &one, 1);
6655 decVal.bitsnum[2] = 0;
6656 VARIANT_DI_tostringW(&decVal, buff, ARRAY_SIZE(buff));
6658 if (dwFlags & LOCALE_USE_NLS)
6660 WCHAR cybuff[256];
6662 /* Format the currency for the locale */
6663 cybuff[0] = '\0';
6664 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6665 buff, NULL, cybuff, ARRAY_SIZE(cybuff));
6666 *pbstrOut = SysAllocString(cybuff);
6668 else
6669 *pbstrOut = VARIANT_BstrReplaceDecimal(buff,lcid,dwFlags);
6671 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6674 static inline int output_int_len(int o, int min_len, WCHAR *date, int date_len)
6676 int len, tmp;
6678 if(min_len >= date_len)
6679 return -1;
6681 for(len=0, tmp=o; tmp; tmp/=10) len++;
6682 if(!len) len++;
6683 if(len >= date_len)
6684 return -1;
6686 for(tmp=min_len-len; tmp>0; tmp--)
6687 *date++ = '0';
6688 for(tmp=len; tmp>0; tmp--, o/=10)
6689 date[tmp-1] = '0' + o%10;
6690 return min_len>len ? min_len : len;
6693 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6694 BOOL get_date_format(LCID lcid, DWORD flags, const SYSTEMTIME *st,
6695 const WCHAR *fmt, WCHAR *date, int date_len)
6697 static const LCTYPE dayname[] = {
6698 LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
6699 LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6
6701 static const LCTYPE sdayname[] = {
6702 LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
6703 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
6704 LOCALE_SABBREVDAYNAME6
6706 static const LCTYPE monthname[] = {
6707 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
6708 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
6709 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12
6711 static const LCTYPE smonthname[] = {
6712 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
6713 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
6714 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
6715 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12
6718 if(flags & ~(LOCALE_NOUSEROVERRIDE|VAR_DATEVALUEONLY))
6719 FIXME("ignoring flags %lx\n", flags);
6720 flags &= LOCALE_NOUSEROVERRIDE;
6722 while(*fmt && date_len) {
6723 int count = 1;
6725 switch(*fmt) {
6726 case 'd':
6727 case 'M':
6728 case 'y':
6729 case 'g':
6730 while(*fmt == *(fmt+count))
6731 count++;
6732 fmt += count-1;
6735 switch(*fmt) {
6736 case 'd':
6737 if(count >= 4)
6738 count = GetLocaleInfoW(lcid, dayname[st->wDayOfWeek] | flags, date, date_len)-1;
6739 else if(count == 3)
6740 count = GetLocaleInfoW(lcid, sdayname[st->wDayOfWeek] | flags, date, date_len)-1;
6741 else
6742 count = output_int_len(st->wDay, count, date, date_len);
6743 break;
6744 case 'M':
6745 if(count >= 4)
6746 count = GetLocaleInfoW(lcid, monthname[st->wMonth-1] | flags, date, date_len)-1;
6747 else if(count == 3)
6748 count = GetLocaleInfoW(lcid, smonthname[st->wMonth-1] | flags, date, date_len)-1;
6749 else
6750 count = output_int_len(st->wMonth, count, date, date_len);
6751 break;
6752 case 'y':
6753 if(count >= 3)
6754 count = output_int_len(st->wYear, 0, date, date_len);
6755 else
6756 count = output_int_len(st->wYear%100, count, date, date_len);
6757 break;
6758 case 'g':
6759 if(count == 2) {
6760 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6762 *date++ = 'A';
6763 date_len--;
6764 if(date_len)
6765 *date = 'D';
6766 else
6767 count = -1;
6768 break;
6770 /* fall through */
6771 default:
6772 *date = *fmt;
6775 if(count < 0)
6776 break;
6777 fmt++;
6778 date += count;
6779 date_len -= count;
6782 if(!date_len)
6783 return FALSE;
6784 *date++ = 0;
6785 return TRUE;
6788 /******************************************************************************
6789 * VarBstrFromDate [OLEAUT32.114]
6791 * Convert a VT_DATE to a VT_BSTR.
6793 * PARAMS
6794 * dateIn [I] Source
6795 * lcid [I] LCID for the conversion
6796 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6797 * pbstrOut [O] Destination
6799 * RETURNS
6800 * Success: S_OK.
6801 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6802 * E_OUTOFMEMORY, if memory allocation fails.
6804 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6806 SYSTEMTIME st;
6807 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6808 WCHAR date[128], fmt_buff[80], *time;
6810 TRACE("%g, %#lx, %#lx, %p.\n", dateIn, lcid, dwFlags, pbstrOut);
6812 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6813 return E_INVALIDARG;
6815 *pbstrOut = NULL;
6817 if (dwFlags & VAR_CALENDAR_THAI)
6818 st.wYear += 553; /* Use the Thai buddhist calendar year */
6819 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6820 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6822 if (dwFlags & LOCALE_USE_NLS)
6823 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6824 else
6826 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6827 double partial = dateIn - whole;
6829 if (whole == 0.0)
6830 dwFlags |= VAR_TIMEVALUEONLY;
6831 else if (partial > -1e-12 && partial < 1e-12)
6832 dwFlags |= VAR_DATEVALUEONLY;
6835 if (dwFlags & VAR_TIMEVALUEONLY)
6836 date[0] = '\0';
6837 else
6838 if (!GetLocaleInfoW(lcid, LOCALE_SSHORTDATE, fmt_buff, ARRAY_SIZE(fmt_buff)) ||
6839 !get_date_format(lcid, dwFlags, &st, fmt_buff, date, ARRAY_SIZE(date)))
6840 return E_INVALIDARG;
6842 if (!(dwFlags & VAR_DATEVALUEONLY))
6844 time = date + lstrlenW(date);
6845 if (time != date)
6846 *time++ = ' ';
6847 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time, ARRAY_SIZE(date)-(time-date)))
6848 return E_INVALIDARG;
6851 *pbstrOut = SysAllocString(date);
6852 if (*pbstrOut)
6853 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6854 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6857 /******************************************************************************
6858 * VarBstrFromBool (OLEAUT32.116)
6860 * Convert a VT_BOOL to a VT_BSTR.
6862 * PARAMS
6863 * boolIn [I] Source
6864 * lcid [I] LCID for the conversion
6865 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6866 * pbstrOut [O] Destination
6868 * RETURNS
6869 * Success: S_OK.
6870 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6871 * E_OUTOFMEMORY, if memory allocation fails.
6873 * NOTES
6874 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6875 * localised text of "True" or "False". To convert a bool into a
6876 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6878 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6880 WCHAR szBuff[64];
6881 DWORD dwResId = IDS_TRUE;
6882 LANGID langId;
6884 TRACE("%d, %#lx, %#lx, %p.\n", boolIn, lcid, dwFlags, pbstrOut);
6886 if (!pbstrOut)
6887 return E_INVALIDARG;
6889 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6890 * for variant formatting */
6891 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6893 case VAR_BOOLONOFF:
6894 dwResId = IDS_ON;
6895 break;
6896 case VAR_BOOLYESNO:
6897 dwResId = IDS_YES;
6898 break;
6899 case VAR_LOCALBOOL:
6900 break;
6901 default:
6902 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6905 lcid = ConvertDefaultLocale(lcid);
6906 langId = LANGIDFROMLCID(lcid);
6907 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6908 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6910 if (boolIn == VARIANT_FALSE)
6911 dwResId++; /* Use negative form */
6913 VarBstrFromBool_GetLocalised:
6914 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6916 *pbstrOut = SysAllocString(szBuff);
6917 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6920 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6922 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6923 goto VarBstrFromBool_GetLocalised;
6926 /* Should never get here */
6927 WARN("Failed to load bool text!\n");
6928 return E_OUTOFMEMORY;
6931 /******************************************************************************
6932 * VarBstrFromI1 (OLEAUT32.229)
6934 * Convert a VT_I1 to a VT_BSTR.
6936 * PARAMS
6937 * cIn [I] Source
6938 * lcid [I] LCID for the conversion
6939 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6940 * pbstrOut [O] Destination
6942 * RETURNS
6943 * Success: S_OK.
6944 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6945 * E_OUTOFMEMORY, if memory allocation fails.
6947 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6949 ULONG64 ul64 = cIn;
6951 if (cIn < 0)
6953 ul64 = -cIn;
6954 dwFlags |= VAR_NEGATIVE;
6956 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6959 /******************************************************************************
6960 * VarBstrFromUI2 (OLEAUT32.230)
6962 * Convert a VT_UI2 to a VT_BSTR.
6964 * PARAMS
6965 * usIn [I] Source
6966 * lcid [I] LCID for the conversion
6967 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6968 * pbstrOut [O] Destination
6970 * RETURNS
6971 * Success: S_OK.
6972 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6973 * E_OUTOFMEMORY, if memory allocation fails.
6975 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6977 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6980 /******************************************************************************
6981 * VarBstrFromUI4 (OLEAUT32.231)
6983 * Convert a VT_UI4 to a VT_BSTR.
6985 * PARAMS
6986 * ulIn [I] Source
6987 * lcid [I] LCID for the conversion
6988 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6989 * pbstrOut [O] Destination
6991 * RETURNS
6992 * Success: S_OK.
6993 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6994 * E_OUTOFMEMORY, if memory allocation fails.
6996 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6998 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
7001 /******************************************************************************
7002 * VarBstrFromDec (OLEAUT32.232)
7004 * Convert a VT_DECIMAL to a VT_BSTR.
7006 * PARAMS
7007 * pDecIn [I] Source
7008 * lcid [I] LCID for the conversion
7009 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7010 * pbstrOut [O] Destination
7012 * RETURNS
7013 * Success: S_OK.
7014 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7015 * E_OUTOFMEMORY, if memory allocation fails.
7017 HRESULT WINAPI VarBstrFromDec(const DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7019 WCHAR buff[256];
7020 VARIANT_DI temp;
7022 if (!pbstrOut)
7023 return E_INVALIDARG;
7025 VARIANT_DIFromDec(pDecIn, &temp);
7026 VARIANT_DI_tostringW(&temp, buff, 256);
7028 if (dwFlags & LOCALE_USE_NLS)
7030 WCHAR numbuff[256];
7032 /* Format the number for the locale */
7033 numbuff[0] = '\0';
7034 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
7035 buff, NULL, numbuff, ARRAY_SIZE(numbuff));
7036 TRACE("created NLS string %s\n", debugstr_w(numbuff));
7037 *pbstrOut = SysAllocString(numbuff);
7039 else
7041 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
7044 TRACE("returning %s\n", debugstr_w(*pbstrOut));
7045 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
7048 /************************************************************************
7049 * VarBstrFromI8 (OLEAUT32.370)
7051 * Convert a VT_I8 to a VT_BSTR.
7053 * PARAMS
7054 * llIn [I] Source
7055 * lcid [I] LCID for the conversion
7056 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7057 * pbstrOut [O] Destination
7059 * RETURNS
7060 * Success: S_OK.
7061 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7062 * E_OUTOFMEMORY, if memory allocation fails.
7064 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7066 ULONG64 ul64 = llIn;
7068 if (llIn < 0)
7070 ul64 = -llIn;
7071 dwFlags |= VAR_NEGATIVE;
7073 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
7076 /************************************************************************
7077 * VarBstrFromUI8 (OLEAUT32.371)
7079 * Convert a VT_UI8 to a VT_BSTR.
7081 * PARAMS
7082 * ullIn [I] Source
7083 * lcid [I] LCID for the conversion
7084 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7085 * pbstrOut [O] Destination
7087 * RETURNS
7088 * Success: S_OK.
7089 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7090 * E_OUTOFMEMORY, if memory allocation fails.
7092 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7094 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
7097 /************************************************************************
7098 * VarBstrFromDisp (OLEAUT32.115)
7100 * Convert a VT_DISPATCH to a BSTR.
7102 * PARAMS
7103 * pdispIn [I] Source
7104 * lcid [I] LCID for conversion
7105 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7106 * pbstrOut [O] Destination
7108 * RETURNS
7109 * Success: S_OK.
7110 * Failure: E_INVALIDARG, if the source value is invalid
7111 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7113 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7115 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
7118 /**********************************************************************
7119 * VarBstrCat (OLEAUT32.313)
7121 * Concatenate two BSTR values.
7123 * PARAMS
7124 * pbstrLeft [I] Source
7125 * pbstrRight [I] Value to concatenate
7126 * pbstrOut [O] Destination
7128 * RETURNS
7129 * Success: S_OK.
7130 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7131 * E_OUTOFMEMORY, if memory allocation fails.
7133 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
7135 unsigned int lenLeft, lenRight;
7137 TRACE("%s,%s,%p\n",
7138 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7139 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
7141 if (!pbstrOut)
7142 return E_INVALIDARG;
7144 /* use byte length here to properly handle ansi-allocated BSTRs */
7145 lenLeft = pbstrLeft ? SysStringByteLen(pbstrLeft) : 0;
7146 lenRight = pbstrRight ? SysStringByteLen(pbstrRight) : 0;
7148 *pbstrOut = SysAllocStringByteLen(NULL, lenLeft + lenRight);
7149 if (!*pbstrOut)
7150 return E_OUTOFMEMORY;
7152 (*pbstrOut)[0] = '\0';
7154 if (pbstrLeft)
7155 memcpy(*pbstrOut, pbstrLeft, lenLeft);
7157 if (pbstrRight)
7158 memcpy((CHAR*)*pbstrOut + lenLeft, pbstrRight, lenRight);
7160 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
7161 return S_OK;
7164 /**********************************************************************
7165 * VarBstrCmp (OLEAUT32.314)
7167 * Compare two BSTR values.
7169 * PARAMS
7170 * pbstrLeft [I] Source
7171 * pbstrRight [I] Value to compare
7172 * lcid [I] LCID for the comparison
7173 * dwFlags [I] Flags to pass directly to CompareStringW().
7175 * RETURNS
7176 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7177 * than, equal to or greater than pbstrRight respectively.
7179 * NOTES
7180 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7181 * states. A NULL BSTR pointer is equivalent to an empty string.
7182 * If LCID is equal to 0, a byte by byte comparison is performed.
7184 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
7186 HRESULT hres;
7187 int ret;
7189 TRACE("%s, %s, %#lx, %#lx.\n",
7190 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7191 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
7193 if (!pbstrLeft || !*pbstrLeft)
7195 if (pbstrRight && *pbstrRight)
7196 return VARCMP_LT;
7198 else if (!pbstrRight || !*pbstrRight)
7199 return VARCMP_GT;
7201 if (lcid == 0)
7203 unsigned int lenLeft = SysStringByteLen(pbstrLeft);
7204 unsigned int lenRight = SysStringByteLen(pbstrRight);
7205 ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight));
7206 if (ret < 0)
7207 return VARCMP_LT;
7208 if (ret > 0)
7209 return VARCMP_GT;
7210 if (lenLeft < lenRight)
7211 return VARCMP_LT;
7212 if (lenLeft > lenRight)
7213 return VARCMP_GT;
7214 return VARCMP_EQ;
7216 else
7218 unsigned int lenLeft = SysStringLen(pbstrLeft);
7219 unsigned int lenRight = SysStringLen(pbstrRight);
7221 if (lenLeft == 0 || lenRight == 0)
7223 if (lenLeft == 0 && lenRight == 0) return VARCMP_EQ;
7224 return lenLeft < lenRight ? VARCMP_LT : VARCMP_GT;
7227 hres = CompareStringW(lcid, dwFlags, pbstrLeft, lenLeft,
7228 pbstrRight, lenRight) - CSTR_LESS_THAN;
7229 TRACE("%ld\n", hres);
7230 return hres;
7235 * DATE
7238 /******************************************************************************
7239 * VarDateFromUI1 (OLEAUT32.88)
7241 * Convert a VT_UI1 to a VT_DATE.
7243 * PARAMS
7244 * bIn [I] Source
7245 * pdateOut [O] Destination
7247 * RETURNS
7248 * S_OK.
7250 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
7252 return VarR8FromUI1(bIn, pdateOut);
7255 /******************************************************************************
7256 * VarDateFromI2 (OLEAUT32.89)
7258 * Convert a VT_I2 to a VT_DATE.
7260 * PARAMS
7261 * sIn [I] Source
7262 * pdateOut [O] Destination
7264 * RETURNS
7265 * S_OK.
7267 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
7269 return VarR8FromI2(sIn, pdateOut);
7272 /******************************************************************************
7273 * VarDateFromI4 (OLEAUT32.90)
7275 * Convert a VT_I4 to a VT_DATE.
7277 * PARAMS
7278 * lIn [I] Source
7279 * pdateOut [O] Destination
7281 * RETURNS
7282 * S_OK.
7284 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
7286 return VarDateFromR8(lIn, pdateOut);
7289 /******************************************************************************
7290 * VarDateFromR4 (OLEAUT32.91)
7292 * Convert a VT_R4 to a VT_DATE.
7294 * PARAMS
7295 * fltIn [I] Source
7296 * pdateOut [O] Destination
7298 * RETURNS
7299 * S_OK.
7301 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
7303 return VarR8FromR4(fltIn, pdateOut);
7306 /******************************************************************************
7307 * VarDateFromR8 (OLEAUT32.92)
7309 * Convert a VT_R8 to a VT_DATE.
7311 * PARAMS
7312 * dblIn [I] Source
7313 * pdateOut [O] Destination
7315 * RETURNS
7316 * S_OK.
7318 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
7320 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
7321 *pdateOut = (DATE)dblIn;
7322 return S_OK;
7325 /**********************************************************************
7326 * VarDateFromDisp (OLEAUT32.95)
7328 * Convert a VT_DISPATCH to a VT_DATE.
7330 * PARAMS
7331 * pdispIn [I] Source
7332 * lcid [I] LCID for conversion
7333 * pdateOut [O] Destination
7335 * RETURNS
7336 * Success: S_OK.
7337 * Failure: E_INVALIDARG, if the source value is invalid
7338 * DISP_E_OVERFLOW, if the value will not fit in the destination
7339 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7341 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
7343 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
7346 /******************************************************************************
7347 * VarDateFromBool (OLEAUT32.96)
7349 * Convert a VT_BOOL to a VT_DATE.
7351 * PARAMS
7352 * boolIn [I] Source
7353 * pdateOut [O] Destination
7355 * RETURNS
7356 * S_OK.
7358 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
7360 return VarR8FromBool(boolIn, pdateOut);
7363 /**********************************************************************
7364 * VarDateFromCy (OLEAUT32.93)
7366 * Convert a VT_CY to a VT_DATE.
7368 * PARAMS
7369 * lIn [I] Source
7370 * pdateOut [O] Destination
7372 * RETURNS
7373 * S_OK.
7375 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
7377 return VarR8FromCy(cyIn, pdateOut);
7380 /* Date string parsing */
7381 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7382 #define DP_DATESEP 0x02 /* Date separator */
7383 #define DP_MONTH 0x04 /* Month name */
7384 #define DP_AM 0x08 /* AM */
7385 #define DP_PM 0x10 /* PM */
7387 typedef struct tagDATEPARSE
7389 DWORD dwCount; /* Number of fields found so far (maximum 6) */
7390 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
7391 DWORD dwFlags[6]; /* Flags for each field */
7392 DWORD dwValues[6]; /* Value of each field */
7393 } DATEPARSE;
7395 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7397 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7399 /* Determine if a day is valid in a given month of a given year */
7400 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
7402 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7404 if (day && month && month < 13)
7406 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
7407 return TRUE;
7409 return FALSE;
7412 /* Possible orders for 3 numbers making up a date */
7413 #define ORDER_MDY 0x01
7414 #define ORDER_YMD 0x02
7415 #define ORDER_YDM 0x04
7416 #define ORDER_DMY 0x08
7417 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7419 /* Determine a date for a particular locale, from 3 numbers */
7420 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
7421 DWORD offset, SYSTEMTIME *st)
7423 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
7425 if (!dp->dwCount)
7427 v1 = 30; /* Default to (Variant) 0 date part */
7428 v2 = 12;
7429 v3 = 1899;
7430 goto VARIANT_MakeDate_OK;
7433 v1 = dp->dwValues[offset + 0];
7434 v2 = dp->dwValues[offset + 1];
7435 if (dp->dwCount == 2)
7437 SYSTEMTIME current;
7438 GetSystemTime(&current);
7439 v3 = current.wYear;
7441 else
7442 v3 = dp->dwValues[offset + 2];
7444 TRACE("%ld, %ld, %ld, %ld, %ld.\n", v1, v2, v3, iDate, offset);
7446 /* If one number must be a month (Because a month name was given), then only
7447 * consider orders with the month in that position.
7448 * If we took the current year as 'v3', then only allow a year in that position.
7450 if (dp->dwFlags[offset + 0] & DP_MONTH)
7452 dwAllOrders = ORDER_MDY;
7454 else if (dp->dwFlags[offset + 1] & DP_MONTH)
7456 dwAllOrders = ORDER_DMY;
7457 if (dp->dwCount > 2)
7458 dwAllOrders |= ORDER_YMD;
7460 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
7462 dwAllOrders = ORDER_YDM;
7464 else
7466 dwAllOrders = ORDER_MDY|ORDER_DMY;
7467 if (dp->dwCount > 2)
7468 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
7471 VARIANT_MakeDate_Start:
7472 TRACE("dwAllOrders is %#lx\n", dwAllOrders);
7474 while (dwAllOrders)
7476 DWORD dwTemp;
7478 if (dwCount == 0)
7480 /* First: Try the order given by iDate */
7481 switch (iDate)
7483 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
7484 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
7485 default: dwTry = dwAllOrders & ORDER_YMD; break;
7488 else if (dwCount == 1)
7490 /* Second: Try all the orders compatible with iDate */
7491 switch (iDate)
7493 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7494 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YDM|ORDER_MYD); break;
7495 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7498 else
7500 /* Finally: Try any remaining orders */
7501 dwTry = dwAllOrders;
7504 TRACE("Attempt %ld, dwTry is %#lx\n", dwCount, dwTry);
7506 dwCount++;
7507 if (!dwTry)
7508 continue;
7510 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7512 if (dwTry & ORDER_MDY)
7514 if (VARIANT_IsValidMonthDay(v2,v1,v3))
7516 DATE_SWAP(v1,v2);
7517 goto VARIANT_MakeDate_OK;
7519 dwAllOrders &= ~ORDER_MDY;
7521 if (dwTry & ORDER_YMD)
7523 if (VARIANT_IsValidMonthDay(v3,v2,v1))
7525 DATE_SWAP(v1,v3);
7526 goto VARIANT_MakeDate_OK;
7528 dwAllOrders &= ~ORDER_YMD;
7530 if (dwTry & ORDER_YDM)
7532 if (VARIANT_IsValidMonthDay(v2,v3,v1))
7534 DATE_SWAP(v1,v2);
7535 DATE_SWAP(v2,v3);
7536 goto VARIANT_MakeDate_OK;
7538 dwAllOrders &= ~ORDER_YDM;
7540 if (dwTry & ORDER_DMY)
7542 if (VARIANT_IsValidMonthDay(v1,v2,v3))
7543 goto VARIANT_MakeDate_OK;
7544 dwAllOrders &= ~ORDER_DMY;
7546 if (dwTry & ORDER_MYD)
7548 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7549 if (VARIANT_IsValidMonthDay(v3,v1,v2))
7551 DATE_SWAP(v1,v3);
7552 DATE_SWAP(v2,v3);
7553 goto VARIANT_MakeDate_OK;
7555 dwAllOrders &= ~ORDER_MYD;
7559 if (dp->dwCount == 2)
7561 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7562 v3 = 1; /* 1st of the month */
7563 dwAllOrders = ORDER_YMD|ORDER_MYD;
7564 dp->dwCount = 0; /* Don't return to this code path again */
7565 dwCount = 0;
7566 goto VARIANT_MakeDate_Start;
7569 /* No valid dates were able to be constructed */
7570 return DISP_E_TYPEMISMATCH;
7572 VARIANT_MakeDate_OK:
7574 /* Check that the time part is ok */
7575 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
7576 return DISP_E_TYPEMISMATCH;
7578 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7579 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
7580 st->wHour += 12;
7581 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
7582 st->wHour = 0;
7583 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7585 st->wDay = v1;
7586 st->wMonth = v2;
7587 /* FIXME: For 2 digit dates old versions of Windows used 29 but
7588 * Windows 10 1903 and greater use 49. This cutoff may also be modified by
7589 * setting the value as a string for the relevant calendar id in the
7590 * registry.
7592 * For instance to emulate old Windows versions:
7593 * [HKCU\Control Panel\International\Calendars\TwoDigitYearMax]
7594 * "1"="29"
7595 * (also 2, 9, 10, 11 and 12 for the other Gregorian calendars)
7597 * But Wine doesn't have/use that key at the time of writing.
7599 st->wYear = v3 <= 49 ? 2000 + v3 : v3 <= 99 ? 1900 + v3 : v3;
7600 TRACE("Returning date %ld/%ld/%d\n", v1, v2, st->wYear);
7601 return S_OK;
7604 /******************************************************************************
7605 * VarDateFromStr [OLEAUT32.94]
7607 * Convert a VT_BSTR to at VT_DATE.
7609 * PARAMS
7610 * strIn [I] String to convert
7611 * lcid [I] Locale identifier for the conversion
7612 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7613 * pdateOut [O] Destination for the converted value
7615 * RETURNS
7616 * Success: S_OK. pdateOut contains the converted value.
7617 * FAILURE: An HRESULT error code indicating the problem.
7619 * NOTES
7620 * Any date format that can be created using the date formats from lcid
7621 * (Either from kernel Nls functions, variant conversion or formatting) is a
7622 * valid input to this function. In addition, a few more esoteric formats are
7623 * also supported for compatibility with the native version. The date is
7624 * interpreted according to the date settings in the control panel, unless
7625 * the date is invalid in that format, in which the most compatible format
7626 * that produces a valid date will be used.
7628 HRESULT WINAPI VarDateFromStr(const OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7630 static const USHORT ParseDateTokens[] =
7632 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7633 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7634 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7635 LOCALE_SMONTHNAME13,
7636 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7637 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7638 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7639 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7640 LOCALE_SABBREVMONTHNAME13,
7641 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7642 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7643 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7644 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7645 LOCALE_SABBREVDAYNAME7,
7646 LOCALE_S1159, LOCALE_S2359,
7647 LOCALE_SDATE
7649 static const BYTE ParseDateMonths[] =
7651 1,2,3,4,5,6,7,8,9,10,11,12,13,
7652 1,2,3,4,5,6,7,8,9,10,11,12,13
7654 unsigned int i;
7655 BSTR tokens[ARRAY_SIZE(ParseDateTokens)];
7656 DATEPARSE dp;
7657 DWORD dwDateSeps = 0, iDate = 0;
7658 HRESULT hRet = S_OK;
7660 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7661 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7662 return E_INVALIDARG;
7664 if (!strIn)
7665 return DISP_E_TYPEMISMATCH;
7667 *pdateOut = 0.0;
7669 TRACE("%s, %#lx, %#lx, %p.\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7671 memset(&dp, 0, sizeof(dp));
7673 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7674 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7675 TRACE("iDate is %ld\n", iDate);
7677 /* Get the month/day/am/pm tokens for this locale */
7678 for (i = 0; i < ARRAY_SIZE(tokens); i++)
7680 WCHAR buff[128];
7681 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7683 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7684 * GetAltMonthNames(). We should really cache these strings too.
7686 buff[0] = '\0';
7687 GetLocaleInfoW(lcid, lctype, buff, ARRAY_SIZE(buff));
7688 tokens[i] = SysAllocString(buff);
7689 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7692 /* Parse the string into our structure */
7693 while (*strIn)
7695 if ('0' <= *strIn && *strIn <= '9')
7697 OLECHAR* end;
7698 if (dp.dwCount >= 6)
7700 hRet = DISP_E_TYPEMISMATCH;
7701 break;
7703 dp.dwValues[dp.dwCount] = wcstoul(strIn, &end, 10);
7704 dp.dwCount++;
7705 strIn = end - 1;
7707 else if (iswalpha(*strIn))
7709 BOOL bFound = FALSE;
7711 for (i = 0; i < ARRAY_SIZE(tokens); i++)
7713 DWORD dwLen = lstrlenW(tokens[i]);
7714 if (dwLen && !wcsnicmp(strIn, tokens[i], dwLen))
7716 if (i <= 25)
7718 if (dp.dwCount >= 6)
7719 hRet = DISP_E_TYPEMISMATCH;
7720 else
7722 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7723 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7724 dp.dwCount++;
7727 else if (i > 39 && i < 42)
7729 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7730 hRet = DISP_E_TYPEMISMATCH;
7731 else
7733 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7734 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7737 strIn += (dwLen - 1);
7738 bFound = TRUE;
7739 break;
7743 if (!bFound)
7745 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7746 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7748 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7749 if (*strIn == 'a' || *strIn == 'A')
7751 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7752 dp.dwParseFlags |= DP_AM;
7754 else
7756 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7757 dp.dwParseFlags |= DP_PM;
7759 strIn++;
7761 else
7763 TRACE("No matching token for %s\n", debugstr_w(strIn));
7764 hRet = DISP_E_TYPEMISMATCH;
7765 break;
7769 else if (*strIn == ':' || *strIn == '.')
7771 if (!dp.dwCount || !strIn[1])
7772 hRet = DISP_E_TYPEMISMATCH;
7773 else
7774 if (tokens[42][0] == *strIn)
7776 dwDateSeps++;
7777 if (dwDateSeps > 2)
7778 hRet = DISP_E_TYPEMISMATCH;
7779 else
7780 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7782 else
7783 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7785 else if (*strIn == '-' || *strIn == '/')
7787 dwDateSeps++;
7788 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7789 hRet = DISP_E_TYPEMISMATCH;
7790 else
7791 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7793 else if (*strIn == ',' || iswspace(*strIn))
7795 if (*strIn == ',' && !strIn[1])
7796 hRet = DISP_E_TYPEMISMATCH;
7798 else
7800 hRet = DISP_E_TYPEMISMATCH;
7802 strIn++;
7805 if (!dp.dwCount || dp.dwCount > 6 ||
7806 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7807 hRet = DISP_E_TYPEMISMATCH;
7809 if (SUCCEEDED(hRet))
7811 SYSTEMTIME st;
7812 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7814 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7816 /* Figure out which numbers correspond to which fields.
7818 * This switch statement works based on the fact that native interprets any
7819 * fields that are not joined with a time separator ('.' or ':') as date
7820 * fields. Thus we construct a value from 0-32 where each set bit indicates
7821 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7822 * For valid permutations, we set dwOffset to point to the first date field
7823 * and shorten dp.dwCount by the number of time fields found. The real
7824 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7825 * each date number must represent in the context of iDate.
7827 TRACE("%#lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7829 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7831 case 0x1: /* TT TTDD TTDDD */
7832 if (dp.dwCount > 3 &&
7833 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7834 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7835 hRet = DISP_E_TYPEMISMATCH;
7836 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7837 hRet = DISP_E_TYPEMISMATCH;
7838 st.wHour = dp.dwValues[0];
7839 st.wMinute = dp.dwValues[1];
7840 dp.dwCount -= 2;
7841 dwOffset = 2;
7842 break;
7844 case 0x3: /* TTT TTTDD TTTDDD */
7845 if (dp.dwCount > 4 &&
7846 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7847 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7848 hRet = DISP_E_TYPEMISMATCH;
7849 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7850 hRet = DISP_E_TYPEMISMATCH;
7851 st.wHour = dp.dwValues[0];
7852 st.wMinute = dp.dwValues[1];
7853 st.wSecond = dp.dwValues[2];
7854 dwOffset = 3;
7855 dp.dwCount -= 3;
7856 break;
7858 case 0x4: /* DDTT */
7859 if (dp.dwCount != 4 ||
7860 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7861 hRet = DISP_E_TYPEMISMATCH;
7863 st.wHour = dp.dwValues[2];
7864 st.wMinute = dp.dwValues[3];
7865 dp.dwCount -= 2;
7866 break;
7868 case 0x0: /* T DD DDD TDDD TDDD */
7869 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7871 st.wHour = dp.dwValues[0]; /* T */
7872 dp.dwCount = 0;
7873 break;
7875 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7877 hRet = DISP_E_TYPEMISMATCH;
7879 else if (dp.dwCount == 3)
7881 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7883 dp.dwCount = 2;
7884 st.wHour = dp.dwValues[0];
7885 dwOffset = 1;
7886 break;
7888 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7890 dp.dwCount = 2;
7891 st.wHour = dp.dwValues[2];
7892 break;
7894 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7895 hRet = DISP_E_TYPEMISMATCH;
7897 else if (dp.dwCount == 4)
7899 dp.dwCount = 3;
7900 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7902 st.wHour = dp.dwValues[0];
7903 dwOffset = 1;
7905 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7907 st.wHour = dp.dwValues[3];
7909 else
7910 hRet = DISP_E_TYPEMISMATCH;
7911 break;
7913 /* .. fall through .. */
7915 case 0x8: /* DDDTT */
7916 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7917 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7918 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7919 dp.dwCount == 4 || dp.dwCount == 6)
7920 hRet = DISP_E_TYPEMISMATCH;
7921 st.wHour = dp.dwValues[3];
7922 st.wMinute = dp.dwValues[4];
7923 if (dp.dwCount == 5)
7924 dp.dwCount -= 2;
7925 break;
7927 case 0xC: /* DDTTT */
7928 if (dp.dwCount != 5 ||
7929 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7930 hRet = DISP_E_TYPEMISMATCH;
7931 st.wHour = dp.dwValues[2];
7932 st.wMinute = dp.dwValues[3];
7933 st.wSecond = dp.dwValues[4];
7934 dp.dwCount -= 3;
7935 break;
7937 case 0x18: /* DDDTTT */
7938 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7939 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7940 hRet = DISP_E_TYPEMISMATCH;
7941 st.wHour = dp.dwValues[3];
7942 st.wMinute = dp.dwValues[4];
7943 st.wSecond = dp.dwValues[5];
7944 dp.dwCount -= 3;
7945 break;
7947 default:
7948 hRet = DISP_E_TYPEMISMATCH;
7949 break;
7952 if (SUCCEEDED(hRet))
7954 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7956 if (dwFlags & VAR_TIMEVALUEONLY)
7958 st.wYear = 1899;
7959 st.wMonth = 12;
7960 st.wDay = 30;
7962 else if (dwFlags & VAR_DATEVALUEONLY)
7963 st.wHour = st.wMinute = st.wSecond = 0;
7965 /* Finally, convert the value to a VT_DATE */
7966 if (SUCCEEDED(hRet))
7967 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7971 for (i = 0; i < ARRAY_SIZE(tokens); i++)
7972 SysFreeString(tokens[i]);
7973 return hRet;
7976 /******************************************************************************
7977 * VarDateFromI1 (OLEAUT32.221)
7979 * Convert a VT_I1 to a VT_DATE.
7981 * PARAMS
7982 * cIn [I] Source
7983 * pdateOut [O] Destination
7985 * RETURNS
7986 * S_OK.
7988 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7990 return VarR8FromI1(cIn, pdateOut);
7993 /******************************************************************************
7994 * VarDateFromUI2 (OLEAUT32.222)
7996 * Convert a VT_UI2 to a VT_DATE.
7998 * PARAMS
7999 * uiIn [I] Source
8000 * pdateOut [O] Destination
8002 * RETURNS
8003 * S_OK.
8005 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
8007 return VarR8FromUI2(uiIn, pdateOut);
8010 /******************************************************************************
8011 * VarDateFromUI4 (OLEAUT32.223)
8013 * Convert a VT_UI4 to a VT_DATE.
8015 * PARAMS
8016 * ulIn [I] Source
8017 * pdateOut [O] Destination
8019 * RETURNS
8020 * S_OK.
8022 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
8024 return VarDateFromR8(ulIn, pdateOut);
8027 /**********************************************************************
8028 * VarDateFromDec (OLEAUT32.224)
8030 * Convert a VT_DECIMAL to a VT_DATE.
8032 * PARAMS
8033 * pdecIn [I] Source
8034 * pdateOut [O] Destination
8036 * RETURNS
8037 * S_OK.
8039 HRESULT WINAPI VarDateFromDec(const DECIMAL *pdecIn, DATE* pdateOut)
8041 return VarR8FromDec(pdecIn, pdateOut);
8044 /******************************************************************************
8045 * VarDateFromI8 (OLEAUT32.364)
8047 * Convert a VT_I8 to a VT_DATE.
8049 * PARAMS
8050 * llIn [I] Source
8051 * pdateOut [O] Destination
8053 * RETURNS
8054 * Success: S_OK.
8055 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8057 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
8059 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
8060 *pdateOut = (DATE)llIn;
8061 return S_OK;
8064 /******************************************************************************
8065 * VarDateFromUI8 (OLEAUT32.365)
8067 * Convert a VT_UI8 to a VT_DATE.
8069 * PARAMS
8070 * ullIn [I] Source
8071 * pdateOut [O] Destination
8073 * RETURNS
8074 * Success: S_OK.
8075 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8077 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
8079 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
8080 *pdateOut = (DATE)ullIn;
8081 return S_OK;