amstream: Return E_POINTER on NULL stream in IMediaStreamFilter::GetMediaStream().
[wine/zf.git] / dlls / oleaut32 / vartype.c
blob4201a53642261288ee531bb89834925bdf0dc9f4
1 /*
2 * Low level variant functions
4 * Copyright 2003 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
25 #include "wine/debug.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winnt.h"
29 #include "variant.h"
30 #include "resource.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(variant);
34 extern HMODULE hProxyDll DECLSPEC_HIDDEN;
36 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
37 #define CY_MULTIPLIER_F 10000.0
38 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
39 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
41 static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' };
42 static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' };
44 /* Copy data from one variant to another. */
45 static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
47 switch (vt)
49 case VT_I1:
50 case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
51 case VT_BOOL:
52 case VT_I2:
53 case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
54 case VT_R4:
55 case VT_INT:
56 case VT_I4:
57 case VT_UINT:
58 case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
59 case VT_R8:
60 case VT_DATE:
61 case VT_CY:
62 case VT_I8:
63 case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break;
64 case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break;
65 case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
66 case VT_BSTR: memcpy(pOut, &V_BSTR(srcVar), sizeof(BSTR)); break;
67 default:
68 FIXME("VT_ type %d unhandled, please report!\n", vt);
72 /* Macro to inline conversion from a float or double to any integer type,
73 * rounding according to the 'dutch' convention.
75 #define VARIANT_DutchRound(typ, value, res) do { \
76 double whole = value < 0 ? ceil(value) : floor(value); \
77 double fract = value - whole; \
78 if (fract > 0.5) res = (typ)whole + (typ)1; \
79 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
80 else if (fract >= 0.0) res = (typ)whole; \
81 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
82 else if (fract > -0.5) res = (typ)whole; \
83 else res = (typ)whole - (typ)1; \
84 } while(0)
87 /* Coerce VT_BSTR to a numeric type */
88 static HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
89 void* pOut, VARTYPE vt)
91 VARIANTARG dstVar;
92 HRESULT hRet;
93 NUMPARSE np;
94 BYTE rgb[1024];
96 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
97 np.cDig = ARRAY_SIZE(rgb);
98 np.dwInFlags = NUMPRS_STD;
100 hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
102 if (SUCCEEDED(hRet))
104 /* 1 << vt gives us the VTBIT constant for the destination number type */
105 hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
106 if (SUCCEEDED(hRet))
107 VARIANT_CopyData(&dstVar, vt, pOut);
109 return hRet;
112 /* Coerce VT_DISPATCH to another type */
113 static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut,
114 VARTYPE vt, DWORD dwFlags)
116 static DISPPARAMS emptyParams = { NULL, NULL, 0, 0 };
117 VARIANTARG srcVar, dstVar;
118 HRESULT hRet;
120 if (!pdispIn)
121 return DISP_E_BADVARTYPE;
123 /* Get the default 'value' property from the IDispatch */
124 VariantInit(&srcVar);
125 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
126 &emptyParams, &srcVar, NULL, NULL);
128 if (SUCCEEDED(hRet))
130 /* Convert the property to the requested type */
131 VariantInit(&dstVar);
132 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt);
133 VariantClear(&srcVar);
135 if (SUCCEEDED(hRet))
136 VARIANT_CopyData(&dstVar, vt, pOut);
138 else
139 hRet = DISP_E_TYPEMISMATCH;
140 return hRet;
143 /* Inline return type */
144 #define RETTYP static inline HRESULT
147 /* Simple compiler cast from one type to another */
148 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
149 *out = in; return S_OK; }
151 /* Compiler cast where input cannot be negative */
152 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
153 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
155 /* Compiler cast where input cannot be > some number */
156 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
157 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
159 /* Compiler cast where input cannot be < some number or >= some other number */
160 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
161 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
163 /* I1 */
164 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX)
165 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX)
166 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX)
167 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool)
168 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX)
169 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX)
170 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX)
171 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX)
173 /* UI1 */
174 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX)
175 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool)
176 NEGTST(BYTE, signed char, VarUI1FromI1)
177 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX)
178 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX)
179 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX)
180 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX)
181 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX)
183 /* I2 */
184 SIMPLE(SHORT, BYTE, VarI2FromUI1)
185 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX)
186 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool)
187 SIMPLE(SHORT, signed char, VarI2FromI1)
188 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX)
189 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX)
190 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX)
191 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX)
193 /* UI2 */
194 SIMPLE(USHORT, BYTE, VarUI2FromUI1)
195 NEGTST(USHORT, SHORT, VarUI2FromI2)
196 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX)
197 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool)
198 NEGTST(USHORT, signed char, VarUI2FromI1)
199 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX)
200 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX)
201 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX)
203 /* I4 */
204 SIMPLE(LONG, BYTE, VarI4FromUI1)
205 SIMPLE(LONG, SHORT, VarI4FromI2)
206 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool)
207 SIMPLE(LONG, signed char, VarI4FromI1)
208 SIMPLE(LONG, USHORT, VarI4FromUI2)
209 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX)
210 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX)
211 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX)
213 /* UI4 */
214 SIMPLE(ULONG, BYTE, VarUI4FromUI1)
215 NEGTST(ULONG, SHORT, VarUI4FromI2)
216 NEGTST(ULONG, LONG, VarUI4FromI4)
217 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool)
218 NEGTST(ULONG, signed char, VarUI4FromI1)
219 SIMPLE(ULONG, USHORT, VarUI4FromUI2)
220 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX)
221 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX)
223 /* I8 */
224 SIMPLE(LONG64, BYTE, VarI8FromUI1)
225 SIMPLE(LONG64, SHORT, VarI8FromI2)
226 SIMPLE(LONG64, signed char, VarI8FromI1)
227 SIMPLE(LONG64, USHORT, VarI8FromUI2)
228 SIMPLE(LONG64, ULONG, VarI8FromUI4)
229 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX)
231 /* UI8 */
232 SIMPLE(ULONG64, BYTE, VarUI8FromUI1)
233 NEGTST(ULONG64, SHORT, VarUI8FromI2)
234 NEGTST(ULONG64, signed char, VarUI8FromI1)
235 SIMPLE(ULONG64, USHORT, VarUI8FromUI2)
236 SIMPLE(ULONG64, ULONG, VarUI8FromUI4)
237 NEGTST(ULONG64, LONG64, VarUI8FromI8)
239 /* R4 (float) */
240 SIMPLE(float, BYTE, VarR4FromUI1)
241 SIMPLE(float, SHORT, VarR4FromI2)
242 SIMPLE(float, signed char, VarR4FromI1)
243 SIMPLE(float, USHORT, VarR4FromUI2)
244 SIMPLE(float, LONG, VarR4FromI4)
245 SIMPLE(float, ULONG, VarR4FromUI4)
246 SIMPLE(float, LONG64, VarR4FromI8)
247 SIMPLE(float, ULONG64, VarR4FromUI8)
249 /* R8 (double) */
250 SIMPLE(double, BYTE, VarR8FromUI1)
251 SIMPLE(double, SHORT, VarR8FromI2)
252 SIMPLE(double, float, VarR8FromR4)
253 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
254 SIMPLE(double, DATE, VarR8FromDate)
255 SIMPLE(double, signed char, VarR8FromI1)
256 SIMPLE(double, USHORT, VarR8FromUI2)
257 SIMPLE(double, LONG, VarR8FromI4)
258 SIMPLE(double, ULONG, VarR8FromUI4)
259 SIMPLE(double, LONG64, VarR8FromI8)
260 SIMPLE(double, ULONG64, VarR8FromUI8)
263 /* I1
266 /************************************************************************
267 * VarI1FromUI1 (OLEAUT32.244)
269 * Convert a VT_UI1 to a VT_I1.
271 * PARAMS
272 * bIn [I] Source
273 * pcOut [O] Destination
275 * RETURNS
276 * Success: S_OK.
277 * Failure: E_INVALIDARG, if the source value is invalid
278 * DISP_E_OVERFLOW, if the value will not fit in the destination
280 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
282 return _VarI1FromUI1(bIn, pcOut);
285 /************************************************************************
286 * VarI1FromI2 (OLEAUT32.245)
288 * Convert a VT_I2 to a VT_I1.
290 * PARAMS
291 * sIn [I] Source
292 * pcOut [O] Destination
294 * RETURNS
295 * Success: S_OK.
296 * Failure: E_INVALIDARG, if the source value is invalid
297 * DISP_E_OVERFLOW, if the value will not fit in the destination
299 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
301 return _VarI1FromI2(sIn, pcOut);
304 /************************************************************************
305 * VarI1FromI4 (OLEAUT32.246)
307 * Convert a VT_I4 to a VT_I1.
309 * PARAMS
310 * iIn [I] Source
311 * pcOut [O] Destination
313 * RETURNS
314 * Success: S_OK.
315 * Failure: E_INVALIDARG, if the source value is invalid
316 * DISP_E_OVERFLOW, if the value will not fit in the destination
318 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
320 return _VarI1FromI4(iIn, pcOut);
323 /************************************************************************
324 * VarI1FromR4 (OLEAUT32.247)
326 * Convert a VT_R4 to a VT_I1.
328 * PARAMS
329 * fltIn [I] Source
330 * pcOut [O] Destination
332 * RETURNS
333 * Success: S_OK.
334 * Failure: E_INVALIDARG, if the source value is invalid
335 * DISP_E_OVERFLOW, if the value will not fit in the destination
337 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
339 return VarI1FromR8(fltIn, pcOut);
342 /************************************************************************
343 * VarI1FromR8 (OLEAUT32.248)
345 * Convert a VT_R8 to a VT_I1.
347 * PARAMS
348 * dblIn [I] Source
349 * pcOut [O] Destination
351 * RETURNS
352 * Success: S_OK.
353 * Failure: E_INVALIDARG, if the source value is invalid
354 * DISP_E_OVERFLOW, if the value will not fit in the destination
356 * NOTES
357 * See VarI8FromR8() for details concerning rounding.
359 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
361 if (dblIn < I1_MIN - 0.5 || dblIn >= I1_MAX + 0.5)
362 return DISP_E_OVERFLOW;
363 VARIANT_DutchRound(CHAR, dblIn, *pcOut);
364 return S_OK;
367 /************************************************************************
368 * VarI1FromDate (OLEAUT32.249)
370 * Convert a VT_DATE to a VT_I1.
372 * PARAMS
373 * dateIn [I] Source
374 * pcOut [O] Destination
376 * RETURNS
377 * Success: S_OK.
378 * Failure: E_INVALIDARG, if the source value is invalid
379 * DISP_E_OVERFLOW, if the value will not fit in the destination
381 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
383 return VarI1FromR8(dateIn, pcOut);
386 /************************************************************************
387 * VarI1FromCy (OLEAUT32.250)
389 * Convert a VT_CY to a VT_I1.
391 * PARAMS
392 * cyIn [I] Source
393 * pcOut [O] Destination
395 * RETURNS
396 * Success: S_OK.
397 * Failure: E_INVALIDARG, if the source value is invalid
398 * DISP_E_OVERFLOW, if the value will not fit in the destination
400 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
402 LONG i = I1_MAX + 1;
404 VarI4FromCy(cyIn, &i);
405 return _VarI1FromI4(i, pcOut);
408 /************************************************************************
409 * VarI1FromStr (OLEAUT32.251)
411 * Convert a VT_BSTR to a VT_I1.
413 * PARAMS
414 * strIn [I] Source
415 * lcid [I] LCID for the conversion
416 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
417 * pcOut [O] Destination
419 * RETURNS
420 * Success: S_OK.
421 * Failure: E_INVALIDARG, if the source value is invalid
422 * DISP_E_OVERFLOW, if the value will not fit in the destination
423 * DISP_E_TYPEMISMATCH, if the type cannot be converted
425 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
427 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
430 /************************************************************************
431 * VarI1FromDisp (OLEAUT32.252)
433 * Convert a VT_DISPATCH to a VT_I1.
435 * PARAMS
436 * pdispIn [I] Source
437 * lcid [I] LCID for conversion
438 * pcOut [O] Destination
440 * RETURNS
441 * Success: S_OK.
442 * Failure: E_INVALIDARG, if the source value is invalid
443 * DISP_E_OVERFLOW, if the value will not fit in the destination
444 * DISP_E_TYPEMISMATCH, if the type cannot be converted
446 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
448 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0);
451 /************************************************************************
452 * VarI1FromBool (OLEAUT32.253)
454 * Convert a VT_BOOL to a VT_I1.
456 * PARAMS
457 * boolIn [I] Source
458 * pcOut [O] Destination
460 * RETURNS
461 * S_OK.
463 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
465 return _VarI1FromBool(boolIn, pcOut);
468 /************************************************************************
469 * VarI1FromUI2 (OLEAUT32.254)
471 * Convert a VT_UI2 to a VT_I1.
473 * PARAMS
474 * usIn [I] Source
475 * pcOut [O] Destination
477 * RETURNS
478 * Success: S_OK.
479 * Failure: E_INVALIDARG, if the source value is invalid
480 * DISP_E_OVERFLOW, if the value will not fit in the destination
482 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
484 return _VarI1FromUI2(usIn, pcOut);
487 /************************************************************************
488 * VarI1FromUI4 (OLEAUT32.255)
490 * Convert a VT_UI4 to a VT_I1.
492 * PARAMS
493 * ulIn [I] Source
494 * pcOut [O] Destination
496 * RETURNS
497 * Success: S_OK.
498 * Failure: E_INVALIDARG, if the source value is invalid
499 * DISP_E_OVERFLOW, if the value will not fit in the destination
500 * DISP_E_TYPEMISMATCH, if the type cannot be converted
502 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
504 return _VarI1FromUI4(ulIn, pcOut);
507 /************************************************************************
508 * VarI1FromDec (OLEAUT32.256)
510 * Convert a VT_DECIMAL to a VT_I1.
512 * PARAMS
513 * pDecIn [I] Source
514 * pcOut [O] Destination
516 * RETURNS
517 * Success: S_OK.
518 * Failure: E_INVALIDARG, if the source value is invalid
519 * DISP_E_OVERFLOW, if the value will not fit in the destination
521 HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut)
523 LONG64 i64;
524 HRESULT hRet;
526 hRet = VarI8FromDec(pdecIn, &i64);
528 if (SUCCEEDED(hRet))
529 hRet = _VarI1FromI8(i64, pcOut);
530 return hRet;
533 /************************************************************************
534 * VarI1FromI8 (OLEAUT32.376)
536 * Convert a VT_I8 to a VT_I1.
538 * PARAMS
539 * llIn [I] Source
540 * pcOut [O] Destination
542 * RETURNS
543 * Success: S_OK.
544 * Failure: E_INVALIDARG, if the source value is invalid
545 * DISP_E_OVERFLOW, if the value will not fit in the destination
547 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
549 return _VarI1FromI8(llIn, pcOut);
552 /************************************************************************
553 * VarI1FromUI8 (OLEAUT32.377)
555 * Convert a VT_UI8 to a VT_I1.
557 * PARAMS
558 * ullIn [I] Source
559 * pcOut [O] Destination
561 * RETURNS
562 * Success: S_OK.
563 * Failure: E_INVALIDARG, if the source value is invalid
564 * DISP_E_OVERFLOW, if the value will not fit in the destination
566 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
568 return _VarI1FromUI8(ullIn, pcOut);
571 /* UI1
574 /************************************************************************
575 * VarUI1FromI2 (OLEAUT32.130)
577 * Convert a VT_I2 to a VT_UI1.
579 * PARAMS
580 * sIn [I] Source
581 * pbOut [O] Destination
583 * RETURNS
584 * Success: S_OK.
585 * Failure: E_INVALIDARG, if the source value is invalid
586 * DISP_E_OVERFLOW, if the value will not fit in the destination
588 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
590 return _VarUI1FromI2(sIn, pbOut);
593 /************************************************************************
594 * VarUI1FromI4 (OLEAUT32.131)
596 * Convert a VT_I4 to a VT_UI1.
598 * PARAMS
599 * iIn [I] Source
600 * pbOut [O] Destination
602 * RETURNS
603 * Success: S_OK.
604 * Failure: E_INVALIDARG, if the source value is invalid
605 * DISP_E_OVERFLOW, if the value will not fit in the destination
607 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
609 return _VarUI1FromI4(iIn, pbOut);
612 /************************************************************************
613 * VarUI1FromR4 (OLEAUT32.132)
615 * Convert a VT_R4 to a VT_UI1.
617 * PARAMS
618 * fltIn [I] Source
619 * pbOut [O] Destination
621 * RETURNS
622 * Success: S_OK.
623 * Failure: E_INVALIDARG, if the source value is invalid
624 * DISP_E_OVERFLOW, if the value will not fit in the destination
625 * DISP_E_TYPEMISMATCH, if the type cannot be converted
627 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
629 return VarUI1FromR8(fltIn, pbOut);
632 /************************************************************************
633 * VarUI1FromR8 (OLEAUT32.133)
635 * Convert a VT_R8 to a VT_UI1.
637 * PARAMS
638 * dblIn [I] Source
639 * pbOut [O] Destination
641 * RETURNS
642 * Success: S_OK.
643 * Failure: E_INVALIDARG, if the source value is invalid
644 * DISP_E_OVERFLOW, if the value will not fit in the destination
646 * NOTES
647 * See VarI8FromR8() for details concerning rounding.
649 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
651 if (dblIn < -0.5 || dblIn >= UI1_MAX + 0.5)
652 return DISP_E_OVERFLOW;
653 VARIANT_DutchRound(BYTE, dblIn, *pbOut);
654 return S_OK;
657 /************************************************************************
658 * VarUI1FromCy (OLEAUT32.134)
660 * Convert a VT_CY to a VT_UI1.
662 * PARAMS
663 * cyIn [I] Source
664 * pbOut [O] Destination
666 * RETURNS
667 * Success: S_OK.
668 * Failure: E_INVALIDARG, if the source value is invalid
669 * DISP_E_OVERFLOW, if the value will not fit in the destination
671 * NOTES
672 * Negative values >= -5000 will be converted to 0.
674 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
676 ULONG i = UI1_MAX + 1;
678 VarUI4FromCy(cyIn, &i);
679 return _VarUI1FromUI4(i, pbOut);
682 /************************************************************************
683 * VarUI1FromDate (OLEAUT32.135)
685 * Convert a VT_DATE to a VT_UI1.
687 * PARAMS
688 * dateIn [I] Source
689 * pbOut [O] Destination
691 * RETURNS
692 * Success: S_OK.
693 * Failure: E_INVALIDARG, if the source value is invalid
694 * DISP_E_OVERFLOW, if the value will not fit in the destination
696 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
698 return VarUI1FromR8(dateIn, pbOut);
701 /************************************************************************
702 * VarUI1FromStr (OLEAUT32.136)
704 * Convert a VT_BSTR to a VT_UI1.
706 * PARAMS
707 * strIn [I] Source
708 * lcid [I] LCID for the conversion
709 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
710 * pbOut [O] Destination
712 * RETURNS
713 * Success: S_OK.
714 * Failure: E_INVALIDARG, if the source value is invalid
715 * DISP_E_OVERFLOW, if the value will not fit in the destination
716 * DISP_E_TYPEMISMATCH, if the type cannot be converted
718 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
720 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
723 /************************************************************************
724 * VarUI1FromDisp (OLEAUT32.137)
726 * Convert a VT_DISPATCH to a VT_UI1.
728 * PARAMS
729 * pdispIn [I] Source
730 * lcid [I] LCID for conversion
731 * pbOut [O] Destination
733 * RETURNS
734 * Success: S_OK.
735 * Failure: E_INVALIDARG, if the source value is invalid
736 * DISP_E_OVERFLOW, if the value will not fit in the destination
737 * DISP_E_TYPEMISMATCH, if the type cannot be converted
739 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
741 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0);
744 /************************************************************************
745 * VarUI1FromBool (OLEAUT32.138)
747 * Convert a VT_BOOL to a VT_UI1.
749 * PARAMS
750 * boolIn [I] Source
751 * pbOut [O] Destination
753 * RETURNS
754 * S_OK.
756 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
758 return _VarUI1FromBool(boolIn, pbOut);
761 /************************************************************************
762 * VarUI1FromI1 (OLEAUT32.237)
764 * Convert a VT_I1 to a VT_UI1.
766 * PARAMS
767 * cIn [I] Source
768 * pbOut [O] Destination
770 * RETURNS
771 * Success: S_OK.
772 * Failure: E_INVALIDARG, if the source value is invalid
773 * DISP_E_OVERFLOW, if the value will not fit in the destination
775 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
777 return _VarUI1FromI1(cIn, pbOut);
780 /************************************************************************
781 * VarUI1FromUI2 (OLEAUT32.238)
783 * Convert a VT_UI2 to a VT_UI1.
785 * PARAMS
786 * usIn [I] Source
787 * pbOut [O] Destination
789 * RETURNS
790 * Success: S_OK.
791 * Failure: E_INVALIDARG, if the source value is invalid
792 * DISP_E_OVERFLOW, if the value will not fit in the destination
794 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
796 return _VarUI1FromUI2(usIn, pbOut);
799 /************************************************************************
800 * VarUI1FromUI4 (OLEAUT32.239)
802 * Convert a VT_UI4 to a VT_UI1.
804 * PARAMS
805 * ulIn [I] Source
806 * pbOut [O] Destination
808 * RETURNS
809 * Success: S_OK.
810 * Failure: E_INVALIDARG, if the source value is invalid
811 * DISP_E_OVERFLOW, if the value will not fit in the destination
813 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
815 return _VarUI1FromUI4(ulIn, pbOut);
818 /************************************************************************
819 * VarUI1FromDec (OLEAUT32.240)
821 * Convert a VT_DECIMAL to a VT_UI1.
823 * PARAMS
824 * pDecIn [I] Source
825 * pbOut [O] Destination
827 * RETURNS
828 * Success: S_OK.
829 * Failure: E_INVALIDARG, if the source value is invalid
830 * DISP_E_OVERFLOW, if the value will not fit in the destination
832 HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut)
834 LONG64 i64;
835 HRESULT hRet;
837 hRet = VarI8FromDec(pdecIn, &i64);
839 if (SUCCEEDED(hRet))
840 hRet = _VarUI1FromI8(i64, pbOut);
841 return hRet;
844 /************************************************************************
845 * VarUI1FromI8 (OLEAUT32.372)
847 * Convert a VT_I8 to a VT_UI1.
849 * PARAMS
850 * llIn [I] Source
851 * pbOut [O] Destination
853 * RETURNS
854 * Success: S_OK.
855 * Failure: E_INVALIDARG, if the source value is invalid
856 * DISP_E_OVERFLOW, if the value will not fit in the destination
858 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
860 return _VarUI1FromI8(llIn, pbOut);
863 /************************************************************************
864 * VarUI1FromUI8 (OLEAUT32.373)
866 * Convert a VT_UI8 to a VT_UI1.
868 * PARAMS
869 * ullIn [I] Source
870 * pbOut [O] Destination
872 * RETURNS
873 * Success: S_OK.
874 * Failure: E_INVALIDARG, if the source value is invalid
875 * DISP_E_OVERFLOW, if the value will not fit in the destination
877 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
879 return _VarUI1FromUI8(ullIn, pbOut);
883 /* I2
886 /************************************************************************
887 * VarI2FromUI1 (OLEAUT32.48)
889 * Convert a VT_UI2 to a VT_I2.
891 * PARAMS
892 * bIn [I] Source
893 * psOut [O] Destination
895 * RETURNS
896 * S_OK.
898 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
900 return _VarI2FromUI1(bIn, psOut);
903 /************************************************************************
904 * VarI2FromI4 (OLEAUT32.49)
906 * Convert a VT_I4 to a VT_I2.
908 * PARAMS
909 * iIn [I] Source
910 * psOut [O] Destination
912 * RETURNS
913 * Success: S_OK.
914 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
916 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
918 return _VarI2FromI4(iIn, psOut);
921 /************************************************************************
922 * VarI2FromR4 (OLEAUT32.50)
924 * Convert a VT_R4 to a VT_I2.
926 * PARAMS
927 * fltIn [I] Source
928 * psOut [O] Destination
930 * RETURNS
931 * Success: S_OK.
932 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
934 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
936 return VarI2FromR8(fltIn, psOut);
939 /************************************************************************
940 * VarI2FromR8 (OLEAUT32.51)
942 * Convert a VT_R8 to a VT_I2.
944 * PARAMS
945 * dblIn [I] Source
946 * psOut [O] Destination
948 * RETURNS
949 * Success: S_OK.
950 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
952 * NOTES
953 * See VarI8FromR8() for details concerning rounding.
955 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
957 if (dblIn < I2_MIN - 0.5 || dblIn >= I2_MAX + 0.5)
958 return DISP_E_OVERFLOW;
959 VARIANT_DutchRound(SHORT, dblIn, *psOut);
960 return S_OK;
963 /************************************************************************
964 * VarI2FromCy (OLEAUT32.52)
966 * Convert a VT_CY to a VT_I2.
968 * PARAMS
969 * cyIn [I] Source
970 * psOut [O] Destination
972 * RETURNS
973 * Success: S_OK.
974 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
976 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
978 LONG i = I2_MAX + 1;
980 VarI4FromCy(cyIn, &i);
981 return _VarI2FromI4(i, psOut);
984 /************************************************************************
985 * VarI2FromDate (OLEAUT32.53)
987 * Convert a VT_DATE to a VT_I2.
989 * PARAMS
990 * dateIn [I] Source
991 * psOut [O] Destination
993 * RETURNS
994 * Success: S_OK.
995 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
997 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
999 return VarI2FromR8(dateIn, psOut);
1002 /************************************************************************
1003 * VarI2FromStr (OLEAUT32.54)
1005 * Convert a VT_BSTR to a VT_I2.
1007 * PARAMS
1008 * strIn [I] Source
1009 * lcid [I] LCID for the conversion
1010 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1011 * psOut [O] Destination
1013 * RETURNS
1014 * Success: S_OK.
1015 * Failure: E_INVALIDARG, if any parameter is invalid
1016 * DISP_E_OVERFLOW, if the value will not fit in the destination
1017 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1019 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
1021 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
1024 /************************************************************************
1025 * VarI2FromDisp (OLEAUT32.55)
1027 * Convert a VT_DISPATCH to a VT_I2.
1029 * PARAMS
1030 * pdispIn [I] Source
1031 * lcid [I] LCID for conversion
1032 * psOut [O] Destination
1034 * RETURNS
1035 * Success: S_OK.
1036 * Failure: E_INVALIDARG, if pdispIn is invalid,
1037 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1038 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1040 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
1042 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0);
1045 /************************************************************************
1046 * VarI2FromBool (OLEAUT32.56)
1048 * Convert a VT_BOOL to a VT_I2.
1050 * PARAMS
1051 * boolIn [I] Source
1052 * psOut [O] Destination
1054 * RETURNS
1055 * S_OK.
1057 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
1059 return _VarI2FromBool(boolIn, psOut);
1062 /************************************************************************
1063 * VarI2FromI1 (OLEAUT32.205)
1065 * Convert a VT_I1 to a VT_I2.
1067 * PARAMS
1068 * cIn [I] Source
1069 * psOut [O] Destination
1071 * RETURNS
1072 * S_OK.
1074 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
1076 return _VarI2FromI1(cIn, psOut);
1079 /************************************************************************
1080 * VarI2FromUI2 (OLEAUT32.206)
1082 * Convert a VT_UI2 to a VT_I2.
1084 * PARAMS
1085 * usIn [I] Source
1086 * psOut [O] Destination
1088 * RETURNS
1089 * Success: S_OK.
1090 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1092 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
1094 return _VarI2FromUI2(usIn, psOut);
1097 /************************************************************************
1098 * VarI2FromUI4 (OLEAUT32.207)
1100 * Convert a VT_UI4 to a VT_I2.
1102 * PARAMS
1103 * ulIn [I] Source
1104 * psOut [O] Destination
1106 * RETURNS
1107 * Success: S_OK.
1108 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1110 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
1112 return _VarI2FromUI4(ulIn, psOut);
1115 /************************************************************************
1116 * VarI2FromDec (OLEAUT32.208)
1118 * Convert a VT_DECIMAL to a VT_I2.
1120 * PARAMS
1121 * pDecIn [I] Source
1122 * psOut [O] Destination
1124 * RETURNS
1125 * Success: S_OK.
1126 * Failure: E_INVALIDARG, if the source value is invalid
1127 * DISP_E_OVERFLOW, if the value will not fit in the destination
1129 HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut)
1131 LONG64 i64;
1132 HRESULT hRet;
1134 hRet = VarI8FromDec(pdecIn, &i64);
1136 if (SUCCEEDED(hRet))
1137 hRet = _VarI2FromI8(i64, psOut);
1138 return hRet;
1141 /************************************************************************
1142 * VarI2FromI8 (OLEAUT32.346)
1144 * Convert a VT_I8 to a VT_I2.
1146 * PARAMS
1147 * llIn [I] Source
1148 * psOut [O] Destination
1150 * RETURNS
1151 * Success: S_OK.
1152 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1154 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
1156 return _VarI2FromI8(llIn, psOut);
1159 /************************************************************************
1160 * VarI2FromUI8 (OLEAUT32.347)
1162 * Convert a VT_UI8 to a VT_I2.
1164 * PARAMS
1165 * ullIn [I] Source
1166 * psOut [O] Destination
1168 * RETURNS
1169 * Success: S_OK.
1170 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1172 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
1174 return _VarI2FromUI8(ullIn, psOut);
1177 /* UI2
1180 /************************************************************************
1181 * VarUI2FromUI1 (OLEAUT32.257)
1183 * Convert a VT_UI1 to a VT_UI2.
1185 * PARAMS
1186 * bIn [I] Source
1187 * pusOut [O] Destination
1189 * RETURNS
1190 * S_OK.
1192 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
1194 return _VarUI2FromUI1(bIn, pusOut);
1197 /************************************************************************
1198 * VarUI2FromI2 (OLEAUT32.258)
1200 * Convert a VT_I2 to a VT_UI2.
1202 * PARAMS
1203 * sIn [I] Source
1204 * pusOut [O] Destination
1206 * RETURNS
1207 * Success: S_OK.
1208 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1210 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
1212 return _VarUI2FromI2(sIn, pusOut);
1215 /************************************************************************
1216 * VarUI2FromI4 (OLEAUT32.259)
1218 * Convert a VT_I4 to a VT_UI2.
1220 * PARAMS
1221 * iIn [I] Source
1222 * pusOut [O] Destination
1224 * RETURNS
1225 * Success: S_OK.
1226 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1228 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
1230 return _VarUI2FromI4(iIn, pusOut);
1233 /************************************************************************
1234 * VarUI2FromR4 (OLEAUT32.260)
1236 * Convert a VT_R4 to a VT_UI2.
1238 * PARAMS
1239 * fltIn [I] Source
1240 * pusOut [O] Destination
1242 * RETURNS
1243 * Success: S_OK.
1244 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1246 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
1248 return VarUI2FromR8(fltIn, pusOut);
1251 /************************************************************************
1252 * VarUI2FromR8 (OLEAUT32.261)
1254 * Convert a VT_R8 to a VT_UI2.
1256 * PARAMS
1257 * dblIn [I] Source
1258 * pusOut [O] Destination
1260 * RETURNS
1261 * Success: S_OK.
1262 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1264 * NOTES
1265 * See VarI8FromR8() for details concerning rounding.
1267 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
1269 if (dblIn < -0.5 || dblIn >= UI2_MAX + 0.5)
1270 return DISP_E_OVERFLOW;
1271 VARIANT_DutchRound(USHORT, dblIn, *pusOut);
1272 return S_OK;
1275 /************************************************************************
1276 * VarUI2FromDate (OLEAUT32.262)
1278 * Convert a VT_DATE to a VT_UI2.
1280 * PARAMS
1281 * dateIn [I] Source
1282 * pusOut [O] Destination
1284 * RETURNS
1285 * Success: S_OK.
1286 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1288 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
1290 return VarUI2FromR8(dateIn, pusOut);
1293 /************************************************************************
1294 * VarUI2FromCy (OLEAUT32.263)
1296 * Convert a VT_CY to a VT_UI2.
1298 * PARAMS
1299 * cyIn [I] Source
1300 * pusOut [O] Destination
1302 * RETURNS
1303 * Success: S_OK.
1304 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1306 * NOTES
1307 * Negative values >= -5000 will be converted to 0.
1309 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
1311 ULONG i = UI2_MAX + 1;
1313 VarUI4FromCy(cyIn, &i);
1314 return _VarUI2FromUI4(i, pusOut);
1317 /************************************************************************
1318 * VarUI2FromStr (OLEAUT32.264)
1320 * Convert a VT_BSTR to a VT_UI2.
1322 * PARAMS
1323 * strIn [I] Source
1324 * lcid [I] LCID for the conversion
1325 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1326 * pusOut [O] Destination
1328 * RETURNS
1329 * Success: S_OK.
1330 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1331 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1333 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
1335 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
1338 /************************************************************************
1339 * VarUI2FromDisp (OLEAUT32.265)
1341 * Convert a VT_DISPATCH to a VT_UI2.
1343 * PARAMS
1344 * pdispIn [I] Source
1345 * lcid [I] LCID for conversion
1346 * pusOut [O] Destination
1348 * RETURNS
1349 * Success: S_OK.
1350 * Failure: E_INVALIDARG, if the source value is invalid
1351 * DISP_E_OVERFLOW, if the value will not fit in the destination
1352 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1354 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
1356 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0);
1359 /************************************************************************
1360 * VarUI2FromBool (OLEAUT32.266)
1362 * Convert a VT_BOOL to a VT_UI2.
1364 * PARAMS
1365 * boolIn [I] Source
1366 * pusOut [O] Destination
1368 * RETURNS
1369 * S_OK.
1371 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
1373 return _VarUI2FromBool(boolIn, pusOut);
1376 /************************************************************************
1377 * VarUI2FromI1 (OLEAUT32.267)
1379 * Convert a VT_I1 to a VT_UI2.
1381 * PARAMS
1382 * cIn [I] Source
1383 * pusOut [O] Destination
1385 * RETURNS
1386 * Success: S_OK.
1387 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1389 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
1391 return _VarUI2FromI1(cIn, pusOut);
1394 /************************************************************************
1395 * VarUI2FromUI4 (OLEAUT32.268)
1397 * Convert a VT_UI4 to a VT_UI2.
1399 * PARAMS
1400 * ulIn [I] Source
1401 * pusOut [O] Destination
1403 * RETURNS
1404 * Success: S_OK.
1405 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1407 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
1409 return _VarUI2FromUI4(ulIn, pusOut);
1412 /************************************************************************
1413 * VarUI2FromDec (OLEAUT32.269)
1415 * Convert a VT_DECIMAL to a VT_UI2.
1417 * PARAMS
1418 * pDecIn [I] Source
1419 * pusOut [O] Destination
1421 * RETURNS
1422 * Success: S_OK.
1423 * Failure: E_INVALIDARG, if the source value is invalid
1424 * DISP_E_OVERFLOW, if the value will not fit in the destination
1426 HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut)
1428 LONG64 i64;
1429 HRESULT hRet;
1431 hRet = VarI8FromDec(pdecIn, &i64);
1433 if (SUCCEEDED(hRet))
1434 hRet = _VarUI2FromI8(i64, pusOut);
1435 return hRet;
1438 /************************************************************************
1439 * VarUI2FromI8 (OLEAUT32.378)
1441 * Convert a VT_I8 to a VT_UI2.
1443 * PARAMS
1444 * llIn [I] Source
1445 * pusOut [O] Destination
1447 * RETURNS
1448 * Success: S_OK.
1449 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1451 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
1453 return _VarUI2FromI8(llIn, pusOut);
1456 /************************************************************************
1457 * VarUI2FromUI8 (OLEAUT32.379)
1459 * Convert a VT_UI8 to a VT_UI2.
1461 * PARAMS
1462 * ullIn [I] Source
1463 * pusOut [O] Destination
1465 * RETURNS
1466 * Success: S_OK.
1467 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1469 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
1471 return _VarUI2FromUI8(ullIn, pusOut);
1474 /* I4
1477 /************************************************************************
1478 * VarI4FromUI1 (OLEAUT32.58)
1480 * Convert a VT_UI1 to a VT_I4.
1482 * PARAMS
1483 * bIn [I] Source
1484 * piOut [O] Destination
1486 * RETURNS
1487 * S_OK.
1489 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
1491 return _VarI4FromUI1(bIn, piOut);
1494 /************************************************************************
1495 * VarI4FromI2 (OLEAUT32.59)
1497 * Convert a VT_I2 to a VT_I4.
1499 * PARAMS
1500 * sIn [I] Source
1501 * piOut [O] Destination
1503 * RETURNS
1504 * Success: S_OK.
1505 * Failure: E_INVALIDARG, if the source value is invalid
1506 * DISP_E_OVERFLOW, if the value will not fit in the destination
1508 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
1510 return _VarI4FromI2(sIn, piOut);
1513 /************************************************************************
1514 * VarI4FromR4 (OLEAUT32.60)
1516 * Convert a VT_R4 to a VT_I4.
1518 * PARAMS
1519 * fltIn [I] Source
1520 * piOut [O] Destination
1522 * RETURNS
1523 * Success: S_OK.
1524 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1526 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
1528 return VarI4FromR8(fltIn, piOut);
1531 /************************************************************************
1532 * VarI4FromR8 (OLEAUT32.61)
1534 * Convert a VT_R8 to a VT_I4.
1536 * PARAMS
1537 * dblIn [I] Source
1538 * piOut [O] Destination
1540 * RETURNS
1541 * Success: S_OK.
1542 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1544 * NOTES
1545 * See VarI8FromR8() for details concerning rounding.
1547 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
1549 if (dblIn < I4_MIN - 0.5 || dblIn >= I4_MAX + 0.5)
1550 return DISP_E_OVERFLOW;
1551 VARIANT_DutchRound(LONG, dblIn, *piOut);
1552 return S_OK;
1555 /************************************************************************
1556 * VarI4FromCy (OLEAUT32.62)
1558 * Convert a VT_CY to a VT_I4.
1560 * PARAMS
1561 * cyIn [I] Source
1562 * piOut [O] Destination
1564 * RETURNS
1565 * Success: S_OK.
1566 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1568 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
1570 double d = cyIn.int64 / CY_MULTIPLIER_F;
1571 return VarI4FromR8(d, piOut);
1574 /************************************************************************
1575 * VarI4FromDate (OLEAUT32.63)
1577 * Convert a VT_DATE to a VT_I4.
1579 * PARAMS
1580 * dateIn [I] Source
1581 * piOut [O] Destination
1583 * RETURNS
1584 * Success: S_OK.
1585 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1587 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
1589 return VarI4FromR8(dateIn, piOut);
1592 /************************************************************************
1593 * VarI4FromStr (OLEAUT32.64)
1595 * Convert a VT_BSTR to a VT_I4.
1597 * PARAMS
1598 * strIn [I] Source
1599 * lcid [I] LCID for the conversion
1600 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1601 * piOut [O] Destination
1603 * RETURNS
1604 * Success: S_OK.
1605 * Failure: E_INVALIDARG, if any parameter is invalid
1606 * DISP_E_OVERFLOW, if the value will not fit in the destination
1607 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1609 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
1611 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
1614 /************************************************************************
1615 * VarI4FromDisp (OLEAUT32.65)
1617 * Convert a VT_DISPATCH to a VT_I4.
1619 * PARAMS
1620 * pdispIn [I] Source
1621 * lcid [I] LCID for conversion
1622 * piOut [O] Destination
1624 * RETURNS
1625 * Success: S_OK.
1626 * Failure: E_INVALIDARG, if the source value is invalid
1627 * DISP_E_OVERFLOW, if the value will not fit in the destination
1628 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1630 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
1632 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0);
1635 /************************************************************************
1636 * VarI4FromBool (OLEAUT32.66)
1638 * Convert a VT_BOOL to a VT_I4.
1640 * PARAMS
1641 * boolIn [I] Source
1642 * piOut [O] Destination
1644 * RETURNS
1645 * S_OK.
1647 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
1649 return _VarI4FromBool(boolIn, piOut);
1652 /************************************************************************
1653 * VarI4FromI1 (OLEAUT32.209)
1655 * Convert a VT_I1 to a VT_I4.
1657 * PARAMS
1658 * cIn [I] Source
1659 * piOut [O] Destination
1661 * RETURNS
1662 * S_OK.
1664 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
1666 return _VarI4FromI1(cIn, piOut);
1669 /************************************************************************
1670 * VarI4FromUI2 (OLEAUT32.210)
1672 * Convert a VT_UI2 to a VT_I4.
1674 * PARAMS
1675 * usIn [I] Source
1676 * piOut [O] Destination
1678 * RETURNS
1679 * S_OK.
1681 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
1683 return _VarI4FromUI2(usIn, piOut);
1686 /************************************************************************
1687 * VarI4FromUI4 (OLEAUT32.211)
1689 * Convert a VT_UI4 to a VT_I4.
1691 * PARAMS
1692 * ulIn [I] Source
1693 * piOut [O] Destination
1695 * RETURNS
1696 * Success: S_OK.
1697 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1699 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
1701 return _VarI4FromUI4(ulIn, piOut);
1704 /************************************************************************
1705 * VarI4FromDec (OLEAUT32.212)
1707 * Convert a VT_DECIMAL to a VT_I4.
1709 * PARAMS
1710 * pDecIn [I] Source
1711 * piOut [O] Destination
1713 * RETURNS
1714 * Success: S_OK.
1715 * Failure: E_INVALIDARG, if pdecIn is invalid
1716 * DISP_E_OVERFLOW, if the value will not fit in the destination
1718 HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut)
1720 LONG64 i64;
1721 HRESULT hRet;
1723 hRet = VarI8FromDec(pdecIn, &i64);
1725 if (SUCCEEDED(hRet))
1726 hRet = _VarI4FromI8(i64, piOut);
1727 return hRet;
1730 /************************************************************************
1731 * VarI4FromI8 (OLEAUT32.348)
1733 * Convert a VT_I8 to a VT_I4.
1735 * PARAMS
1736 * llIn [I] Source
1737 * piOut [O] Destination
1739 * RETURNS
1740 * Success: S_OK.
1741 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1743 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
1745 return _VarI4FromI8(llIn, piOut);
1748 /************************************************************************
1749 * VarI4FromUI8 (OLEAUT32.349)
1751 * Convert a VT_UI8 to a VT_I4.
1753 * PARAMS
1754 * ullIn [I] Source
1755 * piOut [O] Destination
1757 * RETURNS
1758 * Success: S_OK.
1759 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1761 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
1763 return _VarI4FromUI8(ullIn, piOut);
1766 /* UI4
1769 /************************************************************************
1770 * VarUI4FromUI1 (OLEAUT32.270)
1772 * Convert a VT_UI1 to a VT_UI4.
1774 * PARAMS
1775 * bIn [I] Source
1776 * pulOut [O] Destination
1778 * RETURNS
1779 * S_OK.
1781 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
1783 return _VarUI4FromUI1(bIn, pulOut);
1786 /************************************************************************
1787 * VarUI4FromI2 (OLEAUT32.271)
1789 * Convert a VT_I2 to a VT_UI4.
1791 * PARAMS
1792 * sIn [I] Source
1793 * pulOut [O] Destination
1795 * RETURNS
1796 * Success: S_OK.
1797 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1799 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
1801 return _VarUI4FromI2(sIn, pulOut);
1804 /************************************************************************
1805 * VarUI4FromI4 (OLEAUT32.272)
1807 * Convert a VT_I4 to a VT_UI4.
1809 * PARAMS
1810 * iIn [I] Source
1811 * pulOut [O] Destination
1813 * RETURNS
1814 * Success: S_OK.
1815 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1817 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
1819 return _VarUI4FromI4(iIn, pulOut);
1822 /************************************************************************
1823 * VarUI4FromR4 (OLEAUT32.273)
1825 * Convert a VT_R4 to a VT_UI4.
1827 * PARAMS
1828 * fltIn [I] Source
1829 * pulOut [O] Destination
1831 * RETURNS
1832 * Success: S_OK.
1833 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1835 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
1837 return VarUI4FromR8(fltIn, pulOut);
1840 /************************************************************************
1841 * VarUI4FromR8 (OLEAUT32.274)
1843 * Convert a VT_R8 to a VT_UI4.
1845 * PARAMS
1846 * dblIn [I] Source
1847 * pulOut [O] Destination
1849 * RETURNS
1850 * Success: S_OK.
1851 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1853 * NOTES
1854 * See VarI8FromR8() for details concerning rounding.
1856 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
1858 if (dblIn < -0.5 || dblIn >= UI4_MAX + 0.5)
1859 return DISP_E_OVERFLOW;
1860 VARIANT_DutchRound(ULONG, dblIn, *pulOut);
1861 return S_OK;
1864 /************************************************************************
1865 * VarUI4FromDate (OLEAUT32.275)
1867 * Convert a VT_DATE to a VT_UI4.
1869 * PARAMS
1870 * dateIn [I] Source
1871 * pulOut [O] Destination
1873 * RETURNS
1874 * Success: S_OK.
1875 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1877 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
1879 return VarUI4FromR8(dateIn, pulOut);
1882 /************************************************************************
1883 * VarUI4FromCy (OLEAUT32.276)
1885 * Convert a VT_CY to a VT_UI4.
1887 * PARAMS
1888 * cyIn [I] Source
1889 * pulOut [O] Destination
1891 * RETURNS
1892 * Success: S_OK.
1893 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1895 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
1897 double d = cyIn.int64 / CY_MULTIPLIER_F;
1898 return VarUI4FromR8(d, pulOut);
1901 /************************************************************************
1902 * VarUI4FromStr (OLEAUT32.277)
1904 * Convert a VT_BSTR to a VT_UI4.
1906 * PARAMS
1907 * strIn [I] Source
1908 * lcid [I] LCID for the conversion
1909 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1910 * pulOut [O] Destination
1912 * RETURNS
1913 * Success: S_OK.
1914 * Failure: E_INVALIDARG, if any parameter is invalid
1915 * DISP_E_OVERFLOW, if the value will not fit in the destination
1916 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1918 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
1920 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
1923 /************************************************************************
1924 * VarUI4FromDisp (OLEAUT32.278)
1926 * Convert a VT_DISPATCH to a VT_UI4.
1928 * PARAMS
1929 * pdispIn [I] Source
1930 * lcid [I] LCID for conversion
1931 * pulOut [O] Destination
1933 * RETURNS
1934 * Success: S_OK.
1935 * Failure: E_INVALIDARG, if the source value is invalid
1936 * DISP_E_OVERFLOW, if the value will not fit in the destination
1937 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1939 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
1941 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0);
1944 /************************************************************************
1945 * VarUI4FromBool (OLEAUT32.279)
1947 * Convert a VT_BOOL to a VT_UI4.
1949 * PARAMS
1950 * boolIn [I] Source
1951 * pulOut [O] Destination
1953 * RETURNS
1954 * S_OK.
1956 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
1958 return _VarUI4FromBool(boolIn, pulOut);
1961 /************************************************************************
1962 * VarUI4FromI1 (OLEAUT32.280)
1964 * Convert a VT_I1 to a VT_UI4.
1966 * PARAMS
1967 * cIn [I] Source
1968 * pulOut [O] Destination
1970 * RETURNS
1971 * Success: S_OK.
1972 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1974 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
1976 return _VarUI4FromI1(cIn, pulOut);
1979 /************************************************************************
1980 * VarUI4FromUI2 (OLEAUT32.281)
1982 * Convert a VT_UI2 to a VT_UI4.
1984 * PARAMS
1985 * usIn [I] Source
1986 * pulOut [O] Destination
1988 * RETURNS
1989 * S_OK.
1991 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
1993 return _VarUI4FromUI2(usIn, pulOut);
1996 /************************************************************************
1997 * VarUI4FromDec (OLEAUT32.282)
1999 * Convert a VT_DECIMAL to a VT_UI4.
2001 * PARAMS
2002 * pDecIn [I] Source
2003 * pulOut [O] Destination
2005 * RETURNS
2006 * Success: S_OK.
2007 * Failure: E_INVALIDARG, if pdecIn is invalid
2008 * DISP_E_OVERFLOW, if the value will not fit in the destination
2010 HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut)
2012 LONG64 i64;
2013 HRESULT hRet;
2015 hRet = VarI8FromDec(pdecIn, &i64);
2017 if (SUCCEEDED(hRet))
2018 hRet = _VarUI4FromI8(i64, pulOut);
2019 return hRet;
2022 /************************************************************************
2023 * VarUI4FromI8 (OLEAUT32.425)
2025 * Convert a VT_I8 to a VT_UI4.
2027 * PARAMS
2028 * llIn [I] Source
2029 * pulOut [O] Destination
2031 * RETURNS
2032 * Success: S_OK.
2033 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2035 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
2037 return _VarUI4FromI8(llIn, pulOut);
2040 /************************************************************************
2041 * VarUI4FromUI8 (OLEAUT32.426)
2043 * Convert a VT_UI8 to a VT_UI4.
2045 * PARAMS
2046 * ullIn [I] Source
2047 * pulOut [O] Destination
2049 * RETURNS
2050 * Success: S_OK.
2051 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2053 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
2055 return _VarUI4FromUI8(ullIn, pulOut);
2058 /* I8
2061 /************************************************************************
2062 * VarI8FromUI1 (OLEAUT32.333)
2064 * Convert a VT_UI1 to a VT_I8.
2066 * PARAMS
2067 * bIn [I] Source
2068 * pi64Out [O] Destination
2070 * RETURNS
2071 * S_OK.
2073 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
2075 return _VarI8FromUI1(bIn, pi64Out);
2079 /************************************************************************
2080 * VarI8FromI2 (OLEAUT32.334)
2082 * Convert a VT_I2 to a VT_I8.
2084 * PARAMS
2085 * sIn [I] Source
2086 * pi64Out [O] Destination
2088 * RETURNS
2089 * S_OK.
2091 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
2093 return _VarI8FromI2(sIn, pi64Out);
2096 /************************************************************************
2097 * VarI8FromR4 (OLEAUT32.335)
2099 * Convert a VT_R4 to a VT_I8.
2101 * PARAMS
2102 * fltIn [I] Source
2103 * pi64Out [O] Destination
2105 * RETURNS
2106 * Success: S_OK.
2107 * Failure: E_INVALIDARG, if the source value is invalid
2108 * DISP_E_OVERFLOW, if the value will not fit in the destination
2110 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
2112 return VarI8FromR8(fltIn, pi64Out);
2115 /************************************************************************
2116 * VarI8FromR8 (OLEAUT32.336)
2118 * Convert a VT_R8 to a VT_I8.
2120 * PARAMS
2121 * dblIn [I] Source
2122 * pi64Out [O] Destination
2124 * RETURNS
2125 * Success: S_OK.
2126 * Failure: E_INVALIDARG, if the source value is invalid
2127 * DISP_E_OVERFLOW, if the value will not fit in the destination
2129 * NOTES
2130 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2131 * very high or low values will not be accurately converted.
2133 * Numbers are rounded using Dutch rounding, as follows:
2135 *| Fractional Part Sign Direction Example
2136 *| --------------- ---- --------- -------
2137 *| < 0.5 + Down 0.4 -> 0.0
2138 *| < 0.5 - Up -0.4 -> 0.0
2139 *| > 0.5 + Up 0.6 -> 1.0
2140 *| < 0.5 - Up -0.6 -> -1.0
2141 *| = 0.5 + Up/Down Down if even, Up if odd
2142 *| = 0.5 - Up/Down Up if even, Down if odd
2144 * This system is often used in supermarkets.
2146 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
2148 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
2149 return DISP_E_OVERFLOW;
2150 VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
2151 return S_OK;
2154 /************************************************************************
2155 * VarI8FromCy (OLEAUT32.337)
2157 * Convert a VT_CY to a VT_I8.
2159 * PARAMS
2160 * cyIn [I] Source
2161 * pi64Out [O] Destination
2163 * RETURNS
2164 * S_OK.
2166 * NOTES
2167 * All negative numbers are rounded down by 1, including those that are
2168 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2169 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2170 * for details.
2172 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
2174 *pi64Out = cyIn.int64 / CY_MULTIPLIER;
2176 if (cyIn.int64 < 0)
2177 (*pi64Out)--; /* Mimic Win32 bug */
2178 else
2180 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2182 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1)))
2183 (*pi64Out)++;
2185 return S_OK;
2188 /************************************************************************
2189 * VarI8FromDate (OLEAUT32.338)
2191 * Convert a VT_DATE to a VT_I8.
2193 * PARAMS
2194 * dateIn [I] Source
2195 * pi64Out [O] Destination
2197 * RETURNS
2198 * Success: S_OK.
2199 * Failure: E_INVALIDARG, if the source value is invalid
2200 * DISP_E_OVERFLOW, if the value will not fit in the destination
2201 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2203 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
2205 return VarI8FromR8(dateIn, pi64Out);
2208 /************************************************************************
2209 * VarI8FromStr (OLEAUT32.339)
2211 * Convert a VT_BSTR to a VT_I8.
2213 * PARAMS
2214 * strIn [I] Source
2215 * lcid [I] LCID for the conversion
2216 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2217 * pi64Out [O] Destination
2219 * RETURNS
2220 * Success: S_OK.
2221 * Failure: E_INVALIDARG, if the source value is invalid
2222 * DISP_E_OVERFLOW, if the value will not fit in the destination
2223 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2225 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
2227 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
2230 /************************************************************************
2231 * VarI8FromDisp (OLEAUT32.340)
2233 * Convert a VT_DISPATCH to a VT_I8.
2235 * PARAMS
2236 * pdispIn [I] Source
2237 * lcid [I] LCID for conversion
2238 * pi64Out [O] Destination
2240 * RETURNS
2241 * Success: S_OK.
2242 * Failure: E_INVALIDARG, if the source value is invalid
2243 * DISP_E_OVERFLOW, if the value will not fit in the destination
2244 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2246 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
2248 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0);
2251 /************************************************************************
2252 * VarI8FromBool (OLEAUT32.341)
2254 * Convert a VT_BOOL to a VT_I8.
2256 * PARAMS
2257 * boolIn [I] Source
2258 * pi64Out [O] Destination
2260 * RETURNS
2261 * S_OK.
2263 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
2265 return VarI8FromI2(boolIn, pi64Out);
2268 /************************************************************************
2269 * VarI8FromI1 (OLEAUT32.342)
2271 * Convert a VT_I1 to a VT_I8.
2273 * PARAMS
2274 * cIn [I] Source
2275 * pi64Out [O] Destination
2277 * RETURNS
2278 * S_OK.
2280 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
2282 return _VarI8FromI1(cIn, pi64Out);
2285 /************************************************************************
2286 * VarI8FromUI2 (OLEAUT32.343)
2288 * Convert a VT_UI2 to a VT_I8.
2290 * PARAMS
2291 * usIn [I] Source
2292 * pi64Out [O] Destination
2294 * RETURNS
2295 * S_OK.
2297 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
2299 return _VarI8FromUI2(usIn, pi64Out);
2302 /************************************************************************
2303 * VarI8FromUI4 (OLEAUT32.344)
2305 * Convert a VT_UI4 to a VT_I8.
2307 * PARAMS
2308 * ulIn [I] Source
2309 * pi64Out [O] Destination
2311 * RETURNS
2312 * S_OK.
2314 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
2316 return _VarI8FromUI4(ulIn, pi64Out);
2319 /************************************************************************
2320 * VarI8FromDec (OLEAUT32.345)
2322 * Convert a VT_DECIMAL to a VT_I8.
2324 * PARAMS
2325 * pDecIn [I] Source
2326 * pi64Out [O] Destination
2328 * RETURNS
2329 * Success: S_OK.
2330 * Failure: E_INVALIDARG, if the source value is invalid
2331 * DISP_E_OVERFLOW, if the value will not fit in the destination
2333 HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out)
2335 if (!DEC_SCALE(pdecIn))
2337 /* This decimal is just a 96 bit integer */
2338 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2339 return E_INVALIDARG;
2341 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000)
2342 return DISP_E_OVERFLOW;
2344 if (DEC_SIGN(pdecIn))
2345 *pi64Out = -DEC_LO64(pdecIn);
2346 else
2347 *pi64Out = DEC_LO64(pdecIn);
2348 return S_OK;
2350 else
2352 /* Decimal contains a floating point number */
2353 HRESULT hRet;
2354 double dbl;
2356 hRet = VarR8FromDec(pdecIn, &dbl);
2357 if (SUCCEEDED(hRet))
2358 hRet = VarI8FromR8(dbl, pi64Out);
2359 return hRet;
2363 /************************************************************************
2364 * VarI8FromUI8 (OLEAUT32.427)
2366 * Convert a VT_UI8 to a VT_I8.
2368 * PARAMS
2369 * ullIn [I] Source
2370 * pi64Out [O] Destination
2372 * RETURNS
2373 * Success: S_OK.
2374 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2376 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
2378 return _VarI8FromUI8(ullIn, pi64Out);
2381 /* UI8
2384 /************************************************************************
2385 * VarUI8FromI8 (OLEAUT32.428)
2387 * Convert a VT_I8 to a VT_UI8.
2389 * PARAMS
2390 * ulIn [I] Source
2391 * pui64Out [O] Destination
2393 * RETURNS
2394 * Success: S_OK.
2395 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2397 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
2399 return _VarUI8FromI8(llIn, pui64Out);
2402 /************************************************************************
2403 * VarUI8FromUI1 (OLEAUT32.429)
2405 * Convert a VT_UI1 to a VT_UI8.
2407 * PARAMS
2408 * bIn [I] Source
2409 * pui64Out [O] Destination
2411 * RETURNS
2412 * S_OK.
2414 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
2416 return _VarUI8FromUI1(bIn, pui64Out);
2419 /************************************************************************
2420 * VarUI8FromI2 (OLEAUT32.430)
2422 * Convert a VT_I2 to a VT_UI8.
2424 * PARAMS
2425 * sIn [I] Source
2426 * pui64Out [O] Destination
2428 * RETURNS
2429 * S_OK.
2431 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
2433 return _VarUI8FromI2(sIn, pui64Out);
2436 /************************************************************************
2437 * VarUI8FromR4 (OLEAUT32.431)
2439 * Convert a VT_R4 to a VT_UI8.
2441 * PARAMS
2442 * fltIn [I] Source
2443 * pui64Out [O] Destination
2445 * RETURNS
2446 * Success: S_OK.
2447 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2449 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
2451 return VarUI8FromR8(fltIn, pui64Out);
2454 /************************************************************************
2455 * VarUI8FromR8 (OLEAUT32.432)
2457 * Convert a VT_R8 to a VT_UI8.
2459 * PARAMS
2460 * dblIn [I] Source
2461 * pui64Out [O] Destination
2463 * RETURNS
2464 * Success: S_OK.
2465 * Failure: E_INVALIDARG, if the source value is invalid
2466 * DISP_E_OVERFLOW, if the value will not fit in the destination
2468 * NOTES
2469 * See VarI8FromR8() for details concerning rounding.
2471 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
2473 if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
2474 return DISP_E_OVERFLOW;
2475 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
2476 return S_OK;
2479 /************************************************************************
2480 * VarUI8FromCy (OLEAUT32.433)
2482 * Convert a VT_CY to a VT_UI8.
2484 * PARAMS
2485 * cyIn [I] Source
2486 * pui64Out [O] Destination
2488 * RETURNS
2489 * Success: S_OK.
2490 * Failure: E_INVALIDARG, if the source value is invalid
2491 * DISP_E_OVERFLOW, if the value will not fit in the destination
2493 * NOTES
2494 * Negative values >= -5000 will be converted to 0.
2496 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
2498 if (cyIn.int64 < 0)
2500 if (cyIn.int64 < -CY_HALF)
2501 return DISP_E_OVERFLOW;
2502 *pui64Out = 0;
2504 else
2506 *pui64Out = cyIn.int64 / CY_MULTIPLIER;
2508 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2510 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1)))
2511 (*pui64Out)++;
2513 return S_OK;
2516 /************************************************************************
2517 * VarUI8FromDate (OLEAUT32.434)
2519 * Convert a VT_DATE to a VT_UI8.
2521 * PARAMS
2522 * dateIn [I] Source
2523 * pui64Out [O] Destination
2525 * RETURNS
2526 * Success: S_OK.
2527 * Failure: E_INVALIDARG, if the source value is invalid
2528 * DISP_E_OVERFLOW, if the value will not fit in the destination
2529 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2531 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
2533 return VarUI8FromR8(dateIn, pui64Out);
2536 /************************************************************************
2537 * VarUI8FromStr (OLEAUT32.435)
2539 * Convert a VT_BSTR to a VT_UI8.
2541 * PARAMS
2542 * strIn [I] Source
2543 * lcid [I] LCID for the conversion
2544 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2545 * pui64Out [O] Destination
2547 * RETURNS
2548 * Success: S_OK.
2549 * Failure: E_INVALIDARG, if the source value is invalid
2550 * DISP_E_OVERFLOW, if the value will not fit in the destination
2551 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2553 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
2555 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
2558 /************************************************************************
2559 * VarUI8FromDisp (OLEAUT32.436)
2561 * Convert a VT_DISPATCH to a VT_UI8.
2563 * PARAMS
2564 * pdispIn [I] Source
2565 * lcid [I] LCID for conversion
2566 * pui64Out [O] Destination
2568 * RETURNS
2569 * Success: S_OK.
2570 * Failure: E_INVALIDARG, if the source value is invalid
2571 * DISP_E_OVERFLOW, if the value will not fit in the destination
2572 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2574 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
2576 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0);
2579 /************************************************************************
2580 * VarUI8FromBool (OLEAUT32.437)
2582 * Convert a VT_BOOL to a VT_UI8.
2584 * PARAMS
2585 * boolIn [I] Source
2586 * pui64Out [O] Destination
2588 * RETURNS
2589 * Success: S_OK.
2590 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2592 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
2594 return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
2596 /************************************************************************
2597 * VarUI8FromI1 (OLEAUT32.438)
2599 * Convert a VT_I1 to a VT_UI8.
2601 * PARAMS
2602 * cIn [I] Source
2603 * pui64Out [O] Destination
2605 * RETURNS
2606 * Success: S_OK.
2607 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2609 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
2611 return _VarUI8FromI1(cIn, pui64Out);
2614 /************************************************************************
2615 * VarUI8FromUI2 (OLEAUT32.439)
2617 * Convert a VT_UI2 to a VT_UI8.
2619 * PARAMS
2620 * usIn [I] Source
2621 * pui64Out [O] Destination
2623 * RETURNS
2624 * S_OK.
2626 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
2628 return _VarUI8FromUI2(usIn, pui64Out);
2631 /************************************************************************
2632 * VarUI8FromUI4 (OLEAUT32.440)
2634 * Convert a VT_UI4 to a VT_UI8.
2636 * PARAMS
2637 * ulIn [I] Source
2638 * pui64Out [O] Destination
2640 * RETURNS
2641 * S_OK.
2643 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
2645 return _VarUI8FromUI4(ulIn, pui64Out);
2648 /************************************************************************
2649 * VarUI8FromDec (OLEAUT32.441)
2651 * Convert a VT_DECIMAL to a VT_UI8.
2653 * PARAMS
2654 * pDecIn [I] Source
2655 * pui64Out [O] Destination
2657 * RETURNS
2658 * Success: S_OK.
2659 * Failure: E_INVALIDARG, if the source value is invalid
2660 * DISP_E_OVERFLOW, if the value will not fit in the destination
2662 * NOTES
2663 * Under native Win32, if the source value has a scale of 0, its sign is
2664 * ignored, i.e. this function takes the absolute value rather than fail
2665 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2666 * (use VarAbs() on pDecIn first if you really want this behaviour).
2668 HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out)
2670 if (!DEC_SCALE(pdecIn))
2672 /* This decimal is just a 96 bit integer */
2673 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2674 return E_INVALIDARG;
2676 if (DEC_HI32(pdecIn))
2677 return DISP_E_OVERFLOW;
2679 if (DEC_SIGN(pdecIn))
2681 WARN("Sign would be ignored under Win32!\n");
2682 return DISP_E_OVERFLOW;
2685 *pui64Out = DEC_LO64(pdecIn);
2686 return S_OK;
2688 else
2690 /* Decimal contains a floating point number */
2691 HRESULT hRet;
2692 double dbl;
2694 hRet = VarR8FromDec(pdecIn, &dbl);
2695 if (SUCCEEDED(hRet))
2696 hRet = VarUI8FromR8(dbl, pui64Out);
2697 return hRet;
2701 /* R4
2704 /************************************************************************
2705 * VarR4FromUI1 (OLEAUT32.68)
2707 * Convert a VT_UI1 to a VT_R4.
2709 * PARAMS
2710 * bIn [I] Source
2711 * pFltOut [O] Destination
2713 * RETURNS
2714 * S_OK.
2716 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
2718 return _VarR4FromUI1(bIn, pFltOut);
2721 /************************************************************************
2722 * VarR4FromI2 (OLEAUT32.69)
2724 * Convert a VT_I2 to a VT_R4.
2726 * PARAMS
2727 * sIn [I] Source
2728 * pFltOut [O] Destination
2730 * RETURNS
2731 * S_OK.
2733 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
2735 return _VarR4FromI2(sIn, pFltOut);
2738 /************************************************************************
2739 * VarR4FromI4 (OLEAUT32.70)
2741 * Convert a VT_I4 to a VT_R4.
2743 * PARAMS
2744 * sIn [I] Source
2745 * pFltOut [O] Destination
2747 * RETURNS
2748 * S_OK.
2750 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
2752 return _VarR4FromI4(lIn, pFltOut);
2755 /************************************************************************
2756 * VarR4FromR8 (OLEAUT32.71)
2758 * Convert a VT_R8 to a VT_R4.
2760 * PARAMS
2761 * dblIn [I] Source
2762 * pFltOut [O] Destination
2764 * RETURNS
2765 * Success: S_OK.
2766 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2768 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
2770 double d = dblIn < 0.0 ? -dblIn : dblIn;
2771 if (d > R4_MAX) return DISP_E_OVERFLOW;
2772 *pFltOut = dblIn;
2773 return S_OK;
2776 /************************************************************************
2777 * VarR4FromCy (OLEAUT32.72)
2779 * Convert a VT_CY to a VT_R4.
2781 * PARAMS
2782 * cyIn [I] Source
2783 * pFltOut [O] Destination
2785 * RETURNS
2786 * S_OK.
2788 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
2790 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
2791 return S_OK;
2794 /************************************************************************
2795 * VarR4FromDate (OLEAUT32.73)
2797 * Convert a VT_DATE to a VT_R4.
2799 * PARAMS
2800 * dateIn [I] Source
2801 * pFltOut [O] Destination
2803 * RETURNS
2804 * Success: S_OK.
2805 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2807 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
2809 return VarR4FromR8(dateIn, pFltOut);
2812 /************************************************************************
2813 * VarR4FromStr (OLEAUT32.74)
2815 * Convert a VT_BSTR to a VT_R4.
2817 * PARAMS
2818 * strIn [I] Source
2819 * lcid [I] LCID for the conversion
2820 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2821 * pFltOut [O] Destination
2823 * RETURNS
2824 * Success: S_OK.
2825 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2826 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2828 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
2830 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
2833 /************************************************************************
2834 * VarR4FromDisp (OLEAUT32.75)
2836 * Convert a VT_DISPATCH to a VT_R4.
2838 * PARAMS
2839 * pdispIn [I] Source
2840 * lcid [I] LCID for conversion
2841 * pFltOut [O] Destination
2843 * RETURNS
2844 * Success: S_OK.
2845 * Failure: E_INVALIDARG, if the source value is invalid
2846 * DISP_E_OVERFLOW, if the value will not fit in the destination
2847 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2849 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
2851 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0);
2854 /************************************************************************
2855 * VarR4FromBool (OLEAUT32.76)
2857 * Convert a VT_BOOL to a VT_R4.
2859 * PARAMS
2860 * boolIn [I] Source
2861 * pFltOut [O] Destination
2863 * RETURNS
2864 * S_OK.
2866 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2868 return VarR4FromI2(boolIn, pFltOut);
2871 /************************************************************************
2872 * VarR4FromI1 (OLEAUT32.213)
2874 * Convert a VT_I1 to a VT_R4.
2876 * PARAMS
2877 * cIn [I] Source
2878 * pFltOut [O] Destination
2880 * RETURNS
2881 * Success: S_OK.
2882 * Failure: E_INVALIDARG, if the source value is invalid
2883 * DISP_E_OVERFLOW, if the value will not fit in the destination
2884 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2886 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2888 return _VarR4FromI1(cIn, pFltOut);
2891 /************************************************************************
2892 * VarR4FromUI2 (OLEAUT32.214)
2894 * Convert a VT_UI2 to a VT_R4.
2896 * PARAMS
2897 * usIn [I] Source
2898 * pFltOut [O] Destination
2900 * RETURNS
2901 * Success: S_OK.
2902 * Failure: E_INVALIDARG, if the source value is invalid
2903 * DISP_E_OVERFLOW, if the value will not fit in the destination
2904 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2906 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2908 return _VarR4FromUI2(usIn, pFltOut);
2911 /************************************************************************
2912 * VarR4FromUI4 (OLEAUT32.215)
2914 * Convert a VT_UI4 to a VT_R4.
2916 * PARAMS
2917 * ulIn [I] Source
2918 * pFltOut [O] Destination
2920 * RETURNS
2921 * Success: S_OK.
2922 * Failure: E_INVALIDARG, if the source value is invalid
2923 * DISP_E_OVERFLOW, if the value will not fit in the destination
2924 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2926 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2928 return _VarR4FromUI4(ulIn, pFltOut);
2931 /************************************************************************
2932 * VarR4FromDec (OLEAUT32.216)
2934 * Convert a VT_DECIMAL to a VT_R4.
2936 * PARAMS
2937 * pDecIn [I] Source
2938 * pFltOut [O] Destination
2940 * RETURNS
2941 * Success: S_OK.
2942 * Failure: E_INVALIDARG, if the source value is invalid.
2944 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
2946 BYTE scale = DEC_SCALE(pDecIn);
2947 double divisor = 1.0;
2948 double highPart;
2950 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2951 return E_INVALIDARG;
2953 while (scale--)
2954 divisor *= 10.0;
2956 if (DEC_SIGN(pDecIn))
2957 divisor = -divisor;
2959 if (DEC_HI32(pDecIn))
2961 highPart = (double)DEC_HI32(pDecIn) / divisor;
2962 highPart *= 4294967296.0F;
2963 highPart *= 4294967296.0F;
2965 else
2966 highPart = 0.0;
2968 *pFltOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
2969 return S_OK;
2972 /************************************************************************
2973 * VarR4FromI8 (OLEAUT32.360)
2975 * Convert a VT_I8 to a VT_R4.
2977 * PARAMS
2978 * ullIn [I] Source
2979 * pFltOut [O] Destination
2981 * RETURNS
2982 * S_OK.
2984 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2986 return _VarR4FromI8(llIn, pFltOut);
2989 /************************************************************************
2990 * VarR4FromUI8 (OLEAUT32.361)
2992 * Convert a VT_UI8 to a VT_R4.
2994 * PARAMS
2995 * ullIn [I] Source
2996 * pFltOut [O] Destination
2998 * RETURNS
2999 * S_OK.
3001 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
3003 return _VarR4FromUI8(ullIn, pFltOut);
3006 /************************************************************************
3007 * VarR4CmpR8 (OLEAUT32.316)
3009 * Compare a VT_R4 to a VT_R8.
3011 * PARAMS
3012 * fltLeft [I] Source
3013 * dblRight [I] Value to compare
3015 * RETURNS
3016 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3017 * equal to or greater than dblRight respectively.
3019 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3021 if (fltLeft < dblRight)
3022 return VARCMP_LT;
3023 else if (fltLeft > dblRight)
3024 return VARCMP_GT;
3025 return VARCMP_EQ;
3028 /* R8
3031 /************************************************************************
3032 * VarR8FromUI1 (OLEAUT32.78)
3034 * Convert a VT_UI1 to a VT_R8.
3036 * PARAMS
3037 * bIn [I] Source
3038 * pDblOut [O] Destination
3040 * RETURNS
3041 * S_OK.
3043 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3045 return _VarR8FromUI1(bIn, pDblOut);
3048 /************************************************************************
3049 * VarR8FromI2 (OLEAUT32.79)
3051 * Convert a VT_I2 to a VT_R8.
3053 * PARAMS
3054 * sIn [I] Source
3055 * pDblOut [O] Destination
3057 * RETURNS
3058 * S_OK.
3060 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3062 return _VarR8FromI2(sIn, pDblOut);
3065 /************************************************************************
3066 * VarR8FromI4 (OLEAUT32.80)
3068 * Convert a VT_I4 to a VT_R8.
3070 * PARAMS
3071 * sIn [I] Source
3072 * pDblOut [O] Destination
3074 * RETURNS
3075 * S_OK.
3077 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3079 return _VarR8FromI4(lIn, pDblOut);
3082 /************************************************************************
3083 * VarR8FromR4 (OLEAUT32.81)
3085 * Convert a VT_R4 to a VT_R8.
3087 * PARAMS
3088 * fltIn [I] Source
3089 * pDblOut [O] Destination
3091 * RETURNS
3092 * S_OK.
3094 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3096 return _VarR8FromR4(fltIn, pDblOut);
3099 /************************************************************************
3100 * VarR8FromCy (OLEAUT32.82)
3102 * Convert a VT_CY to a VT_R8.
3104 * PARAMS
3105 * cyIn [I] Source
3106 * pDblOut [O] Destination
3108 * RETURNS
3109 * S_OK.
3111 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3113 return _VarR8FromCy(cyIn, pDblOut);
3116 /************************************************************************
3117 * VarR8FromDate (OLEAUT32.83)
3119 * Convert a VT_DATE to a VT_R8.
3121 * PARAMS
3122 * dateIn [I] Source
3123 * pDblOut [O] Destination
3125 * RETURNS
3126 * S_OK.
3128 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3130 return _VarR8FromDate(dateIn, pDblOut);
3133 /************************************************************************
3134 * VarR8FromStr (OLEAUT32.84)
3136 * Convert a VT_BSTR to a VT_R8.
3138 * PARAMS
3139 * strIn [I] Source
3140 * lcid [I] LCID for the conversion
3141 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3142 * pDblOut [O] Destination
3144 * RETURNS
3145 * Success: S_OK.
3146 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3147 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3149 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3151 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3154 /************************************************************************
3155 * VarR8FromDisp (OLEAUT32.85)
3157 * Convert a VT_DISPATCH to a VT_R8.
3159 * PARAMS
3160 * pdispIn [I] Source
3161 * lcid [I] LCID for conversion
3162 * pDblOut [O] Destination
3164 * RETURNS
3165 * Success: S_OK.
3166 * Failure: E_INVALIDARG, if the source value is invalid
3167 * DISP_E_OVERFLOW, if the value will not fit in the destination
3168 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3170 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3172 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0);
3175 /************************************************************************
3176 * VarR8FromBool (OLEAUT32.86)
3178 * Convert a VT_BOOL to a VT_R8.
3180 * PARAMS
3181 * boolIn [I] Source
3182 * pDblOut [O] Destination
3184 * RETURNS
3185 * S_OK.
3187 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3189 return VarR8FromI2(boolIn, pDblOut);
3192 /************************************************************************
3193 * VarR8FromI1 (OLEAUT32.217)
3195 * Convert a VT_I1 to a VT_R8.
3197 * PARAMS
3198 * cIn [I] Source
3199 * pDblOut [O] Destination
3201 * RETURNS
3202 * Success: S_OK.
3203 * Failure: E_INVALIDARG, if the source value is invalid
3204 * DISP_E_OVERFLOW, if the value will not fit in the destination
3205 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3207 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3209 return _VarR8FromI1(cIn, pDblOut);
3212 /************************************************************************
3213 * VarR8FromUI2 (OLEAUT32.218)
3215 * Convert a VT_UI2 to a VT_R8.
3217 * PARAMS
3218 * usIn [I] Source
3219 * pDblOut [O] Destination
3221 * RETURNS
3222 * Success: S_OK.
3223 * Failure: E_INVALIDARG, if the source value is invalid
3224 * DISP_E_OVERFLOW, if the value will not fit in the destination
3225 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3227 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3229 return _VarR8FromUI2(usIn, pDblOut);
3232 /************************************************************************
3233 * VarR8FromUI4 (OLEAUT32.219)
3235 * Convert a VT_UI4 to a VT_R8.
3237 * PARAMS
3238 * ulIn [I] Source
3239 * pDblOut [O] Destination
3241 * RETURNS
3242 * Success: S_OK.
3243 * Failure: E_INVALIDARG, if the source value is invalid
3244 * DISP_E_OVERFLOW, if the value will not fit in the destination
3245 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3247 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3249 return _VarR8FromUI4(ulIn, pDblOut);
3252 /************************************************************************
3253 * VarR8FromDec (OLEAUT32.220)
3255 * Convert a VT_DECIMAL to a VT_R8.
3257 * PARAMS
3258 * pDecIn [I] Source
3259 * pDblOut [O] Destination
3261 * RETURNS
3262 * Success: S_OK.
3263 * Failure: E_INVALIDARG, if the source value is invalid.
3265 HRESULT WINAPI VarR8FromDec(const DECIMAL* pDecIn, double *pDblOut)
3267 BYTE scale = DEC_SCALE(pDecIn);
3268 double divisor = 1.0, highPart;
3270 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3271 return E_INVALIDARG;
3273 while (scale--)
3274 divisor *= 10;
3276 if (DEC_SIGN(pDecIn))
3277 divisor = -divisor;
3279 if (DEC_HI32(pDecIn))
3281 highPart = (double)DEC_HI32(pDecIn) / divisor;
3282 highPart *= 4294967296.0F;
3283 highPart *= 4294967296.0F;
3285 else
3286 highPart = 0.0;
3288 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3289 return S_OK;
3292 /************************************************************************
3293 * VarR8FromI8 (OLEAUT32.362)
3295 * Convert a VT_I8 to a VT_R8.
3297 * PARAMS
3298 * ullIn [I] Source
3299 * pDblOut [O] Destination
3301 * RETURNS
3302 * S_OK.
3304 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3306 return _VarR8FromI8(llIn, pDblOut);
3309 /************************************************************************
3310 * VarR8FromUI8 (OLEAUT32.363)
3312 * Convert a VT_UI8 to a VT_R8.
3314 * PARAMS
3315 * ullIn [I] Source
3316 * pDblOut [O] Destination
3318 * RETURNS
3319 * S_OK.
3321 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3323 return _VarR8FromUI8(ullIn, pDblOut);
3326 /************************************************************************
3327 * VarR8Pow (OLEAUT32.315)
3329 * Raise a VT_R8 to a power.
3331 * PARAMS
3332 * dblLeft [I] Source
3333 * dblPow [I] Power to raise dblLeft by
3334 * pDblOut [O] Destination
3336 * RETURNS
3337 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3339 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3341 *pDblOut = pow(dblLeft, dblPow);
3342 return S_OK;
3345 /************************************************************************
3346 * VarR8Round (OLEAUT32.317)
3348 * Round a VT_R8 to a given number of decimal points.
3350 * PARAMS
3351 * dblIn [I] Source
3352 * nDig [I] Number of decimal points to round to
3353 * pDblOut [O] Destination for rounded number
3355 * RETURNS
3356 * Success: S_OK. pDblOut is rounded to nDig digits.
3357 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3359 * NOTES
3360 * The native version of this function rounds using the internal
3361 * binary representation of the number. Wine uses the dutch rounding
3362 * convention, so therefore small differences can occur in the value returned.
3363 * MSDN says that you should use your own rounding function if you want
3364 * rounding to be predictable in your application.
3366 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3368 double scale, whole, fract;
3370 if (nDig < 0)
3371 return E_INVALIDARG;
3373 scale = pow(10.0, nDig);
3375 dblIn *= scale;
3376 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3377 fract = dblIn - whole;
3379 if (fract > 0.5)
3380 dblIn = whole + 1.0;
3381 else if (fract == 0.5)
3382 dblIn = whole + fmod(whole, 2.0);
3383 else if (fract >= 0.0)
3384 dblIn = whole;
3385 else if (fract == -0.5)
3386 dblIn = whole - fmod(whole, 2.0);
3387 else if (fract > -0.5)
3388 dblIn = whole;
3389 else
3390 dblIn = whole - 1.0;
3392 *pDblOut = dblIn / scale;
3393 return S_OK;
3396 /* CY
3399 /* Powers of 10 from 0..4 D.P. */
3400 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3401 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3403 /************************************************************************
3404 * VarCyFromUI1 (OLEAUT32.98)
3406 * Convert a VT_UI1 to a VT_CY.
3408 * PARAMS
3409 * bIn [I] Source
3410 * pCyOut [O] Destination
3412 * RETURNS
3413 * Success: S_OK.
3414 * Failure: E_INVALIDARG, if the source value is invalid
3415 * DISP_E_OVERFLOW, if the value will not fit in the destination
3416 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3418 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3420 pCyOut->int64 = (ULONG64)bIn * CY_MULTIPLIER;
3421 return S_OK;
3424 /************************************************************************
3425 * VarCyFromI2 (OLEAUT32.99)
3427 * Convert a VT_I2 to a VT_CY.
3429 * PARAMS
3430 * sIn [I] Source
3431 * pCyOut [O] Destination
3433 * RETURNS
3434 * Success: S_OK.
3435 * Failure: E_INVALIDARG, if the source value is invalid
3436 * DISP_E_OVERFLOW, if the value will not fit in the destination
3437 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3439 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3441 pCyOut->int64 = (LONG64)sIn * CY_MULTIPLIER;
3442 return S_OK;
3445 /************************************************************************
3446 * VarCyFromI4 (OLEAUT32.100)
3448 * Convert a VT_I4 to a VT_CY.
3450 * PARAMS
3451 * sIn [I] Source
3452 * pCyOut [O] Destination
3454 * RETURNS
3455 * Success: S_OK.
3456 * Failure: E_INVALIDARG, if the source value is invalid
3457 * DISP_E_OVERFLOW, if the value will not fit in the destination
3458 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3460 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3462 pCyOut->int64 = (LONG64)lIn * CY_MULTIPLIER;
3463 return S_OK;
3466 /************************************************************************
3467 * VarCyFromR4 (OLEAUT32.101)
3469 * Convert a VT_R4 to a VT_CY.
3471 * PARAMS
3472 * fltIn [I] Source
3473 * pCyOut [O] Destination
3475 * RETURNS
3476 * Success: S_OK.
3477 * Failure: E_INVALIDARG, if the source value is invalid
3478 * DISP_E_OVERFLOW, if the value will not fit in the destination
3479 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3481 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3483 return VarCyFromR8(fltIn, pCyOut);
3486 /************************************************************************
3487 * VarCyFromR8 (OLEAUT32.102)
3489 * Convert a VT_R8 to a VT_CY.
3491 * PARAMS
3492 * dblIn [I] Source
3493 * pCyOut [O] Destination
3495 * RETURNS
3496 * Success: S_OK.
3497 * Failure: E_INVALIDARG, if the source value is invalid
3498 * DISP_E_OVERFLOW, if the value will not fit in the destination
3499 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3501 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3503 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3504 /* This code gives identical results to Win32 on Intel.
3505 * Here we use fp exceptions to catch overflows when storing the value.
3507 static const unsigned short r8_fpcontrol = 0x137f;
3508 static const double r8_multiplier = CY_MULTIPLIER_F;
3509 unsigned short old_fpcontrol, result_fpstatus;
3511 /* Clear exceptions, save the old fp state and load the new state */
3512 __asm__ __volatile__( "fnclex" );
3513 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3514 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3515 /* Perform the conversion. */
3516 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3517 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3518 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3519 /* Save the resulting fp state, load the old state and clear exceptions */
3520 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3521 __asm__ __volatile__( "fnclex" );
3522 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3524 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3525 return DISP_E_OVERFLOW;
3526 #else
3527 /* This version produces slightly different results for boundary cases */
3528 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3529 return DISP_E_OVERFLOW;
3530 dblIn *= CY_MULTIPLIER_F;
3531 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3532 #endif
3533 return S_OK;
3536 /************************************************************************
3537 * VarCyFromDate (OLEAUT32.103)
3539 * Convert a VT_DATE to a VT_CY.
3541 * PARAMS
3542 * dateIn [I] Source
3543 * pCyOut [O] Destination
3545 * RETURNS
3546 * Success: S_OK.
3547 * Failure: E_INVALIDARG, if the source value is invalid
3548 * DISP_E_OVERFLOW, if the value will not fit in the destination
3549 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3551 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3553 return VarCyFromR8(dateIn, pCyOut);
3556 /************************************************************************
3557 * VarCyFromStr (OLEAUT32.104)
3559 * Convert a VT_BSTR to a VT_CY.
3561 * PARAMS
3562 * strIn [I] Source
3563 * lcid [I] LCID for the conversion
3564 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3565 * pCyOut [O] Destination
3567 * RETURNS
3568 * Success: S_OK.
3569 * Failure: E_INVALIDARG, if the source value is invalid
3570 * DISP_E_OVERFLOW, if the value will not fit in the destination
3571 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3573 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3575 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3578 /************************************************************************
3579 * VarCyFromDisp (OLEAUT32.105)
3581 * Convert a VT_DISPATCH to a VT_CY.
3583 * PARAMS
3584 * pdispIn [I] Source
3585 * lcid [I] LCID for conversion
3586 * pCyOut [O] Destination
3588 * RETURNS
3589 * Success: S_OK.
3590 * Failure: E_INVALIDARG, if the source value is invalid
3591 * DISP_E_OVERFLOW, if the value will not fit in the destination
3592 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3594 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3596 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0);
3599 /************************************************************************
3600 * VarCyFromBool (OLEAUT32.106)
3602 * Convert a VT_BOOL to a VT_CY.
3604 * PARAMS
3605 * boolIn [I] Source
3606 * pCyOut [O] Destination
3608 * RETURNS
3609 * Success: S_OK.
3610 * Failure: E_INVALIDARG, if the source value is invalid
3611 * DISP_E_OVERFLOW, if the value will not fit in the destination
3612 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3614 * NOTES
3615 * While the sign of the boolean is stored in the currency, the value is
3616 * converted to either 0 or 1.
3618 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3620 pCyOut->int64 = (LONG64)boolIn * CY_MULTIPLIER;
3621 return S_OK;
3624 /************************************************************************
3625 * VarCyFromI1 (OLEAUT32.225)
3627 * Convert a VT_I1 to a VT_CY.
3629 * PARAMS
3630 * cIn [I] Source
3631 * pCyOut [O] Destination
3633 * RETURNS
3634 * Success: S_OK.
3635 * Failure: E_INVALIDARG, if the source value is invalid
3636 * DISP_E_OVERFLOW, if the value will not fit in the destination
3637 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3639 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3641 pCyOut->int64 = (LONG64)cIn * CY_MULTIPLIER;
3642 return S_OK;
3645 /************************************************************************
3646 * VarCyFromUI2 (OLEAUT32.226)
3648 * Convert a VT_UI2 to a VT_CY.
3650 * PARAMS
3651 * usIn [I] Source
3652 * pCyOut [O] Destination
3654 * RETURNS
3655 * Success: S_OK.
3656 * Failure: E_INVALIDARG, if the source value is invalid
3657 * DISP_E_OVERFLOW, if the value will not fit in the destination
3658 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3660 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3662 pCyOut->int64 = (ULONG64)usIn * CY_MULTIPLIER;
3663 return S_OK;
3666 /************************************************************************
3667 * VarCyFromUI4 (OLEAUT32.227)
3669 * Convert a VT_UI4 to a VT_CY.
3671 * PARAMS
3672 * ulIn [I] Source
3673 * pCyOut [O] Destination
3675 * RETURNS
3676 * Success: S_OK.
3677 * Failure: E_INVALIDARG, if the source value is invalid
3678 * DISP_E_OVERFLOW, if the value will not fit in the destination
3679 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3681 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3683 pCyOut->int64 = (ULONG64)ulIn * CY_MULTIPLIER;
3684 return S_OK;
3687 /************************************************************************
3688 * VarCyFromDec (OLEAUT32.228)
3690 * Convert a VT_DECIMAL to a VT_CY.
3692 * PARAMS
3693 * pdecIn [I] Source
3694 * pCyOut [O] Destination
3696 * RETURNS
3697 * Success: S_OK.
3698 * Failure: E_INVALIDARG, if the source value is invalid
3699 * DISP_E_OVERFLOW, if the value will not fit in the destination
3700 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3702 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
3704 DECIMAL rounded;
3705 HRESULT hRet;
3707 hRet = VarDecRound(pdecIn, 4, &rounded);
3709 if (SUCCEEDED(hRet))
3711 double d;
3713 if (DEC_HI32(&rounded))
3714 return DISP_E_OVERFLOW;
3716 /* Note: Without the casts this promotes to int64 which loses precision */
3717 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3718 if (DEC_SIGN(&rounded))
3719 d = -d;
3720 return VarCyFromR8(d, pCyOut);
3722 return hRet;
3725 /************************************************************************
3726 * VarCyFromI8 (OLEAUT32.366)
3728 * Convert a VT_I8 to a VT_CY.
3730 * PARAMS
3731 * ullIn [I] Source
3732 * pCyOut [O] Destination
3734 * RETURNS
3735 * Success: S_OK.
3736 * Failure: E_INVALIDARG, if the source value is invalid
3737 * DISP_E_OVERFLOW, if the value will not fit in the destination
3738 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3740 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3742 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3743 pCyOut->int64 = llIn * CY_MULTIPLIER;
3744 return S_OK;
3747 /************************************************************************
3748 * VarCyFromUI8 (OLEAUT32.375)
3750 * Convert a VT_UI8 to a VT_CY.
3752 * PARAMS
3753 * ullIn [I] Source
3754 * pCyOut [O] Destination
3756 * RETURNS
3757 * Success: S_OK.
3758 * Failure: E_INVALIDARG, if the source value is invalid
3759 * DISP_E_OVERFLOW, if the value will not fit in the destination
3760 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3762 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3764 if (ullIn > (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3765 pCyOut->int64 = ullIn * CY_MULTIPLIER;
3766 return S_OK;
3769 /************************************************************************
3770 * VarCyAdd (OLEAUT32.299)
3772 * Add one CY to another.
3774 * PARAMS
3775 * cyLeft [I] Source
3776 * cyRight [I] Value to add
3777 * pCyOut [O] Destination
3779 * RETURNS
3780 * Success: S_OK.
3781 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3783 HRESULT WINAPI VarCyAdd(CY cyLeft, CY cyRight, CY* pCyOut)
3785 double l,r;
3786 _VarR8FromCy(cyLeft, &l);
3787 _VarR8FromCy(cyRight, &r);
3788 l = l + r;
3789 return VarCyFromR8(l, pCyOut);
3792 /************************************************************************
3793 * VarCyMul (OLEAUT32.303)
3795 * Multiply one CY by another.
3797 * PARAMS
3798 * cyLeft [I] Source
3799 * cyRight [I] Value to multiply by
3800 * pCyOut [O] Destination
3802 * RETURNS
3803 * Success: S_OK.
3804 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3806 HRESULT WINAPI VarCyMul(CY cyLeft, CY cyRight, CY* pCyOut)
3808 double l,r;
3809 _VarR8FromCy(cyLeft, &l);
3810 _VarR8FromCy(cyRight, &r);
3811 l = l * r;
3812 return VarCyFromR8(l, pCyOut);
3815 /************************************************************************
3816 * VarCyMulI4 (OLEAUT32.304)
3818 * Multiply one CY by a VT_I4.
3820 * PARAMS
3821 * cyLeft [I] Source
3822 * lRight [I] Value to multiply by
3823 * pCyOut [O] Destination
3825 * RETURNS
3826 * Success: S_OK.
3827 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3829 HRESULT WINAPI VarCyMulI4(CY cyLeft, LONG lRight, CY* pCyOut)
3831 double d;
3833 _VarR8FromCy(cyLeft, &d);
3834 d = d * lRight;
3835 return VarCyFromR8(d, pCyOut);
3838 /************************************************************************
3839 * VarCySub (OLEAUT32.305)
3841 * Subtract one CY from another.
3843 * PARAMS
3844 * cyLeft [I] Source
3845 * cyRight [I] Value to subtract
3846 * pCyOut [O] Destination
3848 * RETURNS
3849 * Success: S_OK.
3850 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3852 HRESULT WINAPI VarCySub(CY cyLeft, CY cyRight, CY* pCyOut)
3854 double l,r;
3855 _VarR8FromCy(cyLeft, &l);
3856 _VarR8FromCy(cyRight, &r);
3857 l = l - r;
3858 return VarCyFromR8(l, pCyOut);
3861 /************************************************************************
3862 * VarCyAbs (OLEAUT32.306)
3864 * Convert a VT_CY into its absolute value.
3866 * PARAMS
3867 * cyIn [I] Source
3868 * pCyOut [O] Destination
3870 * RETURNS
3871 * Success: S_OK. pCyOut contains the absolute value.
3872 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3874 HRESULT WINAPI VarCyAbs(CY cyIn, CY* pCyOut)
3876 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3877 return DISP_E_OVERFLOW;
3879 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3880 return S_OK;
3883 /************************************************************************
3884 * VarCyFix (OLEAUT32.307)
3886 * Return the integer part of a VT_CY.
3888 * PARAMS
3889 * cyIn [I] Source
3890 * pCyOut [O] Destination
3892 * RETURNS
3893 * Success: S_OK.
3894 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3896 * NOTES
3897 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3898 * negative numbers away from 0, while this function rounds them towards zero.
3900 HRESULT WINAPI VarCyFix(CY cyIn, CY* pCyOut)
3902 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3903 pCyOut->int64 *= CY_MULTIPLIER;
3904 return S_OK;
3907 /************************************************************************
3908 * VarCyInt (OLEAUT32.308)
3910 * Return the integer part of a VT_CY.
3912 * PARAMS
3913 * cyIn [I] Source
3914 * pCyOut [O] Destination
3916 * RETURNS
3917 * Success: S_OK.
3918 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3920 * NOTES
3921 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3922 * negative numbers towards 0, while this function rounds them away from zero.
3924 HRESULT WINAPI VarCyInt(CY cyIn, CY* pCyOut)
3926 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3927 pCyOut->int64 *= CY_MULTIPLIER;
3929 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3931 pCyOut->int64 -= CY_MULTIPLIER;
3933 return S_OK;
3936 /************************************************************************
3937 * VarCyNeg (OLEAUT32.309)
3939 * Change the sign of a VT_CY.
3941 * PARAMS
3942 * cyIn [I] Source
3943 * pCyOut [O] Destination
3945 * RETURNS
3946 * Success: S_OK.
3947 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3949 HRESULT WINAPI VarCyNeg(CY cyIn, CY* pCyOut)
3951 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3952 return DISP_E_OVERFLOW;
3954 pCyOut->int64 = -cyIn.int64;
3955 return S_OK;
3958 /************************************************************************
3959 * VarCyRound (OLEAUT32.310)
3961 * Change the precision of a VT_CY.
3963 * PARAMS
3964 * cyIn [I] Source
3965 * cDecimals [I] New number of decimals to keep
3966 * pCyOut [O] Destination
3968 * RETURNS
3969 * Success: S_OK.
3970 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3972 HRESULT WINAPI VarCyRound(CY cyIn, int cDecimals, CY* pCyOut)
3974 if (cDecimals < 0)
3975 return E_INVALIDARG;
3977 if (cDecimals > 3)
3979 /* Rounding to more precision than we have */
3980 *pCyOut = cyIn;
3981 return S_OK;
3983 else
3985 double d, div = CY_Divisors[cDecimals];
3987 _VarR8FromCy(cyIn, &d);
3988 d = d * div;
3989 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3990 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3991 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3992 return S_OK;
3996 /************************************************************************
3997 * VarCyCmp (OLEAUT32.311)
3999 * Compare two VT_CY values.
4001 * PARAMS
4002 * cyLeft [I] Source
4003 * cyRight [I] Value to compare
4005 * RETURNS
4006 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4007 * compare is less, equal or greater than source respectively.
4008 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4010 HRESULT WINAPI VarCyCmp(CY cyLeft, CY cyRight)
4012 HRESULT hRet;
4013 CY result;
4015 /* Subtract right from left, and compare the result to 0 */
4016 hRet = VarCySub(cyLeft, cyRight, &result);
4018 if (SUCCEEDED(hRet))
4020 if (result.int64 < 0)
4021 hRet = (HRESULT)VARCMP_LT;
4022 else if (result.int64 > 0)
4023 hRet = (HRESULT)VARCMP_GT;
4024 else
4025 hRet = (HRESULT)VARCMP_EQ;
4027 return hRet;
4030 /************************************************************************
4031 * VarCyCmpR8 (OLEAUT32.312)
4033 * Compare a VT_CY to a double
4035 * PARAMS
4036 * cyLeft [I] Currency Source
4037 * dblRight [I] double to compare to cyLeft
4039 * RETURNS
4040 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4041 * less than, equal to or greater than cyLeft respectively.
4042 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4044 HRESULT WINAPI VarCyCmpR8(CY cyLeft, double dblRight)
4046 HRESULT hRet;
4047 CY cyRight;
4049 hRet = VarCyFromR8(dblRight, &cyRight);
4051 if (SUCCEEDED(hRet))
4052 hRet = VarCyCmp(cyLeft, cyRight);
4054 return hRet;
4057 /************************************************************************
4058 * VarCyMulI8 (OLEAUT32.329)
4060 * Multiply a VT_CY by a VT_I8.
4062 * PARAMS
4063 * cyLeft [I] Source
4064 * llRight [I] Value to multiply by
4065 * pCyOut [O] Destination
4067 * RETURNS
4068 * Success: S_OK.
4069 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4071 HRESULT WINAPI VarCyMulI8(CY cyLeft, LONG64 llRight, CY* pCyOut)
4073 double d;
4075 _VarR8FromCy(cyLeft, &d);
4076 d = d * (double)llRight;
4077 return VarCyFromR8(d, pCyOut);
4080 /* DECIMAL
4083 /************************************************************************
4084 * VarDecFromUI1 (OLEAUT32.190)
4086 * Convert a VT_UI1 to a DECIMAL.
4088 * PARAMS
4089 * bIn [I] Source
4090 * pDecOut [O] Destination
4092 * RETURNS
4093 * S_OK.
4095 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4097 return VarDecFromUI4(bIn, pDecOut);
4100 /************************************************************************
4101 * VarDecFromI2 (OLEAUT32.191)
4103 * Convert a VT_I2 to a DECIMAL.
4105 * PARAMS
4106 * sIn [I] Source
4107 * pDecOut [O] Destination
4109 * RETURNS
4110 * S_OK.
4112 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4114 return VarDecFromI4(sIn, pDecOut);
4117 /************************************************************************
4118 * VarDecFromI4 (OLEAUT32.192)
4120 * Convert a VT_I4 to a DECIMAL.
4122 * PARAMS
4123 * sIn [I] Source
4124 * pDecOut [O] Destination
4126 * RETURNS
4127 * S_OK.
4129 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4131 DEC_HI32(pDecOut) = 0;
4132 DEC_MID32(pDecOut) = 0;
4134 if (lIn < 0)
4136 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4137 DEC_LO32(pDecOut) = -lIn;
4139 else
4141 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4142 DEC_LO32(pDecOut) = lIn;
4144 return S_OK;
4147 /* internal representation of the value stored in a DECIMAL. The bytes are
4148 stored from LSB at index 0 to MSB at index 11
4150 typedef struct DECIMAL_internal
4152 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4153 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4154 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4155 } VARIANT_DI;
4157 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest);
4158 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest);
4159 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to);
4160 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to);
4161 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor);
4162 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n);
4164 /************************************************************************
4165 * VarDecFromR4 (OLEAUT32.193)
4167 * Convert a VT_R4 to a DECIMAL.
4169 * PARAMS
4170 * fltIn [I] Source
4171 * pDecOut [O] Destination
4173 * RETURNS
4174 * S_OK.
4176 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4178 VARIANT_DI di;
4179 HRESULT hres;
4181 hres = VARIANT_DI_FromR4(fltIn, &di);
4182 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4183 return hres;
4186 /************************************************************************
4187 * VarDecFromR8 (OLEAUT32.194)
4189 * Convert a VT_R8 to a DECIMAL.
4191 * PARAMS
4192 * dblIn [I] Source
4193 * pDecOut [O] Destination
4195 * RETURNS
4196 * S_OK.
4198 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4200 VARIANT_DI di;
4201 HRESULT hres;
4203 hres = VARIANT_DI_FromR8(dblIn, &di);
4204 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4205 return hres;
4208 /************************************************************************
4209 * VarDecFromDate (OLEAUT32.195)
4211 * Convert a VT_DATE to a DECIMAL.
4213 * PARAMS
4214 * dateIn [I] Source
4215 * pDecOut [O] Destination
4217 * RETURNS
4218 * S_OK.
4220 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4222 return VarDecFromR8(dateIn, pDecOut);
4225 /************************************************************************
4226 * VarDecFromCy (OLEAUT32.196)
4228 * Convert a VT_CY to a DECIMAL.
4230 * PARAMS
4231 * cyIn [I] Source
4232 * pDecOut [O] Destination
4234 * RETURNS
4235 * S_OK.
4237 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4239 DEC_HI32(pDecOut) = 0;
4241 /* Note: This assumes 2s complement integer representation */
4242 if (cyIn.s.Hi & 0x80000000)
4244 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4245 DEC_LO64(pDecOut) = -cyIn.int64;
4247 else
4249 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4250 DEC_MID32(pDecOut) = cyIn.s.Hi;
4251 DEC_LO32(pDecOut) = cyIn.s.Lo;
4253 return S_OK;
4256 /************************************************************************
4257 * VarDecFromStr (OLEAUT32.197)
4259 * Convert a VT_BSTR to a DECIMAL.
4261 * PARAMS
4262 * strIn [I] Source
4263 * lcid [I] LCID for the conversion
4264 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4265 * pDecOut [O] Destination
4267 * RETURNS
4268 * Success: S_OK.
4269 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4271 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4273 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4276 /************************************************************************
4277 * VarDecFromDisp (OLEAUT32.198)
4279 * Convert a VT_DISPATCH to a DECIMAL.
4281 * PARAMS
4282 * pdispIn [I] Source
4283 * lcid [I] LCID for conversion
4284 * pDecOut [O] Destination
4286 * RETURNS
4287 * Success: S_OK.
4288 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4290 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4292 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0);
4295 /************************************************************************
4296 * VarDecFromBool (OLEAUT32.199)
4298 * Convert a VT_BOOL to a DECIMAL.
4300 * PARAMS
4301 * bIn [I] Source
4302 * pDecOut [O] Destination
4304 * RETURNS
4305 * S_OK.
4307 * NOTES
4308 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4310 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4312 DEC_HI32(pDecOut) = 0;
4313 DEC_MID32(pDecOut) = 0;
4314 if (bIn)
4316 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4317 DEC_LO32(pDecOut) = 1;
4319 else
4321 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4322 DEC_LO32(pDecOut) = 0;
4324 return S_OK;
4327 /************************************************************************
4328 * VarDecFromI1 (OLEAUT32.241)
4330 * Convert a VT_I1 to a DECIMAL.
4332 * PARAMS
4333 * cIn [I] Source
4334 * pDecOut [O] Destination
4336 * RETURNS
4337 * S_OK.
4339 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4341 return VarDecFromI4(cIn, pDecOut);
4344 /************************************************************************
4345 * VarDecFromUI2 (OLEAUT32.242)
4347 * Convert a VT_UI2 to a DECIMAL.
4349 * PARAMS
4350 * usIn [I] Source
4351 * pDecOut [O] Destination
4353 * RETURNS
4354 * S_OK.
4356 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4358 return VarDecFromUI4(usIn, pDecOut);
4361 /************************************************************************
4362 * VarDecFromUI4 (OLEAUT32.243)
4364 * Convert a VT_UI4 to a DECIMAL.
4366 * PARAMS
4367 * ulIn [I] Source
4368 * pDecOut [O] Destination
4370 * RETURNS
4371 * S_OK.
4373 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4375 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4376 DEC_HI32(pDecOut) = 0;
4377 DEC_MID32(pDecOut) = 0;
4378 DEC_LO32(pDecOut) = ulIn;
4379 return S_OK;
4382 /************************************************************************
4383 * VarDecFromI8 (OLEAUT32.374)
4385 * Convert a VT_I8 to a DECIMAL.
4387 * PARAMS
4388 * llIn [I] Source
4389 * pDecOut [O] Destination
4391 * RETURNS
4392 * S_OK.
4394 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4396 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4398 DEC_HI32(pDecOut) = 0;
4400 /* Note: This assumes 2s complement integer representation */
4401 if (pLi->u.HighPart & 0x80000000)
4403 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4404 DEC_LO64(pDecOut) = -pLi->QuadPart;
4406 else
4408 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4409 DEC_MID32(pDecOut) = pLi->u.HighPart;
4410 DEC_LO32(pDecOut) = pLi->u.LowPart;
4412 return S_OK;
4415 /************************************************************************
4416 * VarDecFromUI8 (OLEAUT32.375)
4418 * Convert a VT_UI8 to a DECIMAL.
4420 * PARAMS
4421 * ullIn [I] Source
4422 * pDecOut [O] Destination
4424 * RETURNS
4425 * S_OK.
4427 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4429 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4430 DEC_HI32(pDecOut) = 0;
4431 DEC_LO64(pDecOut) = ullIn;
4432 return S_OK;
4435 /* Make two DECIMALS the same scale; used by math functions below */
4436 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4437 const DECIMAL** ppDecRight,
4438 DECIMAL pDecOut[2])
4440 static DECIMAL scaleFactor;
4441 unsigned char remainder;
4442 DECIMAL decTemp;
4443 VARIANT_DI di;
4444 int scaleAmount, i;
4446 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4447 return E_INVALIDARG;
4449 DEC_LO32(&scaleFactor) = 10;
4451 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4453 if (!scaleAmount)
4454 return S_OK; /* Same scale */
4456 if (scaleAmount > 0)
4458 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4459 *ppDecRight = &pDecOut[0];
4461 else
4463 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4464 *ppDecLeft = &pDecOut[0];
4465 i = -scaleAmount;
4468 /* Multiply up the value to be scaled by the correct amount (if possible) */
4469 while (i > 0 && SUCCEEDED(VarDecMul(&decTemp, &scaleFactor, &pDecOut[0])))
4471 decTemp = pDecOut[0];
4472 i--;
4475 if (!i)
4477 DEC_SCALE(&pDecOut[0]) += (scaleAmount > 0) ? scaleAmount : (-scaleAmount);
4478 return S_OK; /* Same scale */
4481 /* Scaling further not possible, reduce accuracy of other argument */
4482 pDecOut[0] = decTemp;
4483 if (scaleAmount > 0)
4485 DEC_SCALE(&pDecOut[0]) += scaleAmount - i;
4486 VARIANT_DIFromDec(*ppDecLeft, &di);
4487 *ppDecLeft = &pDecOut[1];
4489 else
4491 DEC_SCALE(&pDecOut[0]) += (-scaleAmount) - i;
4492 VARIANT_DIFromDec(*ppDecRight, &di);
4493 *ppDecRight = &pDecOut[1];
4496 di.scale -= i;
4497 remainder = 0;
4498 while (i-- > 0 && !VARIANT_int_iszero(di.bitsnum, ARRAY_SIZE(di.bitsnum)))
4500 remainder = VARIANT_int_divbychar(di.bitsnum, ARRAY_SIZE(di.bitsnum), 10);
4501 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4504 /* round up the result - native oleaut32 does this */
4505 if (remainder >= 5) {
4506 for (remainder = 1, i = 0; i < ARRAY_SIZE(di.bitsnum) && remainder; i++) {
4507 ULONGLONG digit = di.bitsnum[i] + 1;
4508 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4509 di.bitsnum[i] = digit & 0xFFFFFFFF;
4513 VARIANT_DecFromDI(&di, &pDecOut[1]);
4514 return S_OK;
4517 /* Add two unsigned 32 bit values with overflow */
4518 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4520 ULARGE_INTEGER ul64;
4522 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4523 *pulHigh = ul64.u.HighPart;
4524 return ul64.u.LowPart;
4527 /* Subtract two unsigned 32 bit values with underflow */
4528 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4530 BOOL invert = FALSE;
4531 ULARGE_INTEGER ul64;
4533 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4534 if (ulLeft < ulRight)
4535 invert = TRUE;
4537 if (ul64.QuadPart > (ULONG64)*pulHigh)
4538 ul64.QuadPart -= (ULONG64)*pulHigh;
4539 else
4541 ul64.QuadPart -= (ULONG64)*pulHigh;
4542 invert = TRUE;
4544 if (invert)
4545 ul64.u.HighPart = -ul64.u.HighPart ;
4547 *pulHigh = ul64.u.HighPart;
4548 return ul64.u.LowPart;
4551 /* Multiply two unsigned 32 bit values with overflow */
4552 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4554 ULARGE_INTEGER ul64;
4556 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4557 *pulHigh = ul64.u.HighPart;
4558 return ul64.u.LowPart;
4561 /* Compare two decimals that have the same scale */
4562 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4564 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4565 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4566 return -1;
4567 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4568 return 0;
4569 return 1;
4572 /************************************************************************
4573 * VarDecAdd (OLEAUT32.177)
4575 * Add one DECIMAL to another.
4577 * PARAMS
4578 * pDecLeft [I] Source
4579 * pDecRight [I] Value to add
4580 * pDecOut [O] Destination
4582 * RETURNS
4583 * Success: S_OK.
4584 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4586 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4588 HRESULT hRet;
4589 DECIMAL scaled[2];
4591 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, scaled);
4593 if (SUCCEEDED(hRet))
4595 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4596 ULONG overflow = 0;
4597 BYTE sign = DECIMAL_POS;
4598 int cmp;
4600 /* Correct for the sign of the result */
4601 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4603 /* -x + -y : Negative */
4604 sign = DECIMAL_NEG;
4605 goto VarDecAdd_AsPositive;
4607 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4609 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4611 /* -x + y : Negative if x > y */
4612 if (cmp > 0)
4614 sign = DECIMAL_NEG;
4615 VarDecAdd_AsNegative:
4616 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4617 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4618 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4620 else
4622 VarDecAdd_AsInvertedNegative:
4623 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4624 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4625 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4628 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4630 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4632 /* x + -y : Negative if x <= y */
4633 if (cmp <= 0)
4635 sign = DECIMAL_NEG;
4636 goto VarDecAdd_AsInvertedNegative;
4638 goto VarDecAdd_AsNegative;
4640 else
4642 /* x + y : Positive */
4643 VarDecAdd_AsPositive:
4644 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4645 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4646 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4649 if (overflow)
4650 return DISP_E_OVERFLOW; /* overflowed */
4652 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4653 DEC_SIGN(pDecOut) = sign;
4655 return hRet;
4658 /* translate from external DECIMAL format into an internal representation */
4659 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4661 to->scale = DEC_SCALE(from);
4662 to->sign = DEC_SIGN(from) ? 1 : 0;
4664 to->bitsnum[0] = DEC_LO32(from);
4665 to->bitsnum[1] = DEC_MID32(from);
4666 to->bitsnum[2] = DEC_HI32(from);
4669 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to)
4671 if (from->sign) {
4672 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4673 } else {
4674 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4677 DEC_LO32(to) = from->bitsnum[0];
4678 DEC_MID32(to) = from->bitsnum[1];
4679 DEC_HI32(to) = from->bitsnum[2];
4682 /* clear an internal representation of a DECIMAL */
4683 static void VARIANT_DI_clear(VARIANT_DI * i)
4685 memset(i, 0, sizeof(VARIANT_DI));
4688 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4689 size is supported. The value in p is replaced by the quotient of the division, and
4690 the remainder is returned as a result. This routine is most often used with a divisor
4691 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4693 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4695 if (divisor == 0) {
4696 /* division by 0 */
4697 return 0xFF;
4698 } else if (divisor == 1) {
4699 /* dividend remains unchanged */
4700 return 0;
4701 } else {
4702 unsigned char remainder = 0;
4703 ULONGLONG iTempDividend;
4704 signed int i;
4706 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4707 for (; i >= 0; i--) {
4708 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4709 remainder = iTempDividend % divisor;
4710 p[i] = iTempDividend / divisor;
4713 return remainder;
4717 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4718 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n)
4720 for (; n > 0; n--) if (*p++ != 0) return FALSE;
4721 return TRUE;
4724 /* multiply two DECIMALS, without changing either one, and place result in third
4725 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4726 digits when scale > 0 in order to fit an overflowing result. Final overflow
4727 flag is returned.
4729 static int VARIANT_DI_mul(const VARIANT_DI * a, const VARIANT_DI * b, VARIANT_DI * result)
4731 BOOL r_overflow = FALSE;
4732 DWORD running[6];
4733 signed int mulstart;
4735 VARIANT_DI_clear(result);
4736 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4738 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4739 of the result is formed by adding the scales of the operands.
4741 result->scale = a->scale + b->scale;
4742 memset(running, 0, sizeof(running));
4744 /* count number of leading zero-bytes in operand A */
4745 for (mulstart = ARRAY_SIZE(a->bitsnum) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4746 if (mulstart < 0) {
4747 /* result is 0, because operand A is 0 */
4748 result->scale = 0;
4749 result->sign = 0;
4750 } else {
4751 unsigned char remainder = 0;
4752 int iA;
4754 /* perform actual multiplication */
4755 for (iA = 0; iA <= mulstart; iA++) {
4756 ULONG iOverflowMul;
4757 int iB;
4759 for (iOverflowMul = 0, iB = 0; iB < ARRAY_SIZE(b->bitsnum); iB++) {
4760 ULONG iRV;
4761 int iR;
4763 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4764 iR = iA + iB;
4765 do {
4766 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4767 iR++;
4768 } while (iRV);
4772 /* Too bad - native oleaut does not do this, so we should not either */
4773 #if 0
4774 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4775 This operation should not lose significant digits, and gives an
4776 opportunity to reduce the possibility of overflows in future
4777 operations issued by the application.
4779 while (result->scale > 0) {
4780 memcpy(quotient, running, sizeof(quotient));
4781 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4782 if (remainder > 0) break;
4783 memcpy(running, quotient, sizeof(quotient));
4784 result->scale--;
4786 #endif
4787 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4788 This operation *will* lose significant digits of the result because
4789 all the factors of 10 were consumed by the previous operation.
4791 while (result->scale > 0 && !VARIANT_int_iszero(running + ARRAY_SIZE(result->bitsnum),
4792 ARRAY_SIZE(running) - ARRAY_SIZE(result->bitsnum))) {
4794 remainder = VARIANT_int_divbychar(running, ARRAY_SIZE(running), 10);
4795 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4796 result->scale--;
4799 /* round up the result - native oleaut32 does this */
4800 if (remainder >= 5) {
4801 unsigned int i;
4802 for (remainder = 1, i = 0; i < ARRAY_SIZE(running) && remainder; i++) {
4803 ULONGLONG digit = running[i] + 1;
4804 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4805 running[i] = digit & 0xFFFFFFFF;
4809 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4810 and copy result bits into result structure
4812 r_overflow = !VARIANT_int_iszero(running + ARRAY_SIZE(result->bitsnum),
4813 ARRAY_SIZE(running) - ARRAY_SIZE(result->bitsnum));
4814 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4816 return r_overflow;
4819 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4820 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4821 success, FALSE if insufficient space in output buffer.
4823 static BOOL VARIANT_DI_tostringW(const VARIANT_DI * a, WCHAR * s, unsigned int n)
4825 BOOL overflow = FALSE;
4826 DWORD quotient[3];
4827 unsigned char remainder;
4828 unsigned int i;
4830 /* place negative sign */
4831 if (!VARIANT_int_iszero(a->bitsnum, ARRAY_SIZE(a->bitsnum)) && a->sign) {
4832 if (n > 0) {
4833 *s++ = '-';
4834 n--;
4836 else overflow = TRUE;
4839 /* prepare initial 0 */
4840 if (!overflow) {
4841 if (n >= 2) {
4842 s[0] = '0';
4843 s[1] = '\0';
4844 } else overflow = TRUE;
4847 i = 0;
4848 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4849 while (!overflow && !VARIANT_int_iszero(quotient, ARRAY_SIZE(quotient))) {
4850 remainder = VARIANT_int_divbychar(quotient, ARRAY_SIZE(quotient), 10);
4851 if (i + 2 > n) {
4852 overflow = TRUE;
4853 } else {
4854 s[i++] = '0' + remainder;
4855 s[i] = '\0';
4859 if (!overflow && !VARIANT_int_iszero(a->bitsnum, ARRAY_SIZE(a->bitsnum))) {
4861 /* reverse order of digits */
4862 WCHAR * x = s; WCHAR * y = s + i - 1;
4863 while (x < y) {
4864 *x ^= *y;
4865 *y ^= *x;
4866 *x++ ^= *y--;
4869 /* check for decimal point. "i" now has string length */
4870 if (i <= a->scale) {
4871 unsigned int numzeroes = a->scale + 1 - i;
4872 if (i + 1 + numzeroes >= n) {
4873 overflow = TRUE;
4874 } else {
4875 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4876 i += numzeroes;
4877 while (numzeroes > 0) {
4878 s[--numzeroes] = '0';
4883 /* place decimal point */
4884 if (a->scale > 0) {
4885 unsigned int periodpos = i - a->scale;
4886 if (i + 2 >= n) {
4887 overflow = TRUE;
4888 } else {
4889 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4890 s[periodpos] = '.'; i++;
4892 /* remove extra zeros at the end, if any */
4893 while (s[i - 1] == '0') s[--i] = '\0';
4894 if (s[i - 1] == '.') s[--i] = '\0';
4899 return !overflow;
4902 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4903 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4905 DWORD shifted;
4906 unsigned int i;
4908 /* shift whole DWORDs to the left */
4909 while (shift >= 32)
4911 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4912 *p = 0; shift -= 32;
4915 /* shift remainder (1..31 bits) */
4916 shifted = 0;
4917 if (shift > 0) for (i = 0; i < n; i++)
4919 DWORD b;
4920 b = p[i] >> (32 - shift);
4921 p[i] = (p[i] << shift) | shifted;
4922 shifted = b;
4926 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4927 Value at v is incremented by the value at p. Any size is supported, provided
4928 that v is not shorter than p. Any unapplied carry is returned as a result.
4930 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, const DWORD * p,
4931 unsigned int np)
4933 unsigned char carry = 0;
4935 if (nv >= np) {
4936 ULONGLONG sum;
4937 unsigned int i;
4939 for (i = 0; i < np; i++) {
4940 sum = (ULONGLONG)v[i]
4941 + (ULONGLONG)p[i]
4942 + (ULONGLONG)carry;
4943 v[i] = sum & 0xffffffff;
4944 carry = sum >> 32;
4946 for (; i < nv && carry; i++) {
4947 sum = (ULONGLONG)v[i]
4948 + (ULONGLONG)carry;
4949 v[i] = sum & 0xffffffff;
4950 carry = sum >> 32;
4953 return carry;
4956 /* perform integral division with operand p as dividend. Parameter n indicates
4957 number of available DWORDs in divisor p, but available space in p must be
4958 actually at least 2 * n DWORDs, because the remainder of the integral
4959 division is built in the next n DWORDs past the start of the quotient. This
4960 routine replaces the dividend in p with the quotient, and appends n
4961 additional DWORDs for the remainder.
4963 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4964 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4965 source code to the VLI (Very Large Integer) division operator. This algorithm
4966 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4967 variably-scaled integers such as the MS DECIMAL representation.
4969 static void VARIANT_int_div(DWORD * p, unsigned int n, const DWORD * divisor,
4970 unsigned int dn)
4972 unsigned int i;
4973 DWORD tempsub[8];
4974 DWORD * negdivisor = tempsub + n;
4976 /* build 2s-complement of divisor */
4977 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
4978 p[n] = 1;
4979 VARIANT_int_add(negdivisor, n, p + n, 1);
4980 memset(p + n, 0, n * sizeof(DWORD));
4982 /* skip all leading zero DWORDs in quotient */
4983 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
4984 /* i is now number of DWORDs left to process */
4985 for (i <<= 5; i < (n << 5); i++) {
4986 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
4988 /* trial subtraction */
4989 memcpy(tempsub, p + n, n * sizeof(DWORD));
4990 VARIANT_int_add(tempsub, n, negdivisor, n);
4992 /* check whether result of subtraction was negative */
4993 if ((tempsub[n - 1] & 0x80000000) == 0) {
4994 memcpy(p + n, tempsub, n * sizeof(DWORD));
4995 p[0] |= 1;
5000 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
5001 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
5003 unsigned int i;
5004 ULONG iOverflowMul;
5006 for (iOverflowMul = 0, i = 0; i < n; i++)
5007 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
5008 return (unsigned char)iOverflowMul;
5011 /* increment value in A by the value indicated in B, with scale adjusting.
5012 Modifies parameters by adjusting scales. Returns 0 if addition was
5013 successful, nonzero if a parameter underflowed before it could be
5014 successfully used in the addition.
5016 static int VARIANT_int_addlossy(
5017 DWORD * a, int * ascale, unsigned int an,
5018 DWORD * b, int * bscale, unsigned int bn)
5020 int underflow = 0;
5022 if (VARIANT_int_iszero(a, an)) {
5023 /* if A is zero, copy B into A, after removing digits */
5024 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
5025 VARIANT_int_divbychar(b, bn, 10);
5026 (*bscale)--;
5028 memcpy(a, b, an * sizeof(DWORD));
5029 *ascale = *bscale;
5030 } else if (!VARIANT_int_iszero(b, bn)) {
5031 unsigned int tn = an + 1;
5032 DWORD t[5];
5034 if (bn + 1 > tn) tn = bn + 1;
5035 if (*ascale != *bscale) {
5036 /* first (optimistic) try - try to scale down the one with the bigger
5037 scale, while this number is divisible by 10 */
5038 DWORD * digitchosen;
5039 unsigned int nchosen;
5040 int * scalechosen;
5041 int targetscale;
5043 if (*ascale < *bscale) {
5044 targetscale = *ascale;
5045 scalechosen = bscale;
5046 digitchosen = b;
5047 nchosen = bn;
5048 } else {
5049 targetscale = *bscale;
5050 scalechosen = ascale;
5051 digitchosen = a;
5052 nchosen = an;
5054 memset(t, 0, tn * sizeof(DWORD));
5055 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5057 /* divide by 10 until target scale is reached */
5058 while (*scalechosen > targetscale) {
5059 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5060 if (!remainder) {
5061 (*scalechosen)--;
5062 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5063 } else break;
5067 if (*ascale != *bscale) {
5068 DWORD * digitchosen;
5069 unsigned int nchosen;
5070 int * scalechosen;
5071 int targetscale;
5073 /* try to scale up the one with the smaller scale */
5074 if (*ascale > *bscale) {
5075 targetscale = *ascale;
5076 scalechosen = bscale;
5077 digitchosen = b;
5078 nchosen = bn;
5079 } else {
5080 targetscale = *bscale;
5081 scalechosen = ascale;
5082 digitchosen = a;
5083 nchosen = an;
5085 memset(t, 0, tn * sizeof(DWORD));
5086 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5088 /* multiply by 10 until target scale is reached, or
5089 significant bytes overflow the number
5091 while (*scalechosen < targetscale && t[nchosen] == 0) {
5092 VARIANT_int_mulbychar(t, tn, 10);
5093 if (t[nchosen] == 0) {
5094 /* still does not overflow */
5095 (*scalechosen)++;
5096 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5101 if (*ascale != *bscale) {
5102 /* still different? try to scale down the one with the bigger scale
5103 (this *will* lose significant digits) */
5104 DWORD * digitchosen;
5105 unsigned int nchosen;
5106 int * scalechosen;
5107 int targetscale;
5109 if (*ascale < *bscale) {
5110 targetscale = *ascale;
5111 scalechosen = bscale;
5112 digitchosen = b;
5113 nchosen = bn;
5114 } else {
5115 targetscale = *bscale;
5116 scalechosen = ascale;
5117 digitchosen = a;
5118 nchosen = an;
5120 memset(t, 0, tn * sizeof(DWORD));
5121 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5123 /* divide by 10 until target scale is reached */
5124 while (*scalechosen > targetscale) {
5125 VARIANT_int_divbychar(t, tn, 10);
5126 (*scalechosen)--;
5127 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5131 /* check whether any of the operands still has significant digits
5132 (underflow case 1)
5134 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5135 underflow = 1;
5136 } else {
5137 /* at this step, both numbers have the same scale and can be added
5138 as integers. However, the result might not fit in A, so further
5139 scaling down might be necessary.
5141 while (!underflow) {
5142 memset(t, 0, tn * sizeof(DWORD));
5143 memcpy(t, a, an * sizeof(DWORD));
5145 VARIANT_int_add(t, tn, b, bn);
5146 if (VARIANT_int_iszero(t + an, tn - an)) {
5147 /* addition was successful */
5148 memcpy(a, t, an * sizeof(DWORD));
5149 break;
5150 } else {
5151 /* addition overflowed - remove significant digits
5152 from both operands and try again */
5153 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5154 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5155 /* check whether any operand keeps significant digits after
5156 scaledown (underflow case 2)
5158 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5163 return underflow;
5166 /* perform complete DECIMAL division in the internal representation. Returns
5167 0 if the division was completed (even if quotient is set to 0), or nonzero
5168 in case of quotient overflow.
5170 static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * divisor,
5171 VARIANT_DI * quotient, BOOL round_remainder)
5173 HRESULT r_overflow = S_OK;
5175 if (VARIANT_int_iszero(divisor->bitsnum, ARRAY_SIZE(divisor->bitsnum))) {
5176 /* division by 0 */
5177 r_overflow = DISP_E_DIVBYZERO;
5178 } else if (VARIANT_int_iszero(dividend->bitsnum, ARRAY_SIZE(dividend->bitsnum))) {
5179 VARIANT_DI_clear(quotient);
5180 } else {
5181 int quotientscale, remainderscale, tempquotientscale;
5182 DWORD remainderplusquotient[8];
5183 int underflow;
5185 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5186 tempquotientscale = quotientscale;
5187 VARIANT_DI_clear(quotient);
5188 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5190 /* The following strategy is used for division
5191 1) if there was a nonzero remainder from previous iteration, use it as
5192 dividend for this iteration, else (for first iteration) use intended
5193 dividend
5194 2) perform integer division in temporary buffer, develop quotient in
5195 low-order part, remainder in high-order part
5196 3) add quotient from step 2 to final result, with possible loss of
5197 significant digits
5198 4) multiply integer part of remainder by 10, while incrementing the
5199 scale of the remainder. This operation preserves the intended value
5200 of the remainder.
5201 5) loop to step 1 until one of the following is true:
5202 a) remainder is zero (exact division achieved)
5203 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5205 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5206 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5207 do {
5208 VARIANT_int_div(remainderplusquotient, 4, divisor->bitsnum, ARRAY_SIZE(divisor->bitsnum));
5209 underflow = VARIANT_int_addlossy( quotient->bitsnum, &quotientscale,
5210 ARRAY_SIZE(quotient->bitsnum), remainderplusquotient, &tempquotientscale, 4);
5211 if (round_remainder) {
5212 if(remainderplusquotient[4] >= 5){
5213 unsigned int i;
5214 unsigned char remainder = 1;
5215 for (i = 0; i < ARRAY_SIZE(quotient->bitsnum) && remainder; i++) {
5216 ULONGLONG digit = quotient->bitsnum[i] + 1;
5217 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5218 quotient->bitsnum[i] = digit & 0xFFFFFFFF;
5221 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5222 } else {
5223 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5224 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5226 tempquotientscale = ++remainderscale;
5227 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5229 /* quotient scale might now be negative (extremely big number). If, so, try
5230 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5231 until scale is 0. If this cannot be done, it is a real overflow.
5233 while (r_overflow == S_OK && quotientscale < 0) {
5234 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5235 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5236 VARIANT_int_mulbychar(remainderplusquotient, ARRAY_SIZE(remainderplusquotient), 10);
5237 if (VARIANT_int_iszero(remainderplusquotient + ARRAY_SIZE(quotient->bitsnum),
5238 ARRAY_SIZE(remainderplusquotient) - ARRAY_SIZE(quotient->bitsnum))) {
5239 quotientscale++;
5240 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5241 } else r_overflow = DISP_E_OVERFLOW;
5243 if (r_overflow == S_OK) {
5244 if (quotientscale <= 255) quotient->scale = quotientscale;
5245 else VARIANT_DI_clear(quotient);
5248 return r_overflow;
5251 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5252 with an undefined scale, which will be assigned to (if possible). It also
5253 receives an exponent of 2. This procedure will then manipulate the mantissa
5254 and calculate a corresponding scale, so that the exponent2 value is assimilated
5255 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5256 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5257 a DECIMAL. */
5258 static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, BOOL isDouble)
5260 HRESULT hres = S_OK;
5261 int exponent5, exponent10;
5263 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5264 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5265 exponent10 might be used to set the VARIANT_DI scale directly. However,
5266 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5267 exponent5 = -exponent2;
5268 exponent10 = exponent2;
5270 /* Handle exponent5 > 0 */
5271 while (exponent5 > 0) {
5272 char bPrevCarryBit;
5273 char bCurrCarryBit;
5275 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5276 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5277 somehow the mantissa should be divided by 2. */
5278 if ((val->bitsnum[0] & 1) == 0) {
5279 /* The mantissa is divisible by 2. Therefore the division can be done
5280 without losing significant digits. */
5281 exponent10++; exponent5--;
5283 /* Shift right */
5284 bPrevCarryBit = val->bitsnum[2] & 1;
5285 val->bitsnum[2] >>= 1;
5286 bCurrCarryBit = val->bitsnum[1] & 1;
5287 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5288 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5289 } else {
5290 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5291 be multiplied by 5, unless the multiplication overflows. */
5292 DWORD temp_bitsnum[3];
5294 exponent5--;
5296 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5297 if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) {
5298 /* Multiplication succeeded without overflow, so copy result back
5299 into VARIANT_DI */
5300 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5302 /* Mask out 3 extraneous bits introduced by the multiply */
5303 } else {
5304 /* Multiplication by 5 overflows. The mantissa should be divided
5305 by 2, and therefore will lose significant digits. */
5306 exponent10++;
5308 /* Shift right */
5309 bPrevCarryBit = val->bitsnum[2] & 1;
5310 val->bitsnum[2] >>= 1;
5311 bCurrCarryBit = val->bitsnum[1] & 1;
5312 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5313 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5318 /* Handle exponent5 < 0 */
5319 while (exponent5 < 0) {
5320 /* In order to divide the value represented by the VARIANT_DI by 5, it
5321 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5322 and the mantissa should be multiplied by 2 */
5323 if ((val->bitsnum[2] & 0x80000000) == 0) {
5324 /* The mantissa can withstand a shift-left without overflowing */
5325 exponent10--; exponent5++;
5326 VARIANT_int_shiftleft(val->bitsnum, 3, 1);
5327 } else {
5328 /* The mantissa would overflow if shifted. Therefore it should be
5329 directly divided by 5. This will lose significant digits, unless
5330 by chance the mantissa happens to be divisible by 5 */
5331 exponent5++;
5332 VARIANT_int_divbychar(val->bitsnum, 3, 5);
5336 /* At this point, the mantissa has assimilated the exponent5, but the
5337 exponent10 might not be suitable for assignment. The exponent10 must be
5338 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5339 down appropriately. */
5340 while (hres == S_OK && exponent10 > 0) {
5341 /* In order to bring exponent10 down to 0, the mantissa should be
5342 multiplied by 10 to compensate. If the exponent10 is too big, this
5343 will cause the mantissa to overflow. */
5344 if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) {
5345 exponent10--;
5346 } else {
5347 hres = DISP_E_OVERFLOW;
5350 while (exponent10 < -DEC_MAX_SCALE) {
5351 int rem10;
5352 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5353 be divided by 10 to compensate. If the exponent10 is too small, this
5354 will cause the mantissa to underflow and become 0 */
5355 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5356 exponent10++;
5357 if (VARIANT_int_iszero(val->bitsnum, 3)) {
5358 /* Underflow, unable to keep dividing */
5359 exponent10 = 0;
5360 } else if (rem10 >= 5) {
5361 DWORD x = 1;
5362 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5365 /* This step is required in order to remove excess bits of precision from the
5366 end of the bit representation, down to the precision guaranteed by the
5367 floating point number. */
5368 if (isDouble) {
5369 while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[1] & 0xFFE00000) != 0)) {
5370 int rem10;
5372 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5373 exponent10++;
5374 if (rem10 >= 5) {
5375 DWORD x = 1;
5376 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5379 } else {
5380 while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 ||
5381 (val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) {
5382 int rem10;
5384 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5385 exponent10++;
5386 if (rem10 >= 5) {
5387 DWORD x = 1;
5388 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5392 /* Remove multiples of 10 from the representation */
5393 while (exponent10 < 0) {
5394 DWORD temp_bitsnum[3];
5396 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5397 if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) {
5398 exponent10++;
5399 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5400 } else break;
5403 /* Scale assignment */
5404 if (hres == S_OK) val->scale = -exponent10;
5406 return hres;
5409 typedef union
5411 struct
5413 unsigned int m : 23;
5414 unsigned int exp_bias : 8;
5415 unsigned int sign : 1;
5416 } i;
5417 float f;
5418 } R4_FIELDS;
5420 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5421 intermediate string step. */
5422 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest)
5424 HRESULT hres = S_OK;
5425 R4_FIELDS fx;
5427 fx.f = source;
5429 /* Detect special cases */
5430 if (fx.i.m == 0 && fx.i.exp_bias == 0) {
5431 /* Floating-point zero */
5432 VARIANT_DI_clear(dest);
5433 } else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) {
5434 /* Floating-point infinity */
5435 hres = DISP_E_OVERFLOW;
5436 } else if (fx.i.exp_bias == 0xFF) {
5437 /* Floating-point NaN */
5438 hres = DISP_E_BADVARTYPE;
5439 } else {
5440 int exponent2;
5441 VARIANT_DI_clear(dest);
5443 exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */
5444 dest->sign = fx.i.sign; /* Sign is simply copied */
5446 /* Copy significant bits to VARIANT_DI mantissa */
5447 dest->bitsnum[0] = fx.i.m;
5448 dest->bitsnum[0] &= 0x007FFFFF;
5449 if (fx.i.exp_bias == 0) {
5450 /* Denormalized number - correct exponent */
5451 exponent2++;
5452 } else {
5453 /* Add hidden bit to mantissa */
5454 dest->bitsnum[0] |= 0x00800000;
5457 /* The act of copying a FP mantissa as integer bits is equivalent to
5458 shifting left the mantissa 23 bits. The exponent2 is reduced to
5459 compensate. */
5460 exponent2 -= 23;
5462 hres = VARIANT_DI_normalize(dest, exponent2, FALSE);
5465 return hres;
5468 typedef union
5470 struct
5472 unsigned int m_lo : 32; /* 52 bits of precision */
5473 unsigned int m_hi : 20;
5474 unsigned int exp_bias : 11; /* bias == 1023 */
5475 unsigned int sign : 1;
5476 } i;
5477 double d;
5478 } R8_FIELDS;
5480 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5481 intermediate string step. */
5482 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest)
5484 HRESULT hres = S_OK;
5485 R8_FIELDS fx;
5487 fx.d = source;
5489 /* Detect special cases */
5490 if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) {
5491 /* Floating-point zero */
5492 VARIANT_DI_clear(dest);
5493 } else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) {
5494 /* Floating-point infinity */
5495 hres = DISP_E_OVERFLOW;
5496 } else if (fx.i.exp_bias == 0x7FF) {
5497 /* Floating-point NaN */
5498 hres = DISP_E_BADVARTYPE;
5499 } else {
5500 int exponent2;
5501 VARIANT_DI_clear(dest);
5503 exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */
5504 dest->sign = fx.i.sign; /* Sign is simply copied */
5506 /* Copy significant bits to VARIANT_DI mantissa */
5507 dest->bitsnum[0] = fx.i.m_lo;
5508 dest->bitsnum[1] = fx.i.m_hi;
5509 dest->bitsnum[1] &= 0x000FFFFF;
5510 if (fx.i.exp_bias == 0) {
5511 /* Denormalized number - correct exponent */
5512 exponent2++;
5513 } else {
5514 /* Add hidden bit to mantissa */
5515 dest->bitsnum[1] |= 0x00100000;
5518 /* The act of copying a FP mantissa as integer bits is equivalent to
5519 shifting left the mantissa 52 bits. The exponent2 is reduced to
5520 compensate. */
5521 exponent2 -= 52;
5523 hres = VARIANT_DI_normalize(dest, exponent2, TRUE);
5526 return hres;
5529 static HRESULT VARIANT_do_division(const DECIMAL *pDecLeft, const DECIMAL *pDecRight, DECIMAL *pDecOut,
5530 BOOL round)
5532 HRESULT hRet = S_OK;
5533 VARIANT_DI di_left, di_right, di_result;
5534 HRESULT divresult;
5536 VARIANT_DIFromDec(pDecLeft, &di_left);
5537 VARIANT_DIFromDec(pDecRight, &di_right);
5538 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result, round);
5539 if (divresult != S_OK)
5541 /* division actually overflowed */
5542 hRet = divresult;
5544 else
5546 hRet = S_OK;
5548 if (di_result.scale > DEC_MAX_SCALE)
5550 unsigned char remainder = 0;
5552 /* division underflowed. In order to comply with the MSDN
5553 specifications for DECIMAL ranges, some significant digits
5554 must be removed
5556 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5557 di_result.scale);
5558 while (di_result.scale > DEC_MAX_SCALE &&
5559 !VARIANT_int_iszero(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum)))
5561 remainder = VARIANT_int_divbychar(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum), 10);
5562 di_result.scale--;
5564 if (di_result.scale > DEC_MAX_SCALE)
5566 WARN("result underflowed, setting to 0\n");
5567 di_result.scale = 0;
5568 di_result.sign = 0;
5570 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5572 unsigned int i;
5573 for (remainder = 1, i = 0; i < ARRAY_SIZE(di_result.bitsnum) && remainder; i++) {
5574 ULONGLONG digit = di_result.bitsnum[i] + 1;
5575 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5576 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5580 VARIANT_DecFromDI(&di_result, pDecOut);
5582 return hRet;
5585 /************************************************************************
5586 * VarDecDiv (OLEAUT32.178)
5588 * Divide one DECIMAL by another.
5590 * PARAMS
5591 * pDecLeft [I] Source
5592 * pDecRight [I] Value to divide by
5593 * pDecOut [O] Destination
5595 * RETURNS
5596 * Success: S_OK.
5597 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5599 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5601 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5603 return VARIANT_do_division(pDecLeft, pDecRight, pDecOut, FALSE);
5606 /************************************************************************
5607 * VarDecMul (OLEAUT32.179)
5609 * Multiply one DECIMAL by another.
5611 * PARAMS
5612 * pDecLeft [I] Source
5613 * pDecRight [I] Value to multiply by
5614 * pDecOut [O] Destination
5616 * RETURNS
5617 * Success: S_OK.
5618 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5620 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5622 HRESULT hRet = S_OK;
5623 VARIANT_DI di_left, di_right, di_result;
5624 int mulresult;
5626 VARIANT_DIFromDec(pDecLeft, &di_left);
5627 VARIANT_DIFromDec(pDecRight, &di_right);
5628 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5629 if (mulresult)
5631 /* multiplication actually overflowed */
5632 hRet = DISP_E_OVERFLOW;
5634 else
5636 if (di_result.scale > DEC_MAX_SCALE)
5638 /* multiplication underflowed. In order to comply with the MSDN
5639 specifications for DECIMAL ranges, some significant digits
5640 must be removed
5642 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5643 di_result.scale);
5644 while (di_result.scale > DEC_MAX_SCALE &&
5645 !VARIANT_int_iszero(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum)))
5647 VARIANT_int_divbychar(di_result.bitsnum, ARRAY_SIZE(di_result.bitsnum), 10);
5648 di_result.scale--;
5650 if (di_result.scale > DEC_MAX_SCALE)
5652 WARN("result underflowed, setting to 0\n");
5653 di_result.scale = 0;
5654 di_result.sign = 0;
5657 VARIANT_DecFromDI(&di_result, pDecOut);
5659 return hRet;
5662 /************************************************************************
5663 * VarDecSub (OLEAUT32.181)
5665 * Subtract one DECIMAL from another.
5667 * PARAMS
5668 * pDecLeft [I] Source
5669 * pDecRight [I] DECIMAL to subtract from pDecLeft
5670 * pDecOut [O] Destination
5672 * RETURNS
5673 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5675 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5677 DECIMAL decRight;
5679 /* Implement as addition of the negative */
5680 VarDecNeg(pDecRight, &decRight);
5681 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5684 /************************************************************************
5685 * VarDecAbs (OLEAUT32.182)
5687 * Convert a DECIMAL into its absolute value.
5689 * PARAMS
5690 * pDecIn [I] Source
5691 * pDecOut [O] Destination
5693 * RETURNS
5694 * S_OK. This function does not fail.
5696 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5698 *pDecOut = *pDecIn;
5699 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5700 return S_OK;
5703 /************************************************************************
5704 * VarDecFix (OLEAUT32.187)
5706 * Return the integer portion of a DECIMAL.
5708 * PARAMS
5709 * pDecIn [I] Source
5710 * pDecOut [O] Destination
5712 * RETURNS
5713 * Success: S_OK.
5714 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5716 * NOTES
5717 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5718 * negative numbers away from 0, while this function rounds them towards zero.
5720 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5722 double dbl;
5723 HRESULT hr;
5725 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5726 return E_INVALIDARG;
5728 if (!DEC_SCALE(pDecIn))
5730 *pDecOut = *pDecIn; /* Already an integer */
5731 return S_OK;
5734 hr = VarR8FromDec(pDecIn, &dbl);
5735 if (SUCCEEDED(hr)) {
5736 LONGLONG rounded = dbl;
5738 hr = VarDecFromI8(rounded, pDecOut);
5740 return hr;
5743 /************************************************************************
5744 * VarDecInt (OLEAUT32.188)
5746 * Return the integer portion of a DECIMAL.
5748 * PARAMS
5749 * pDecIn [I] Source
5750 * pDecOut [O] Destination
5752 * RETURNS
5753 * Success: S_OK.
5754 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5756 * NOTES
5757 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5758 * negative numbers towards 0, while this function rounds them away from zero.
5760 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5762 double dbl;
5763 HRESULT hr;
5765 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5766 return E_INVALIDARG;
5768 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5769 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5771 hr = VarR8FromDec(pDecIn, &dbl);
5772 if (SUCCEEDED(hr)) {
5773 LONGLONG rounded = dbl >= 0.0 ? dbl + 0.5 : dbl - 0.5;
5775 hr = VarDecFromI8(rounded, pDecOut);
5777 return hr;
5780 /************************************************************************
5781 * VarDecNeg (OLEAUT32.189)
5783 * Change the sign of a DECIMAL.
5785 * PARAMS
5786 * pDecIn [I] Source
5787 * pDecOut [O] Destination
5789 * RETURNS
5790 * S_OK. This function does not fail.
5792 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5794 *pDecOut = *pDecIn;
5795 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5796 return S_OK;
5799 /************************************************************************
5800 * VarDecRound (OLEAUT32.203)
5802 * Change the precision of a DECIMAL.
5804 * PARAMS
5805 * pDecIn [I] Source
5806 * cDecimals [I] New number of decimals to keep
5807 * pDecOut [O] Destination
5809 * RETURNS
5810 * Success: S_OK. pDecOut contains the rounded value.
5811 * Failure: E_INVALIDARG if any argument is invalid.
5813 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5815 DECIMAL divisor, tmp;
5816 HRESULT hr;
5817 unsigned int i;
5819 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5820 return E_INVALIDARG;
5822 if (cDecimals >= DEC_SCALE(pDecIn))
5824 *pDecOut = *pDecIn; /* More precision than we have */
5825 return S_OK;
5828 /* truncate significant digits and rescale */
5829 memset(&divisor, 0, sizeof(divisor));
5830 DEC_LO64(&divisor) = 1;
5832 memset(&tmp, 0, sizeof(tmp));
5833 DEC_LO64(&tmp) = 10;
5834 for (i = 0; i < DEC_SCALE(pDecIn) - cDecimals; ++i)
5836 hr = VarDecMul(&divisor, &tmp, &divisor);
5837 if (FAILED(hr))
5838 return hr;
5841 hr = VARIANT_do_division(pDecIn, &divisor, pDecOut, TRUE);
5842 if (FAILED(hr))
5843 return hr;
5845 DEC_SCALE(pDecOut) = cDecimals;
5847 return S_OK;
5850 /************************************************************************
5851 * VarDecCmp (OLEAUT32.204)
5853 * Compare two DECIMAL values.
5855 * PARAMS
5856 * pDecLeft [I] Source
5857 * pDecRight [I] Value to compare
5859 * RETURNS
5860 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5861 * is less than, equal to or greater than pDecRight respectively.
5862 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5864 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5866 HRESULT hRet;
5867 DECIMAL result;
5869 if (!pDecLeft || !pDecRight)
5870 return VARCMP_NULL;
5872 if ((!(DEC_SIGN(pDecLeft) & DECIMAL_NEG)) && (DEC_SIGN(pDecRight) & DECIMAL_NEG) &&
5873 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5874 return VARCMP_GT;
5875 else if ((DEC_SIGN(pDecLeft) & DECIMAL_NEG) && (!(DEC_SIGN(pDecRight) & DECIMAL_NEG)) &&
5876 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5877 return VARCMP_LT;
5879 /* Subtract right from left, and compare the result to 0 */
5880 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5882 if (SUCCEEDED(hRet))
5884 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5886 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5887 hRet = (HRESULT)VARCMP_LT;
5888 else if (non_zero)
5889 hRet = (HRESULT)VARCMP_GT;
5890 else
5891 hRet = (HRESULT)VARCMP_EQ;
5893 return hRet;
5896 /************************************************************************
5897 * VarDecCmpR8 (OLEAUT32.298)
5899 * Compare a DECIMAL to a double
5901 * PARAMS
5902 * pDecLeft [I] DECIMAL Source
5903 * dblRight [I] double to compare to pDecLeft
5905 * RETURNS
5906 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5907 * is less than, equal to or greater than pDecLeft respectively.
5908 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5910 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5912 HRESULT hRet;
5913 DECIMAL decRight;
5915 hRet = VarDecFromR8(dblRight, &decRight);
5917 if (SUCCEEDED(hRet))
5918 hRet = VarDecCmp(pDecLeft, &decRight);
5920 return hRet;
5923 /* BOOL
5926 /************************************************************************
5927 * VarBoolFromUI1 (OLEAUT32.118)
5929 * Convert a VT_UI1 to a VT_BOOL.
5931 * PARAMS
5932 * bIn [I] Source
5933 * pBoolOut [O] Destination
5935 * RETURNS
5936 * S_OK.
5938 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5940 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5941 return S_OK;
5944 /************************************************************************
5945 * VarBoolFromI2 (OLEAUT32.119)
5947 * Convert a VT_I2 to a VT_BOOL.
5949 * PARAMS
5950 * sIn [I] Source
5951 * pBoolOut [O] Destination
5953 * RETURNS
5954 * S_OK.
5956 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5958 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5959 return S_OK;
5962 /************************************************************************
5963 * VarBoolFromI4 (OLEAUT32.120)
5965 * Convert a VT_I4 to a VT_BOOL.
5967 * PARAMS
5968 * sIn [I] Source
5969 * pBoolOut [O] Destination
5971 * RETURNS
5972 * S_OK.
5974 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
5976 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
5977 return S_OK;
5980 /************************************************************************
5981 * VarBoolFromR4 (OLEAUT32.121)
5983 * Convert a VT_R4 to a VT_BOOL.
5985 * PARAMS
5986 * fltIn [I] Source
5987 * pBoolOut [O] Destination
5989 * RETURNS
5990 * S_OK.
5992 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
5994 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
5995 return S_OK;
5998 /************************************************************************
5999 * VarBoolFromR8 (OLEAUT32.122)
6001 * Convert a VT_R8 to a VT_BOOL.
6003 * PARAMS
6004 * dblIn [I] Source
6005 * pBoolOut [O] Destination
6007 * RETURNS
6008 * S_OK.
6010 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
6012 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
6013 return S_OK;
6016 /************************************************************************
6017 * VarBoolFromDate (OLEAUT32.123)
6019 * Convert a VT_DATE to a VT_BOOL.
6021 * PARAMS
6022 * dateIn [I] Source
6023 * pBoolOut [O] Destination
6025 * RETURNS
6026 * S_OK.
6028 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
6030 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
6031 return S_OK;
6034 /************************************************************************
6035 * VarBoolFromCy (OLEAUT32.124)
6037 * Convert a VT_CY to a VT_BOOL.
6039 * PARAMS
6040 * cyIn [I] Source
6041 * pBoolOut [O] Destination
6043 * RETURNS
6044 * S_OK.
6046 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
6048 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
6049 return S_OK;
6052 /************************************************************************
6053 * VARIANT_GetLocalisedText [internal]
6055 * Get a localized string from the resources
6058 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
6060 HRSRC hrsrc;
6062 hrsrc = FindResourceExW( hProxyDll, (LPWSTR)RT_STRING,
6063 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
6064 if (hrsrc)
6066 HGLOBAL hmem = LoadResource( hProxyDll, hrsrc );
6068 if (hmem)
6070 const WCHAR *p;
6071 unsigned int i;
6073 p = LockResource( hmem );
6074 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
6076 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
6077 lpszDest[*p] = '\0';
6078 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
6079 return TRUE;
6082 return FALSE;
6085 /************************************************************************
6086 * VarBoolFromStr (OLEAUT32.125)
6088 * Convert a VT_BSTR to a VT_BOOL.
6090 * PARAMS
6091 * strIn [I] Source
6092 * lcid [I] LCID for the conversion
6093 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6094 * pBoolOut [O] Destination
6096 * RETURNS
6097 * Success: S_OK.
6098 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6099 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6101 * NOTES
6102 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6103 * it may contain (in any case mapping) the text "true" or "false".
6104 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6105 * localised text of "True" or "False" in the language specified by lcid.
6106 * - If none of these matches occur, the string is treated as a numeric string
6107 * and the boolean pBoolOut will be set according to whether the number is zero
6108 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6109 * - If the text is not numeric and does not match any of the above, then
6110 * DISP_E_TYPEMISMATCH is returned.
6112 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
6114 /* Any VB/VBA programmers out there should recognise these strings... */
6115 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
6116 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
6117 WCHAR szBuff[64];
6118 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6119 HRESULT hRes = S_OK;
6121 if (!strIn || !pBoolOut)
6122 return DISP_E_TYPEMISMATCH;
6124 /* Check if we should be comparing against localised text */
6125 if (dwFlags & VAR_LOCALBOOL)
6127 /* Convert our LCID into a usable value */
6128 lcid = ConvertDefaultLocale(lcid);
6130 langId = LANGIDFROMLCID(lcid);
6132 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6133 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6135 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6136 * I don't think this is needed unless any of the localised text strings
6137 * contain characters that can be so mapped. In the event that this is
6138 * true for a given language (possibly some Asian languages), then strIn
6139 * should be mapped here _only_ if langId is an Id for which this can occur.
6143 /* Note that if we are not comparing against localised strings, langId
6144 * will have its default value of LANG_ENGLISH. This allows us to mimic
6145 * the native behaviour of always checking against English strings even
6146 * after we've checked for localised ones.
6148 VarBoolFromStr_CheckLocalised:
6149 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
6151 /* Compare against localised strings, ignoring case */
6152 if (!wcsicmp(strIn, szBuff))
6154 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
6155 return hRes;
6157 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
6158 if (!wcsicmp(strIn, szBuff))
6160 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
6161 return hRes;
6165 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6167 /* We have checked the localised text, now check English */
6168 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6169 goto VarBoolFromStr_CheckLocalised;
6172 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6173 if (!wcscmp(strIn, szFalse))
6174 *pBoolOut = VARIANT_FALSE;
6175 else if (!wcscmp(strIn, szTrue))
6176 *pBoolOut = VARIANT_TRUE;
6177 else
6179 double d;
6181 /* If this string is a number, convert it as one */
6182 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
6183 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
6185 return hRes;
6188 /************************************************************************
6189 * VarBoolFromDisp (OLEAUT32.126)
6191 * Convert a VT_DISPATCH to a VT_BOOL.
6193 * PARAMS
6194 * pdispIn [I] Source
6195 * lcid [I] LCID for conversion
6196 * pBoolOut [O] Destination
6198 * RETURNS
6199 * Success: S_OK.
6200 * Failure: E_INVALIDARG, if the source value is invalid
6201 * DISP_E_OVERFLOW, if the value will not fit in the destination
6202 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6204 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
6206 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
6209 /************************************************************************
6210 * VarBoolFromI1 (OLEAUT32.233)
6212 * Convert a VT_I1 to a VT_BOOL.
6214 * PARAMS
6215 * cIn [I] Source
6216 * pBoolOut [O] Destination
6218 * RETURNS
6219 * S_OK.
6221 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
6223 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
6224 return S_OK;
6227 /************************************************************************
6228 * VarBoolFromUI2 (OLEAUT32.234)
6230 * Convert a VT_UI2 to a VT_BOOL.
6232 * PARAMS
6233 * usIn [I] Source
6234 * pBoolOut [O] Destination
6236 * RETURNS
6237 * S_OK.
6239 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
6241 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
6242 return S_OK;
6245 /************************************************************************
6246 * VarBoolFromUI4 (OLEAUT32.235)
6248 * Convert a VT_UI4 to a VT_BOOL.
6250 * PARAMS
6251 * ulIn [I] Source
6252 * pBoolOut [O] Destination
6254 * RETURNS
6255 * S_OK.
6257 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
6259 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
6260 return S_OK;
6263 /************************************************************************
6264 * VarBoolFromDec (OLEAUT32.236)
6266 * Convert a VT_DECIMAL to a VT_BOOL.
6268 * PARAMS
6269 * pDecIn [I] Source
6270 * pBoolOut [O] Destination
6272 * RETURNS
6273 * Success: S_OK.
6274 * Failure: E_INVALIDARG, if pDecIn is invalid.
6276 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
6278 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
6279 return E_INVALIDARG;
6281 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
6282 *pBoolOut = VARIANT_TRUE;
6283 else
6284 *pBoolOut = VARIANT_FALSE;
6285 return S_OK;
6288 /************************************************************************
6289 * VarBoolFromI8 (OLEAUT32.370)
6291 * Convert a VT_I8 to a VT_BOOL.
6293 * PARAMS
6294 * ullIn [I] Source
6295 * pBoolOut [O] Destination
6297 * RETURNS
6298 * S_OK.
6300 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
6302 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
6303 return S_OK;
6306 /************************************************************************
6307 * VarBoolFromUI8 (OLEAUT32.371)
6309 * Convert a VT_UI8 to a VT_BOOL.
6311 * PARAMS
6312 * ullIn [I] Source
6313 * pBoolOut [O] Destination
6315 * RETURNS
6316 * S_OK.
6318 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
6320 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
6321 return S_OK;
6324 /* BSTR
6327 /* Write a number from a UI8 and sign */
6328 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
6332 WCHAR ulNextDigit = ulVal % 10;
6334 *szOut-- = '0' + ulNextDigit;
6335 ulVal = (ulVal - ulNextDigit) / 10;
6336 } while (ulVal);
6338 szOut++;
6339 return szOut;
6342 /* Create a (possibly localised) BSTR from a UI8 and sign */
6343 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
6345 WCHAR szConverted[256];
6347 if (dwFlags & VAR_NEGATIVE)
6348 *--szOut = '-';
6350 if (dwFlags & LOCALE_USE_NLS)
6352 /* Format the number for the locale */
6353 szConverted[0] = '\0';
6354 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6355 szOut, NULL, szConverted, ARRAY_SIZE(szConverted));
6356 szOut = szConverted;
6358 return SysAllocStringByteLen((LPCSTR)szOut, lstrlenW(szOut) * sizeof(WCHAR));
6361 /* Create a (possibly localised) BSTR from a UI8 and sign */
6362 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
6364 WCHAR szBuff[64], *szOut = szBuff + ARRAY_SIZE(szBuff) - 1;
6366 if (!pbstrOut)
6367 return E_INVALIDARG;
6369 /* Create the basic number string */
6370 *szOut-- = '\0';
6371 szOut = VARIANT_WriteNumber(ulVal, szOut);
6373 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
6374 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6375 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6378 /******************************************************************************
6379 * VarBstrFromUI1 (OLEAUT32.108)
6381 * Convert a VT_UI1 to a VT_BSTR.
6383 * PARAMS
6384 * bIn [I] Source
6385 * lcid [I] LCID for the conversion
6386 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6387 * pbstrOut [O] Destination
6389 * RETURNS
6390 * Success: S_OK.
6391 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6392 * E_OUTOFMEMORY, if memory allocation fails.
6394 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6396 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6399 /******************************************************************************
6400 * VarBstrFromI2 (OLEAUT32.109)
6402 * Convert a VT_I2 to a VT_BSTR.
6404 * PARAMS
6405 * sIn [I] Source
6406 * lcid [I] LCID for the conversion
6407 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6408 * pbstrOut [O] Destination
6410 * RETURNS
6411 * Success: S_OK.
6412 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6413 * E_OUTOFMEMORY, if memory allocation fails.
6415 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6417 ULONG64 ul64 = sIn;
6419 if (sIn < 0)
6421 ul64 = -sIn;
6422 dwFlags |= VAR_NEGATIVE;
6424 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6427 /******************************************************************************
6428 * VarBstrFromI4 (OLEAUT32.110)
6430 * Convert a VT_I4 to a VT_BSTR.
6432 * PARAMS
6433 * lIn [I] Source
6434 * lcid [I] LCID for the conversion
6435 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6436 * pbstrOut [O] Destination
6438 * RETURNS
6439 * Success: S_OK.
6440 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6441 * E_OUTOFMEMORY, if memory allocation fails.
6443 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6445 ULONG64 ul64 = lIn;
6447 if (lIn < 0)
6449 ul64 = -(LONG64)lIn;
6450 dwFlags |= VAR_NEGATIVE;
6452 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6455 static BSTR VARIANT_BstrReplaceDecimal(const WCHAR * buff, LCID lcid, ULONG dwFlags)
6457 BSTR bstrOut;
6458 WCHAR lpDecimalSep[16];
6460 /* Native oleaut32 uses the locale-specific decimal separator even in the
6461 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6462 American locales will see "one thousand and one tenth" as "1000,1"
6463 instead of "1000.1" (notice the comma). The following code checks for
6464 the need to replace the decimal separator, and if so, will prepare an
6465 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6467 GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE),
6468 lpDecimalSep, ARRAY_SIZE(lpDecimalSep));
6469 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6471 /* locale is compatible with English - return original string */
6472 bstrOut = SysAllocString(buff);
6474 else
6476 WCHAR *p;
6477 WCHAR numbuff[256];
6478 WCHAR empty[] = {'\0'};
6479 NUMBERFMTW minFormat;
6481 minFormat.NumDigits = 0;
6482 minFormat.LeadingZero = 0;
6483 minFormat.Grouping = 0;
6484 minFormat.lpDecimalSep = lpDecimalSep;
6485 minFormat.lpThousandSep = empty;
6486 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6488 /* count number of decimal digits in string */
6489 p = wcschr( buff, '.' );
6490 if (p) minFormat.NumDigits = lstrlenW(p + 1);
6492 numbuff[0] = '\0';
6493 if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, ARRAY_SIZE(numbuff)))
6495 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6496 bstrOut = SysAllocString(buff);
6498 else
6500 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6501 bstrOut = SysAllocString(numbuff);
6504 return bstrOut;
6507 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6508 BSTR* pbstrOut, LPCWSTR lpszFormat)
6510 WCHAR buff[256];
6512 if (!pbstrOut)
6513 return E_INVALIDARG;
6515 swprintf( buff, ARRAY_SIZE(buff), lpszFormat, dblIn );
6517 /* Negative zeroes are disallowed (some applications depend on this).
6518 If buff starts with a minus, and then nothing follows but zeroes
6519 and/or a period, it is a negative zero and is replaced with a
6520 canonical zero. This duplicates native oleaut32 behavior.
6522 if (buff[0] == '-')
6524 static const WCHAR szAccept[] = {'0', '.', '\0'};
6525 if (lstrlenW(buff + 1) == wcsspn(buff + 1, szAccept))
6526 { buff[0] = '0'; buff[1] = '\0'; }
6529 TRACE("created string %s\n", debugstr_w(buff));
6530 if (dwFlags & LOCALE_USE_NLS)
6532 WCHAR numbuff[256];
6534 /* Format the number for the locale */
6535 numbuff[0] = '\0';
6536 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6537 buff, NULL, numbuff, ARRAY_SIZE(numbuff));
6538 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6539 *pbstrOut = SysAllocString(numbuff);
6541 else
6543 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6545 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6548 /******************************************************************************
6549 * VarBstrFromR4 (OLEAUT32.111)
6551 * Convert a VT_R4 to a VT_BSTR.
6553 * PARAMS
6554 * fltIn [I] Source
6555 * lcid [I] LCID for the conversion
6556 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6557 * pbstrOut [O] Destination
6559 * RETURNS
6560 * Success: S_OK.
6561 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6562 * E_OUTOFMEMORY, if memory allocation fails.
6564 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6566 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
6569 /******************************************************************************
6570 * VarBstrFromR8 (OLEAUT32.112)
6572 * Convert a VT_R8 to a VT_BSTR.
6574 * PARAMS
6575 * dblIn [I] Source
6576 * lcid [I] LCID for the conversion
6577 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6578 * pbstrOut [O] Destination
6580 * RETURNS
6581 * Success: S_OK.
6582 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6583 * E_OUTOFMEMORY, if memory allocation fails.
6585 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6587 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
6590 /******************************************************************************
6591 * VarBstrFromCy [OLEAUT32.113]
6593 * Convert a VT_CY to a VT_BSTR.
6595 * PARAMS
6596 * cyIn [I] Source
6597 * lcid [I] LCID for the conversion
6598 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6599 * pbstrOut [O] Destination
6601 * RETURNS
6602 * Success: S_OK.
6603 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6604 * E_OUTOFMEMORY, if memory allocation fails.
6606 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6608 WCHAR buff[256];
6609 VARIANT_DI decVal;
6611 if (!pbstrOut)
6612 return E_INVALIDARG;
6614 decVal.scale = 4;
6615 decVal.sign = 0;
6616 decVal.bitsnum[0] = cyIn.s.Lo;
6617 decVal.bitsnum[1] = cyIn.s.Hi;
6618 if (cyIn.s.Hi & 0x80000000UL) {
6619 DWORD one = 1;
6621 /* Negative number! */
6622 decVal.sign = 1;
6623 decVal.bitsnum[0] = ~decVal.bitsnum[0];
6624 decVal.bitsnum[1] = ~decVal.bitsnum[1];
6625 VARIANT_int_add(decVal.bitsnum, 3, &one, 1);
6627 decVal.bitsnum[2] = 0;
6628 VARIANT_DI_tostringW(&decVal, buff, ARRAY_SIZE(buff));
6630 if (dwFlags & LOCALE_USE_NLS)
6632 WCHAR cybuff[256];
6634 /* Format the currency for the locale */
6635 cybuff[0] = '\0';
6636 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6637 buff, NULL, cybuff, ARRAY_SIZE(cybuff));
6638 *pbstrOut = SysAllocString(cybuff);
6640 else
6641 *pbstrOut = VARIANT_BstrReplaceDecimal(buff,lcid,dwFlags);
6643 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6646 static inline int output_int_len(int o, int min_len, WCHAR *date, int date_len)
6648 int len, tmp;
6650 if(min_len >= date_len)
6651 return -1;
6653 for(len=0, tmp=o; tmp; tmp/=10) len++;
6654 if(!len) len++;
6655 if(len >= date_len)
6656 return -1;
6658 for(tmp=min_len-len; tmp>0; tmp--)
6659 *date++ = '0';
6660 for(tmp=len; tmp>0; tmp--, o/=10)
6661 date[tmp-1] = '0' + o%10;
6662 return min_len>len ? min_len : len;
6665 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6666 BOOL get_date_format(LCID lcid, DWORD flags, const SYSTEMTIME *st,
6667 const WCHAR *fmt, WCHAR *date, int date_len)
6669 static const LCTYPE dayname[] = {
6670 LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
6671 LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6
6673 static const LCTYPE sdayname[] = {
6674 LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
6675 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
6676 LOCALE_SABBREVDAYNAME6
6678 static const LCTYPE monthname[] = {
6679 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
6680 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
6681 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12
6683 static const LCTYPE smonthname[] = {
6684 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
6685 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
6686 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
6687 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12
6690 if(flags & ~(LOCALE_NOUSEROVERRIDE|VAR_DATEVALUEONLY))
6691 FIXME("ignoring flags %x\n", flags);
6692 flags &= LOCALE_NOUSEROVERRIDE;
6694 while(*fmt && date_len) {
6695 int count = 1;
6697 switch(*fmt) {
6698 case 'd':
6699 case 'M':
6700 case 'y':
6701 case 'g':
6702 while(*fmt == *(fmt+count))
6703 count++;
6704 fmt += count-1;
6707 switch(*fmt) {
6708 case 'd':
6709 if(count >= 4)
6710 count = GetLocaleInfoW(lcid, dayname[st->wDayOfWeek] | flags, date, date_len)-1;
6711 else if(count == 3)
6712 count = GetLocaleInfoW(lcid, sdayname[st->wDayOfWeek] | flags, date, date_len)-1;
6713 else
6714 count = output_int_len(st->wDay, count, date, date_len);
6715 break;
6716 case 'M':
6717 if(count >= 4)
6718 count = GetLocaleInfoW(lcid, monthname[st->wMonth-1] | flags, date, date_len)-1;
6719 else if(count == 3)
6720 count = GetLocaleInfoW(lcid, smonthname[st->wMonth-1] | flags, date, date_len)-1;
6721 else
6722 count = output_int_len(st->wMonth, count, date, date_len);
6723 break;
6724 case 'y':
6725 if(count >= 3)
6726 count = output_int_len(st->wYear, 0, date, date_len);
6727 else
6728 count = output_int_len(st->wYear%100, count, date, date_len);
6729 break;
6730 case 'g':
6731 if(count == 2) {
6732 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6734 *date++ = 'A';
6735 date_len--;
6736 if(date_len)
6737 *date = 'D';
6738 else
6739 count = -1;
6740 break;
6742 /* fall through */
6743 default:
6744 *date = *fmt;
6747 if(count < 0)
6748 break;
6749 fmt++;
6750 date += count;
6751 date_len -= count;
6754 if(!date_len)
6755 return FALSE;
6756 *date++ = 0;
6757 return TRUE;
6760 /******************************************************************************
6761 * VarBstrFromDate [OLEAUT32.114]
6763 * Convert a VT_DATE to a VT_BSTR.
6765 * PARAMS
6766 * dateIn [I] Source
6767 * lcid [I] LCID for the conversion
6768 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6769 * pbstrOut [O] Destination
6771 * RETURNS
6772 * Success: S_OK.
6773 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6774 * E_OUTOFMEMORY, if memory allocation fails.
6776 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6778 SYSTEMTIME st;
6779 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6780 WCHAR date[128], fmt_buff[80], *time;
6782 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
6784 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6785 return E_INVALIDARG;
6787 *pbstrOut = NULL;
6789 if (dwFlags & VAR_CALENDAR_THAI)
6790 st.wYear += 553; /* Use the Thai buddhist calendar year */
6791 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6792 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6794 if (dwFlags & LOCALE_USE_NLS)
6795 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6796 else
6798 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6799 double partial = dateIn - whole;
6801 if (whole == 0.0)
6802 dwFlags |= VAR_TIMEVALUEONLY;
6803 else if (partial > -1e-12 && partial < 1e-12)
6804 dwFlags |= VAR_DATEVALUEONLY;
6807 if (dwFlags & VAR_TIMEVALUEONLY)
6808 date[0] = '\0';
6809 else
6810 if (!GetLocaleInfoW(lcid, LOCALE_SSHORTDATE, fmt_buff, ARRAY_SIZE(fmt_buff)) ||
6811 !get_date_format(lcid, dwFlags, &st, fmt_buff, date, ARRAY_SIZE(date)))
6812 return E_INVALIDARG;
6814 if (!(dwFlags & VAR_DATEVALUEONLY))
6816 time = date + lstrlenW(date);
6817 if (time != date)
6818 *time++ = ' ';
6819 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time, ARRAY_SIZE(date)-(time-date)))
6820 return E_INVALIDARG;
6823 *pbstrOut = SysAllocString(date);
6824 if (*pbstrOut)
6825 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6826 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6829 /******************************************************************************
6830 * VarBstrFromBool (OLEAUT32.116)
6832 * Convert a VT_BOOL to a VT_BSTR.
6834 * PARAMS
6835 * boolIn [I] Source
6836 * lcid [I] LCID for the conversion
6837 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6838 * pbstrOut [O] Destination
6840 * RETURNS
6841 * Success: S_OK.
6842 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6843 * E_OUTOFMEMORY, if memory allocation fails.
6845 * NOTES
6846 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6847 * localised text of "True" or "False". To convert a bool into a
6848 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6850 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6852 WCHAR szBuff[64];
6853 DWORD dwResId = IDS_TRUE;
6854 LANGID langId;
6856 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn, lcid, dwFlags, pbstrOut);
6858 if (!pbstrOut)
6859 return E_INVALIDARG;
6861 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6862 * for variant formatting */
6863 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6865 case VAR_BOOLONOFF:
6866 dwResId = IDS_ON;
6867 break;
6868 case VAR_BOOLYESNO:
6869 dwResId = IDS_YES;
6870 break;
6871 case VAR_LOCALBOOL:
6872 break;
6873 default:
6874 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6877 lcid = ConvertDefaultLocale(lcid);
6878 langId = LANGIDFROMLCID(lcid);
6879 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6880 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6882 if (boolIn == VARIANT_FALSE)
6883 dwResId++; /* Use negative form */
6885 VarBstrFromBool_GetLocalised:
6886 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6888 *pbstrOut = SysAllocString(szBuff);
6889 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6892 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6894 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6895 goto VarBstrFromBool_GetLocalised;
6898 /* Should never get here */
6899 WARN("Failed to load bool text!\n");
6900 return E_OUTOFMEMORY;
6903 /******************************************************************************
6904 * VarBstrFromI1 (OLEAUT32.229)
6906 * Convert a VT_I1 to a VT_BSTR.
6908 * PARAMS
6909 * cIn [I] Source
6910 * lcid [I] LCID for the conversion
6911 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6912 * pbstrOut [O] Destination
6914 * RETURNS
6915 * Success: S_OK.
6916 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6917 * E_OUTOFMEMORY, if memory allocation fails.
6919 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6921 ULONG64 ul64 = cIn;
6923 if (cIn < 0)
6925 ul64 = -cIn;
6926 dwFlags |= VAR_NEGATIVE;
6928 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6931 /******************************************************************************
6932 * VarBstrFromUI2 (OLEAUT32.230)
6934 * Convert a VT_UI2 to a VT_BSTR.
6936 * PARAMS
6937 * usIn [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 VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6949 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6952 /******************************************************************************
6953 * VarBstrFromUI4 (OLEAUT32.231)
6955 * Convert a VT_UI4 to a VT_BSTR.
6957 * PARAMS
6958 * ulIn [I] Source
6959 * lcid [I] LCID for the conversion
6960 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6961 * pbstrOut [O] Destination
6963 * RETURNS
6964 * Success: S_OK.
6965 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6966 * E_OUTOFMEMORY, if memory allocation fails.
6968 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6970 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
6973 /******************************************************************************
6974 * VarBstrFromDec (OLEAUT32.232)
6976 * Convert a VT_DECIMAL to a VT_BSTR.
6978 * PARAMS
6979 * pDecIn [I] Source
6980 * lcid [I] LCID for the conversion
6981 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6982 * pbstrOut [O] Destination
6984 * RETURNS
6985 * Success: S_OK.
6986 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6987 * E_OUTOFMEMORY, if memory allocation fails.
6989 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6991 WCHAR buff[256];
6992 VARIANT_DI temp;
6994 if (!pbstrOut)
6995 return E_INVALIDARG;
6997 VARIANT_DIFromDec(pDecIn, &temp);
6998 VARIANT_DI_tostringW(&temp, buff, 256);
7000 if (dwFlags & LOCALE_USE_NLS)
7002 WCHAR numbuff[256];
7004 /* Format the number for the locale */
7005 numbuff[0] = '\0';
7006 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
7007 buff, NULL, numbuff, ARRAY_SIZE(numbuff));
7008 TRACE("created NLS string %s\n", debugstr_w(numbuff));
7009 *pbstrOut = SysAllocString(numbuff);
7011 else
7013 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
7016 TRACE("returning %s\n", debugstr_w(*pbstrOut));
7017 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
7020 /************************************************************************
7021 * VarBstrFromI8 (OLEAUT32.370)
7023 * Convert a VT_I8 to a VT_BSTR.
7025 * PARAMS
7026 * llIn [I] Source
7027 * lcid [I] LCID for the conversion
7028 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7029 * pbstrOut [O] Destination
7031 * RETURNS
7032 * Success: S_OK.
7033 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7034 * E_OUTOFMEMORY, if memory allocation fails.
7036 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7038 ULONG64 ul64 = llIn;
7040 if (llIn < 0)
7042 ul64 = -llIn;
7043 dwFlags |= VAR_NEGATIVE;
7045 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
7048 /************************************************************************
7049 * VarBstrFromUI8 (OLEAUT32.371)
7051 * Convert a VT_UI8 to a VT_BSTR.
7053 * PARAMS
7054 * ullIn [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 VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7066 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
7069 /************************************************************************
7070 * VarBstrFromDisp (OLEAUT32.115)
7072 * Convert a VT_DISPATCH to a BSTR.
7074 * PARAMS
7075 * pdispIn [I] Source
7076 * lcid [I] LCID for conversion
7077 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7078 * pbstrOut [O] Destination
7080 * RETURNS
7081 * Success: S_OK.
7082 * Failure: E_INVALIDARG, if the source value is invalid
7083 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7085 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7087 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
7090 /**********************************************************************
7091 * VarBstrCat (OLEAUT32.313)
7093 * Concatenate two BSTR values.
7095 * PARAMS
7096 * pbstrLeft [I] Source
7097 * pbstrRight [I] Value to concatenate
7098 * pbstrOut [O] Destination
7100 * RETURNS
7101 * Success: S_OK.
7102 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7103 * E_OUTOFMEMORY, if memory allocation fails.
7105 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
7107 unsigned int lenLeft, lenRight;
7109 TRACE("%s,%s,%p\n",
7110 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7111 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
7113 if (!pbstrOut)
7114 return E_INVALIDARG;
7116 /* use byte length here to properly handle ansi-allocated BSTRs */
7117 lenLeft = pbstrLeft ? SysStringByteLen(pbstrLeft) : 0;
7118 lenRight = pbstrRight ? SysStringByteLen(pbstrRight) : 0;
7120 *pbstrOut = SysAllocStringByteLen(NULL, lenLeft + lenRight);
7121 if (!*pbstrOut)
7122 return E_OUTOFMEMORY;
7124 (*pbstrOut)[0] = '\0';
7126 if (pbstrLeft)
7127 memcpy(*pbstrOut, pbstrLeft, lenLeft);
7129 if (pbstrRight)
7130 memcpy((CHAR*)*pbstrOut + lenLeft, pbstrRight, lenRight);
7132 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
7133 return S_OK;
7136 /**********************************************************************
7137 * VarBstrCmp (OLEAUT32.314)
7139 * Compare two BSTR values.
7141 * PARAMS
7142 * pbstrLeft [I] Source
7143 * pbstrRight [I] Value to compare
7144 * lcid [I] LCID for the comparison
7145 * dwFlags [I] Flags to pass directly to CompareStringW().
7147 * RETURNS
7148 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7149 * than, equal to or greater than pbstrRight respectively.
7151 * NOTES
7152 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7153 * states. A NULL BSTR pointer is equivalent to an empty string.
7154 * If LCID is equal to 0, a byte by byte comparison is performed.
7156 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
7158 HRESULT hres;
7159 int ret;
7161 TRACE("%s,%s,%d,%08x\n",
7162 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7163 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
7165 if (!pbstrLeft || !*pbstrLeft)
7167 if (pbstrRight && *pbstrRight)
7168 return VARCMP_LT;
7170 else if (!pbstrRight || !*pbstrRight)
7171 return VARCMP_GT;
7173 if (lcid == 0)
7175 unsigned int lenLeft = SysStringByteLen(pbstrLeft);
7176 unsigned int lenRight = SysStringByteLen(pbstrRight);
7177 ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight));
7178 if (ret < 0)
7179 return VARCMP_LT;
7180 if (ret > 0)
7181 return VARCMP_GT;
7182 if (lenLeft < lenRight)
7183 return VARCMP_LT;
7184 if (lenLeft > lenRight)
7185 return VARCMP_GT;
7186 return VARCMP_EQ;
7188 else
7190 unsigned int lenLeft = SysStringLen(pbstrLeft);
7191 unsigned int lenRight = SysStringLen(pbstrRight);
7193 if (lenLeft == 0 || lenRight == 0)
7195 if (lenLeft == 0 && lenRight == 0) return VARCMP_EQ;
7196 return lenLeft < lenRight ? VARCMP_LT : VARCMP_GT;
7199 hres = CompareStringW(lcid, dwFlags, pbstrLeft, lenLeft,
7200 pbstrRight, lenRight) - CSTR_LESS_THAN;
7201 TRACE("%d\n", hres);
7202 return hres;
7207 * DATE
7210 /******************************************************************************
7211 * VarDateFromUI1 (OLEAUT32.88)
7213 * Convert a VT_UI1 to a VT_DATE.
7215 * PARAMS
7216 * bIn [I] Source
7217 * pdateOut [O] Destination
7219 * RETURNS
7220 * S_OK.
7222 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
7224 return VarR8FromUI1(bIn, pdateOut);
7227 /******************************************************************************
7228 * VarDateFromI2 (OLEAUT32.89)
7230 * Convert a VT_I2 to a VT_DATE.
7232 * PARAMS
7233 * sIn [I] Source
7234 * pdateOut [O] Destination
7236 * RETURNS
7237 * S_OK.
7239 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
7241 return VarR8FromI2(sIn, pdateOut);
7244 /******************************************************************************
7245 * VarDateFromI4 (OLEAUT32.90)
7247 * Convert a VT_I4 to a VT_DATE.
7249 * PARAMS
7250 * lIn [I] Source
7251 * pdateOut [O] Destination
7253 * RETURNS
7254 * S_OK.
7256 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
7258 return VarDateFromR8(lIn, pdateOut);
7261 /******************************************************************************
7262 * VarDateFromR4 (OLEAUT32.91)
7264 * Convert a VT_R4 to a VT_DATE.
7266 * PARAMS
7267 * fltIn [I] Source
7268 * pdateOut [O] Destination
7270 * RETURNS
7271 * S_OK.
7273 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
7275 return VarR8FromR4(fltIn, pdateOut);
7278 /******************************************************************************
7279 * VarDateFromR8 (OLEAUT32.92)
7281 * Convert a VT_R8 to a VT_DATE.
7283 * PARAMS
7284 * dblIn [I] Source
7285 * pdateOut [O] Destination
7287 * RETURNS
7288 * S_OK.
7290 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
7292 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
7293 *pdateOut = (DATE)dblIn;
7294 return S_OK;
7297 /**********************************************************************
7298 * VarDateFromDisp (OLEAUT32.95)
7300 * Convert a VT_DISPATCH to a VT_DATE.
7302 * PARAMS
7303 * pdispIn [I] Source
7304 * lcid [I] LCID for conversion
7305 * pdateOut [O] Destination
7307 * RETURNS
7308 * Success: S_OK.
7309 * Failure: E_INVALIDARG, if the source value is invalid
7310 * DISP_E_OVERFLOW, if the value will not fit in the destination
7311 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7313 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
7315 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
7318 /******************************************************************************
7319 * VarDateFromBool (OLEAUT32.96)
7321 * Convert a VT_BOOL to a VT_DATE.
7323 * PARAMS
7324 * boolIn [I] Source
7325 * pdateOut [O] Destination
7327 * RETURNS
7328 * S_OK.
7330 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
7332 return VarR8FromBool(boolIn, pdateOut);
7335 /**********************************************************************
7336 * VarDateFromCy (OLEAUT32.93)
7338 * Convert a VT_CY to a VT_DATE.
7340 * PARAMS
7341 * lIn [I] Source
7342 * pdateOut [O] Destination
7344 * RETURNS
7345 * S_OK.
7347 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
7349 return VarR8FromCy(cyIn, pdateOut);
7352 /* Date string parsing */
7353 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7354 #define DP_DATESEP 0x02 /* Date separator */
7355 #define DP_MONTH 0x04 /* Month name */
7356 #define DP_AM 0x08 /* AM */
7357 #define DP_PM 0x10 /* PM */
7359 typedef struct tagDATEPARSE
7361 DWORD dwCount; /* Number of fields found so far (maximum 6) */
7362 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
7363 DWORD dwFlags[6]; /* Flags for each field */
7364 DWORD dwValues[6]; /* Value of each field */
7365 } DATEPARSE;
7367 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7369 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7371 /* Determine if a day is valid in a given month of a given year */
7372 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
7374 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7376 if (day && month && month < 13)
7378 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
7379 return TRUE;
7381 return FALSE;
7384 /* Possible orders for 3 numbers making up a date */
7385 #define ORDER_MDY 0x01
7386 #define ORDER_YMD 0x02
7387 #define ORDER_YDM 0x04
7388 #define ORDER_DMY 0x08
7389 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7391 /* Determine a date for a particular locale, from 3 numbers */
7392 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
7393 DWORD offset, SYSTEMTIME *st)
7395 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
7397 if (!dp->dwCount)
7399 v1 = 30; /* Default to (Variant) 0 date part */
7400 v2 = 12;
7401 v3 = 1899;
7402 goto VARIANT_MakeDate_OK;
7405 v1 = dp->dwValues[offset + 0];
7406 v2 = dp->dwValues[offset + 1];
7407 if (dp->dwCount == 2)
7409 SYSTEMTIME current;
7410 GetSystemTime(&current);
7411 v3 = current.wYear;
7413 else
7414 v3 = dp->dwValues[offset + 2];
7416 TRACE("(%d,%d,%d,%d,%d)\n", v1, v2, v3, iDate, offset);
7418 /* If one number must be a month (Because a month name was given), then only
7419 * consider orders with the month in that position.
7420 * If we took the current year as 'v3', then only allow a year in that position.
7422 if (dp->dwFlags[offset + 0] & DP_MONTH)
7424 dwAllOrders = ORDER_MDY;
7426 else if (dp->dwFlags[offset + 1] & DP_MONTH)
7428 dwAllOrders = ORDER_DMY;
7429 if (dp->dwCount > 2)
7430 dwAllOrders |= ORDER_YMD;
7432 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
7434 dwAllOrders = ORDER_YDM;
7436 else
7438 dwAllOrders = ORDER_MDY|ORDER_DMY;
7439 if (dp->dwCount > 2)
7440 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
7443 VARIANT_MakeDate_Start:
7444 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders);
7446 while (dwAllOrders)
7448 DWORD dwTemp;
7450 if (dwCount == 0)
7452 /* First: Try the order given by iDate */
7453 switch (iDate)
7455 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
7456 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
7457 default: dwTry = dwAllOrders & ORDER_YMD; break;
7460 else if (dwCount == 1)
7462 /* Second: Try all the orders compatible with iDate */
7463 switch (iDate)
7465 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7466 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YDM|ORDER_MYD); break;
7467 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7470 else
7472 /* Finally: Try any remaining orders */
7473 dwTry = dwAllOrders;
7476 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount, dwTry);
7478 dwCount++;
7479 if (!dwTry)
7480 continue;
7482 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7484 if (dwTry & ORDER_MDY)
7486 if (VARIANT_IsValidMonthDay(v2,v1,v3))
7488 DATE_SWAP(v1,v2);
7489 goto VARIANT_MakeDate_OK;
7491 dwAllOrders &= ~ORDER_MDY;
7493 if (dwTry & ORDER_YMD)
7495 if (VARIANT_IsValidMonthDay(v3,v2,v1))
7497 DATE_SWAP(v1,v3);
7498 goto VARIANT_MakeDate_OK;
7500 dwAllOrders &= ~ORDER_YMD;
7502 if (dwTry & ORDER_YDM)
7504 if (VARIANT_IsValidMonthDay(v2,v3,v1))
7506 DATE_SWAP(v1,v2);
7507 DATE_SWAP(v2,v3);
7508 goto VARIANT_MakeDate_OK;
7510 dwAllOrders &= ~ORDER_YDM;
7512 if (dwTry & ORDER_DMY)
7514 if (VARIANT_IsValidMonthDay(v1,v2,v3))
7515 goto VARIANT_MakeDate_OK;
7516 dwAllOrders &= ~ORDER_DMY;
7518 if (dwTry & ORDER_MYD)
7520 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7521 if (VARIANT_IsValidMonthDay(v3,v1,v2))
7523 DATE_SWAP(v1,v3);
7524 DATE_SWAP(v2,v3);
7525 goto VARIANT_MakeDate_OK;
7527 dwAllOrders &= ~ORDER_MYD;
7531 if (dp->dwCount == 2)
7533 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7534 v3 = 1; /* 1st of the month */
7535 dwAllOrders = ORDER_YMD|ORDER_MYD;
7536 dp->dwCount = 0; /* Don't return to this code path again */
7537 dwCount = 0;
7538 goto VARIANT_MakeDate_Start;
7541 /* No valid dates were able to be constructed */
7542 return DISP_E_TYPEMISMATCH;
7544 VARIANT_MakeDate_OK:
7546 /* Check that the time part is ok */
7547 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
7548 return DISP_E_TYPEMISMATCH;
7550 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7551 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
7552 st->wHour += 12;
7553 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
7554 st->wHour = 0;
7555 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7557 st->wDay = v1;
7558 st->wMonth = v2;
7559 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7560 * be retrieved from:
7561 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7562 * But Wine doesn't have/use that key as at the time of writing.
7564 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
7565 TRACE("Returning date %d/%d/%d\n", v1, v2, st->wYear);
7566 return S_OK;
7569 /******************************************************************************
7570 * VarDateFromStr [OLEAUT32.94]
7572 * Convert a VT_BSTR to at VT_DATE.
7574 * PARAMS
7575 * strIn [I] String to convert
7576 * lcid [I] Locale identifier for the conversion
7577 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7578 * pdateOut [O] Destination for the converted value
7580 * RETURNS
7581 * Success: S_OK. pdateOut contains the converted value.
7582 * FAILURE: An HRESULT error code indicating the problem.
7584 * NOTES
7585 * Any date format that can be created using the date formats from lcid
7586 * (Either from kernel Nls functions, variant conversion or formatting) is a
7587 * valid input to this function. In addition, a few more esoteric formats are
7588 * also supported for compatibility with the native version. The date is
7589 * interpreted according to the date settings in the control panel, unless
7590 * the date is invalid in that format, in which the most compatible format
7591 * that produces a valid date will be used.
7593 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7595 static const USHORT ParseDateTokens[] =
7597 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7598 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7599 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7600 LOCALE_SMONTHNAME13,
7601 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7602 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7603 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7604 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7605 LOCALE_SABBREVMONTHNAME13,
7606 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7607 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7608 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7609 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7610 LOCALE_SABBREVDAYNAME7,
7611 LOCALE_S1159, LOCALE_S2359,
7612 LOCALE_SDATE
7614 static const BYTE ParseDateMonths[] =
7616 1,2,3,4,5,6,7,8,9,10,11,12,13,
7617 1,2,3,4,5,6,7,8,9,10,11,12,13
7619 unsigned int i;
7620 BSTR tokens[ARRAY_SIZE(ParseDateTokens)];
7621 DATEPARSE dp;
7622 DWORD dwDateSeps = 0, iDate = 0;
7623 HRESULT hRet = S_OK;
7625 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7626 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7627 return E_INVALIDARG;
7629 if (!strIn)
7630 return DISP_E_TYPEMISMATCH;
7632 *pdateOut = 0.0;
7634 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7636 memset(&dp, 0, sizeof(dp));
7638 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7639 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7640 TRACE("iDate is %d\n", iDate);
7642 /* Get the month/day/am/pm tokens for this locale */
7643 for (i = 0; i < ARRAY_SIZE(tokens); i++)
7645 WCHAR buff[128];
7646 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7648 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7649 * GetAltMonthNames(). We should really cache these strings too.
7651 buff[0] = '\0';
7652 GetLocaleInfoW(lcid, lctype, buff, ARRAY_SIZE(buff));
7653 tokens[i] = SysAllocString(buff);
7654 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7657 /* Parse the string into our structure */
7658 while (*strIn)
7660 if ('0' <= *strIn && *strIn <= '9')
7662 if (dp.dwCount >= 6)
7664 hRet = DISP_E_TYPEMISMATCH;
7665 break;
7667 dp.dwValues[dp.dwCount] = wcstoul(strIn, &strIn, 10);
7668 dp.dwCount++;
7669 strIn--;
7671 else if (iswalpha(*strIn))
7673 BOOL bFound = FALSE;
7675 for (i = 0; i < ARRAY_SIZE(tokens); i++)
7677 DWORD dwLen = lstrlenW(tokens[i]);
7678 if (dwLen && !wcsnicmp(strIn, tokens[i], dwLen))
7680 if (i <= 25)
7682 if (dp.dwCount >= 6)
7683 hRet = DISP_E_TYPEMISMATCH;
7684 else
7686 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7687 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7688 dp.dwCount++;
7691 else if (i > 39 && i < 42)
7693 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7694 hRet = DISP_E_TYPEMISMATCH;
7695 else
7697 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7698 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7701 strIn += (dwLen - 1);
7702 bFound = TRUE;
7703 break;
7707 if (!bFound)
7709 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7710 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7712 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7713 if (*strIn == 'a' || *strIn == 'A')
7715 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7716 dp.dwParseFlags |= DP_AM;
7718 else
7720 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7721 dp.dwParseFlags |= DP_PM;
7723 strIn++;
7725 else
7727 TRACE("No matching token for %s\n", debugstr_w(strIn));
7728 hRet = DISP_E_TYPEMISMATCH;
7729 break;
7733 else if (*strIn == ':' || *strIn == '.')
7735 if (!dp.dwCount || !strIn[1])
7736 hRet = DISP_E_TYPEMISMATCH;
7737 else
7738 if (tokens[42][0] == *strIn)
7740 dwDateSeps++;
7741 if (dwDateSeps > 2)
7742 hRet = DISP_E_TYPEMISMATCH;
7743 else
7744 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7746 else
7747 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7749 else if (*strIn == '-' || *strIn == '/')
7751 dwDateSeps++;
7752 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7753 hRet = DISP_E_TYPEMISMATCH;
7754 else
7755 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7757 else if (*strIn == ',' || iswspace(*strIn))
7759 if (*strIn == ',' && !strIn[1])
7760 hRet = DISP_E_TYPEMISMATCH;
7762 else
7764 hRet = DISP_E_TYPEMISMATCH;
7766 strIn++;
7769 if (!dp.dwCount || dp.dwCount > 6 ||
7770 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7771 hRet = DISP_E_TYPEMISMATCH;
7773 if (SUCCEEDED(hRet))
7775 SYSTEMTIME st;
7776 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7778 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7780 /* Figure out which numbers correspond to which fields.
7782 * This switch statement works based on the fact that native interprets any
7783 * fields that are not joined with a time separator ('.' or ':') as date
7784 * fields. Thus we construct a value from 0-32 where each set bit indicates
7785 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7786 * For valid permutations, we set dwOffset to point to the first date field
7787 * and shorten dp.dwCount by the number of time fields found. The real
7788 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7789 * each date number must represent in the context of iDate.
7791 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7793 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7795 case 0x1: /* TT TTDD TTDDD */
7796 if (dp.dwCount > 3 &&
7797 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7798 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7799 hRet = DISP_E_TYPEMISMATCH;
7800 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7801 hRet = DISP_E_TYPEMISMATCH;
7802 st.wHour = dp.dwValues[0];
7803 st.wMinute = dp.dwValues[1];
7804 dp.dwCount -= 2;
7805 dwOffset = 2;
7806 break;
7808 case 0x3: /* TTT TTTDD TTTDDD */
7809 if (dp.dwCount > 4 &&
7810 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7811 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7812 hRet = DISP_E_TYPEMISMATCH;
7813 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7814 hRet = DISP_E_TYPEMISMATCH;
7815 st.wHour = dp.dwValues[0];
7816 st.wMinute = dp.dwValues[1];
7817 st.wSecond = dp.dwValues[2];
7818 dwOffset = 3;
7819 dp.dwCount -= 3;
7820 break;
7822 case 0x4: /* DDTT */
7823 if (dp.dwCount != 4 ||
7824 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7825 hRet = DISP_E_TYPEMISMATCH;
7827 st.wHour = dp.dwValues[2];
7828 st.wMinute = dp.dwValues[3];
7829 dp.dwCount -= 2;
7830 break;
7832 case 0x0: /* T DD DDD TDDD TDDD */
7833 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7835 st.wHour = dp.dwValues[0]; /* T */
7836 dp.dwCount = 0;
7837 break;
7839 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7841 hRet = DISP_E_TYPEMISMATCH;
7843 else if (dp.dwCount == 3)
7845 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7847 dp.dwCount = 2;
7848 st.wHour = dp.dwValues[0];
7849 dwOffset = 1;
7850 break;
7852 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7854 dp.dwCount = 2;
7855 st.wHour = dp.dwValues[2];
7856 break;
7858 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7859 hRet = DISP_E_TYPEMISMATCH;
7861 else if (dp.dwCount == 4)
7863 dp.dwCount = 3;
7864 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7866 st.wHour = dp.dwValues[0];
7867 dwOffset = 1;
7869 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7871 st.wHour = dp.dwValues[3];
7873 else
7874 hRet = DISP_E_TYPEMISMATCH;
7875 break;
7877 /* .. fall through .. */
7879 case 0x8: /* DDDTT */
7880 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7881 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7882 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7883 dp.dwCount == 4 || dp.dwCount == 6)
7884 hRet = DISP_E_TYPEMISMATCH;
7885 st.wHour = dp.dwValues[3];
7886 st.wMinute = dp.dwValues[4];
7887 if (dp.dwCount == 5)
7888 dp.dwCount -= 2;
7889 break;
7891 case 0xC: /* DDTTT */
7892 if (dp.dwCount != 5 ||
7893 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7894 hRet = DISP_E_TYPEMISMATCH;
7895 st.wHour = dp.dwValues[2];
7896 st.wMinute = dp.dwValues[3];
7897 st.wSecond = dp.dwValues[4];
7898 dp.dwCount -= 3;
7899 break;
7901 case 0x18: /* DDDTTT */
7902 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7903 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7904 hRet = DISP_E_TYPEMISMATCH;
7905 st.wHour = dp.dwValues[3];
7906 st.wMinute = dp.dwValues[4];
7907 st.wSecond = dp.dwValues[5];
7908 dp.dwCount -= 3;
7909 break;
7911 default:
7912 hRet = DISP_E_TYPEMISMATCH;
7913 break;
7916 if (SUCCEEDED(hRet))
7918 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7920 if (dwFlags & VAR_TIMEVALUEONLY)
7922 st.wYear = 1899;
7923 st.wMonth = 12;
7924 st.wDay = 30;
7926 else if (dwFlags & VAR_DATEVALUEONLY)
7927 st.wHour = st.wMinute = st.wSecond = 0;
7929 /* Finally, convert the value to a VT_DATE */
7930 if (SUCCEEDED(hRet))
7931 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7935 for (i = 0; i < ARRAY_SIZE(tokens); i++)
7936 SysFreeString(tokens[i]);
7937 return hRet;
7940 /******************************************************************************
7941 * VarDateFromI1 (OLEAUT32.221)
7943 * Convert a VT_I1 to a VT_DATE.
7945 * PARAMS
7946 * cIn [I] Source
7947 * pdateOut [O] Destination
7949 * RETURNS
7950 * S_OK.
7952 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7954 return VarR8FromI1(cIn, pdateOut);
7957 /******************************************************************************
7958 * VarDateFromUI2 (OLEAUT32.222)
7960 * Convert a VT_UI2 to a VT_DATE.
7962 * PARAMS
7963 * uiIn [I] Source
7964 * pdateOut [O] Destination
7966 * RETURNS
7967 * S_OK.
7969 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7971 return VarR8FromUI2(uiIn, pdateOut);
7974 /******************************************************************************
7975 * VarDateFromUI4 (OLEAUT32.223)
7977 * Convert a VT_UI4 to a VT_DATE.
7979 * PARAMS
7980 * ulIn [I] Source
7981 * pdateOut [O] Destination
7983 * RETURNS
7984 * S_OK.
7986 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7988 return VarDateFromR8(ulIn, pdateOut);
7991 /**********************************************************************
7992 * VarDateFromDec (OLEAUT32.224)
7994 * Convert a VT_DECIMAL to a VT_DATE.
7996 * PARAMS
7997 * pdecIn [I] Source
7998 * pdateOut [O] Destination
8000 * RETURNS
8001 * S_OK.
8003 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
8005 return VarR8FromDec(pdecIn, pdateOut);
8008 /******************************************************************************
8009 * VarDateFromI8 (OLEAUT32.364)
8011 * Convert a VT_I8 to a VT_DATE.
8013 * PARAMS
8014 * llIn [I] Source
8015 * pdateOut [O] Destination
8017 * RETURNS
8018 * Success: S_OK.
8019 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8021 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
8023 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
8024 *pdateOut = (DATE)llIn;
8025 return S_OK;
8028 /******************************************************************************
8029 * VarDateFromUI8 (OLEAUT32.365)
8031 * Convert a VT_UI8 to a VT_DATE.
8033 * PARAMS
8034 * ullIn [I] Source
8035 * pdateOut [O] Destination
8037 * RETURNS
8038 * Success: S_OK.
8039 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8041 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
8043 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
8044 *pdateOut = (DATE)ullIn;
8045 return S_OK;