Sync to Wine-0_9_3:
[reactos.git] / reactos / lib / oleaut32 / vartype.c
1 /*
2 * Low level variant functions
3 *
4 * Copyright 2003 Jon Griffiths
5 *
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.
10 *
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.
15 *
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #define COBJMACROS
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
24
25 #include "wine/debug.h"
26 #include "wine/unicode.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winnt.h"
30 #include "variant.h"
31 #include "resource.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(variant);
34
35 extern HMODULE OLEAUT32_hModule;
36
37 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
38 #define CY_MULTIPLIER_F 10000.0
39 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
40 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
41
42 static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' };
43 static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' };
44
45 /* Copy data from one variant to another. */
46 static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
47 {
48 switch (vt)
49 {
50 case VT_I1:
51 case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
52 case VT_BOOL:
53 case VT_I2:
54 case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
55 case VT_R4:
56 case VT_INT:
57 case VT_I4:
58 case VT_UINT:
59 case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
60 case VT_R8:
61 case VT_DATE:
62 case VT_CY:
63 case VT_I8:
64 case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break;
65 case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break;
66 case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
67 default:
68 FIXME("VT_ type %d unhandled, please report!\n", vt);
69 }
70 }
71
72 /* Macro to inline conversion from a float or double to any integer type,
73 * rounding according to the 'dutch' convention.
74 */
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);
85
86
87 /* Coerce VT_BSTR to a numeric type */
88 static HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
89 void* pOut, VARTYPE vt)
90 {
91 VARIANTARG dstVar;
92 HRESULT hRet;
93 NUMPARSE np;
94 BYTE rgb[1024];
95
96 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
97 np.cDig = sizeof(rgb) / sizeof(BYTE);
98 np.dwInFlags = NUMPRS_STD;
99
100 hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
101
102 if (SUCCEEDED(hRet))
103 {
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);
108 }
109 return hRet;
110 }
111
112 /* Coerce VT_DISPATCH to another type */
113 static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, VARTYPE vt)
114 {
115 static const DISPPARAMS emptyParams = { NULL, NULL, 0, 0 };
116 VARIANTARG srcVar, dstVar;
117 HRESULT hRet;
118
119 if (!pdispIn)
120 return DISP_E_BADVARTYPE;
121
122 /* Get the default 'value' property from the IDispatch */
123 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
124 (DISPPARAMS*)&emptyParams, &srcVar, NULL, NULL);
125
126 if (SUCCEEDED(hRet))
127 {
128 /* Convert the property to the requested type */
129 V_VT(&dstVar) = VT_EMPTY;
130 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, 0, vt);
131 VariantClear(&srcVar);
132
133 if (SUCCEEDED(hRet))
134 {
135 VARIANT_CopyData(&dstVar, vt, pOut);
136 VariantClear(&srcVar);
137 }
138 }
139 else
140 hRet = DISP_E_TYPEMISMATCH;
141 return hRet;
142 }
143
144 /* Inline return type */
145 #define RETTYP inline static HRESULT
146
147
148 /* Simple compiler cast from one type to another */
149 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
150 *out = in; return S_OK; }
151
152 /* Compiler cast where input cannot be negative */
153 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
154 if (in < (src)0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
155
156 /* Compiler cast where input cannot be > some number */
157 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
158 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
159
160 /* Compiler cast where input cannot be < some number or >= some other number */
161 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
162 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
163
164 /* I1 */
165 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX);
166 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX);
167 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX);
168 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool);
169 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX);
170 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX);
171 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX);
172 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX);
173
174 /* UI1 */
175 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX);
176 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool);
177 NEGTST(BYTE, signed char, VarUI1FromI1);
178 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX);
179 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX);
180 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX);
181 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX);
182 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX);
183
184 /* I2 */
185 SIMPLE(SHORT, BYTE, VarI2FromUI1);
186 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX);
187 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool);
188 SIMPLE(SHORT, signed char, VarI2FromI1);
189 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX);
190 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX);
191 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX);
192 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX);
193
194 /* UI2 */
195 SIMPLE(USHORT, BYTE, VarUI2FromUI1);
196 NEGTST(USHORT, SHORT, VarUI2FromI2);
197 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX);
198 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool);
199 NEGTST(USHORT, signed char, VarUI2FromI1);
200 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX);
201 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX);
202 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX);
203
204 /* I4 */
205 SIMPLE(LONG, BYTE, VarI4FromUI1);
206 SIMPLE(LONG, SHORT, VarI4FromI2);
207 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool);
208 SIMPLE(LONG, signed char, VarI4FromI1);
209 SIMPLE(LONG, USHORT, VarI4FromUI2);
210 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX);
211 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX);
212 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX);
213
214 /* UI4 */
215 SIMPLE(ULONG, BYTE, VarUI4FromUI1);
216 NEGTST(ULONG, SHORT, VarUI4FromI2);
217 NEGTST(ULONG, LONG, VarUI4FromI4);
218 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool);
219 NEGTST(ULONG, signed char, VarUI4FromI1);
220 SIMPLE(ULONG, USHORT, VarUI4FromUI2);
221 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX);
222 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX);
223
224 /* I8 */
225 SIMPLE(LONG64, BYTE, VarI8FromUI1);
226 SIMPLE(LONG64, SHORT, VarI8FromI2);
227 SIMPLE(LONG64, signed char, VarI8FromI1);
228 SIMPLE(LONG64, USHORT, VarI8FromUI2);
229 SIMPLE(LONG64, LONG, VarI8FromI4);
230 SIMPLE(LONG64, ULONG, VarI8FromUI4);
231 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX);
232
233 /* UI8 */
234 SIMPLE(ULONG64, BYTE, VarUI8FromUI1);
235 NEGTST(ULONG64, SHORT, VarUI8FromI2);
236 NEGTST(ULONG64, signed char, VarUI8FromI1);
237 SIMPLE(ULONG64, USHORT, VarUI8FromUI2);
238 NEGTST(ULONG64, LONG, VarUI8FromI4);
239 SIMPLE(ULONG64, ULONG, VarUI8FromUI4);
240 NEGTST(ULONG64, LONG64, VarUI8FromI8);
241
242 /* R4 (float) */
243 SIMPLE(float, BYTE, VarR4FromUI1);
244 SIMPLE(float, SHORT, VarR4FromI2);
245 SIMPLE(float, signed char, VarR4FromI1);
246 SIMPLE(float, USHORT, VarR4FromUI2);
247 SIMPLE(float, LONG, VarR4FromI4);
248 SIMPLE(float, ULONG, VarR4FromUI4);
249 SIMPLE(float, LONG64, VarR4FromI8);
250 SIMPLE(float, ULONG64, VarR4FromUI8);
251
252 /* R8 (double) */
253 SIMPLE(double, BYTE, VarR8FromUI1);
254 SIMPLE(double, SHORT, VarR8FromI2);
255 SIMPLE(double, float, VarR8FromR4);
256 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
257 SIMPLE(double, DATE, VarR8FromDate);
258 SIMPLE(double, signed char, VarR8FromI1);
259 SIMPLE(double, USHORT, VarR8FromUI2);
260 SIMPLE(double, LONG, VarR8FromI4);
261 SIMPLE(double, ULONG, VarR8FromUI4);
262 SIMPLE(double, LONG64, VarR8FromI8);
263 SIMPLE(double, ULONG64, VarR8FromUI8);
264
265
266 /* I1
267 */
268
269 /************************************************************************
270 * VarI1FromUI1 (OLEAUT32.244)
271 *
272 * Convert a VT_UI1 to a VT_I1.
273 *
274 * PARAMS
275 * bIn [I] Source
276 * pcOut [O] Destination
277 *
278 * RETURNS
279 * Success: S_OK.
280 * Failure: E_INVALIDARG, if the source value is invalid
281 * DISP_E_OVERFLOW, if the value will not fit in the destination
282 */
283 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
284 {
285 return _VarI1FromUI1(bIn, pcOut);
286 }
287
288 /************************************************************************
289 * VarI1FromI2 (OLEAUT32.245)
290 *
291 * Convert a VT_I2 to a VT_I1.
292 *
293 * PARAMS
294 * sIn [I] Source
295 * pcOut [O] Destination
296 *
297 * RETURNS
298 * Success: S_OK.
299 * Failure: E_INVALIDARG, if the source value is invalid
300 * DISP_E_OVERFLOW, if the value will not fit in the destination
301 */
302 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
303 {
304 return _VarI1FromI2(sIn, pcOut);
305 }
306
307 /************************************************************************
308 * VarI1FromI4 (OLEAUT32.246)
309 *
310 * Convert a VT_I4 to a VT_I1.
311 *
312 * PARAMS
313 * iIn [I] Source
314 * pcOut [O] Destination
315 *
316 * RETURNS
317 * Success: S_OK.
318 * Failure: E_INVALIDARG, if the source value is invalid
319 * DISP_E_OVERFLOW, if the value will not fit in the destination
320 */
321 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
322 {
323 return _VarI1FromI4(iIn, pcOut);
324 }
325
326 /************************************************************************
327 * VarI1FromR4 (OLEAUT32.247)
328 *
329 * Convert a VT_R4 to a VT_I1.
330 *
331 * PARAMS
332 * fltIn [I] Source
333 * pcOut [O] Destination
334 *
335 * RETURNS
336 * Success: S_OK.
337 * Failure: E_INVALIDARG, if the source value is invalid
338 * DISP_E_OVERFLOW, if the value will not fit in the destination
339 */
340 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
341 {
342 return VarI1FromR8(fltIn, pcOut);
343 }
344
345 /************************************************************************
346 * VarI1FromR8 (OLEAUT32.248)
347 *
348 * Convert a VT_R8 to a VT_I1.
349 *
350 * PARAMS
351 * dblIn [I] Source
352 * pcOut [O] Destination
353 *
354 * RETURNS
355 * Success: S_OK.
356 * Failure: E_INVALIDARG, if the source value is invalid
357 * DISP_E_OVERFLOW, if the value will not fit in the destination
358 *
359 * NOTES
360 * See VarI8FromR8() for details concerning rounding.
361 */
362 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
363 {
364 if (dblIn < (double)I1_MIN || dblIn > (double)I1_MAX)
365 return DISP_E_OVERFLOW;
366 VARIANT_DutchRound(CHAR, dblIn, *pcOut);
367 return S_OK;
368 }
369
370 /************************************************************************
371 * VarI1FromDate (OLEAUT32.249)
372 *
373 * Convert a VT_DATE to a VT_I1.
374 *
375 * PARAMS
376 * dateIn [I] Source
377 * pcOut [O] Destination
378 *
379 * RETURNS
380 * Success: S_OK.
381 * Failure: E_INVALIDARG, if the source value is invalid
382 * DISP_E_OVERFLOW, if the value will not fit in the destination
383 */
384 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
385 {
386 return VarI1FromR8(dateIn, pcOut);
387 }
388
389 /************************************************************************
390 * VarI1FromCy (OLEAUT32.250)
391 *
392 * Convert a VT_CY to a VT_I1.
393 *
394 * PARAMS
395 * cyIn [I] Source
396 * pcOut [O] Destination
397 *
398 * RETURNS
399 * Success: S_OK.
400 * Failure: E_INVALIDARG, if the source value is invalid
401 * DISP_E_OVERFLOW, if the value will not fit in the destination
402 */
403 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
404 {
405 LONG i = I1_MAX + 1;
406
407 VarI4FromCy(cyIn, &i);
408 return _VarI1FromI4(i, pcOut);
409 }
410
411 /************************************************************************
412 * VarI1FromStr (OLEAUT32.251)
413 *
414 * Convert a VT_BSTR to a VT_I1.
415 *
416 * PARAMS
417 * strIn [I] Source
418 * lcid [I] LCID for the conversion
419 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
420 * pcOut [O] Destination
421 *
422 * RETURNS
423 * Success: S_OK.
424 * Failure: E_INVALIDARG, if the source value is invalid
425 * DISP_E_OVERFLOW, if the value will not fit in the destination
426 * DISP_E_TYPEMISMATCH, if the type cannot be converted
427 */
428 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
429 {
430 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
431 }
432
433 /************************************************************************
434 * VarI1FromDisp (OLEAUT32.252)
435 *
436 * Convert a VT_DISPATCH to a VT_I1.
437 *
438 * PARAMS
439 * pdispIn [I] Source
440 * lcid [I] LCID for conversion
441 * pcOut [O] Destination
442 *
443 * RETURNS
444 * Success: S_OK.
445 * Failure: E_INVALIDARG, if the source value is invalid
446 * DISP_E_OVERFLOW, if the value will not fit in the destination
447 * DISP_E_TYPEMISMATCH, if the type cannot be converted
448 */
449 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
450 {
451 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1);
452 }
453
454 /************************************************************************
455 * VarI1FromBool (OLEAUT32.253)
456 *
457 * Convert a VT_BOOL to a VT_I1.
458 *
459 * PARAMS
460 * boolIn [I] Source
461 * pcOut [O] Destination
462 *
463 * RETURNS
464 * S_OK.
465 */
466 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
467 {
468 return _VarI1FromBool(boolIn, pcOut);
469 }
470
471 /************************************************************************
472 * VarI1FromUI2 (OLEAUT32.254)
473 *
474 * Convert a VT_UI2 to a VT_I1.
475 *
476 * PARAMS
477 * usIn [I] Source
478 * pcOut [O] Destination
479 *
480 * RETURNS
481 * Success: S_OK.
482 * Failure: E_INVALIDARG, if the source value is invalid
483 * DISP_E_OVERFLOW, if the value will not fit in the destination
484 */
485 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
486 {
487 return _VarI1FromUI2(usIn, pcOut);
488 }
489
490 /************************************************************************
491 * VarI1FromUI4 (OLEAUT32.255)
492 *
493 * Convert a VT_UI4 to a VT_I1.
494 *
495 * PARAMS
496 * ulIn [I] Source
497 * pcOut [O] Destination
498 *
499 * RETURNS
500 * Success: S_OK.
501 * Failure: E_INVALIDARG, if the source value is invalid
502 * DISP_E_OVERFLOW, if the value will not fit in the destination
503 * DISP_E_TYPEMISMATCH, if the type cannot be converted
504 */
505 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
506 {
507 return _VarI1FromUI4(ulIn, pcOut);
508 }
509
510 /************************************************************************
511 * VarI1FromDec (OLEAUT32.256)
512 *
513 * Convert a VT_DECIMAL to a VT_I1.
514 *
515 * PARAMS
516 * pDecIn [I] Source
517 * pcOut [O] Destination
518 *
519 * RETURNS
520 * Success: S_OK.
521 * Failure: E_INVALIDARG, if the source value is invalid
522 * DISP_E_OVERFLOW, if the value will not fit in the destination
523 */
524 HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut)
525 {
526 LONG64 i64;
527 HRESULT hRet;
528
529 hRet = VarI8FromDec(pdecIn, &i64);
530
531 if (SUCCEEDED(hRet))
532 hRet = _VarI1FromI8(i64, pcOut);
533 return hRet;
534 }
535
536 /************************************************************************
537 * VarI1FromI8 (OLEAUT32.376)
538 *
539 * Convert a VT_I8 to a VT_I1.
540 *
541 * PARAMS
542 * llIn [I] Source
543 * pcOut [O] Destination
544 *
545 * RETURNS
546 * Success: S_OK.
547 * Failure: E_INVALIDARG, if the source value is invalid
548 * DISP_E_OVERFLOW, if the value will not fit in the destination
549 */
550 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
551 {
552 return _VarI1FromI8(llIn, pcOut);
553 }
554
555 /************************************************************************
556 * VarI1FromUI8 (OLEAUT32.377)
557 *
558 * Convert a VT_UI8 to a VT_I1.
559 *
560 * PARAMS
561 * ullIn [I] Source
562 * pcOut [O] Destination
563 *
564 * RETURNS
565 * Success: S_OK.
566 * Failure: E_INVALIDARG, if the source value is invalid
567 * DISP_E_OVERFLOW, if the value will not fit in the destination
568 */
569 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
570 {
571 return _VarI1FromUI8(ullIn, pcOut);
572 }
573
574 /* UI1
575 */
576
577 /************************************************************************
578 * VarUI1FromI2 (OLEAUT32.130)
579 *
580 * Convert a VT_I2 to a VT_UI1.
581 *
582 * PARAMS
583 * sIn [I] Source
584 * pbOut [O] Destination
585 *
586 * RETURNS
587 * Success: S_OK.
588 * Failure: E_INVALIDARG, if the source value is invalid
589 * DISP_E_OVERFLOW, if the value will not fit in the destination
590 */
591 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
592 {
593 return _VarUI1FromI2(sIn, pbOut);
594 }
595
596 /************************************************************************
597 * VarUI1FromI4 (OLEAUT32.131)
598 *
599 * Convert a VT_I4 to a VT_UI1.
600 *
601 * PARAMS
602 * iIn [I] Source
603 * pbOut [O] Destination
604 *
605 * RETURNS
606 * Success: S_OK.
607 * Failure: E_INVALIDARG, if the source value is invalid
608 * DISP_E_OVERFLOW, if the value will not fit in the destination
609 */
610 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
611 {
612 return _VarUI1FromI4(iIn, pbOut);
613 }
614
615 /************************************************************************
616 * VarUI1FromR4 (OLEAUT32.132)
617 *
618 * Convert a VT_R4 to a VT_UI1.
619 *
620 * PARAMS
621 * fltIn [I] Source
622 * pbOut [O] Destination
623 *
624 * RETURNS
625 * Success: S_OK.
626 * Failure: E_INVALIDARG, if the source value is invalid
627 * DISP_E_OVERFLOW, if the value will not fit in the destination
628 * DISP_E_TYPEMISMATCH, if the type cannot be converted
629 */
630 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
631 {
632 return VarUI1FromR8(fltIn, pbOut);
633 }
634
635 /************************************************************************
636 * VarUI1FromR8 (OLEAUT32.133)
637 *
638 * Convert a VT_R8 to a VT_UI1.
639 *
640 * PARAMS
641 * dblIn [I] Source
642 * pbOut [O] Destination
643 *
644 * RETURNS
645 * Success: S_OK.
646 * Failure: E_INVALIDARG, if the source value is invalid
647 * DISP_E_OVERFLOW, if the value will not fit in the destination
648 *
649 * NOTES
650 * See VarI8FromR8() for details concerning rounding.
651 */
652 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
653 {
654 if (dblIn < -0.5 || dblIn > (double)UI1_MAX)
655 return DISP_E_OVERFLOW;
656 VARIANT_DutchRound(BYTE, dblIn, *pbOut);
657 return S_OK;
658 }
659
660 /************************************************************************
661 * VarUI1FromCy (OLEAUT32.134)
662 *
663 * Convert a VT_CY to a VT_UI1.
664 *
665 * PARAMS
666 * cyIn [I] Source
667 * pbOut [O] Destination
668 *
669 * RETURNS
670 * Success: S_OK.
671 * Failure: E_INVALIDARG, if the source value is invalid
672 * DISP_E_OVERFLOW, if the value will not fit in the destination
673 *
674 * NOTES
675 * Negative values >= -5000 will be converted to 0.
676 */
677 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
678 {
679 ULONG i = UI1_MAX + 1;
680
681 VarUI4FromCy(cyIn, &i);
682 return _VarUI1FromUI4(i, pbOut);
683 }
684
685 /************************************************************************
686 * VarUI1FromDate (OLEAUT32.135)
687 *
688 * Convert a VT_DATE to a VT_UI1.
689 *
690 * PARAMS
691 * dateIn [I] Source
692 * pbOut [O] Destination
693 *
694 * RETURNS
695 * Success: S_OK.
696 * Failure: E_INVALIDARG, if the source value is invalid
697 * DISP_E_OVERFLOW, if the value will not fit in the destination
698 */
699 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
700 {
701 return VarUI1FromR8(dateIn, pbOut);
702 }
703
704 /************************************************************************
705 * VarUI1FromStr (OLEAUT32.136)
706 *
707 * Convert a VT_BSTR to a VT_UI1.
708 *
709 * PARAMS
710 * strIn [I] Source
711 * lcid [I] LCID for the conversion
712 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
713 * pbOut [O] Destination
714 *
715 * RETURNS
716 * Success: S_OK.
717 * Failure: E_INVALIDARG, if the source value is invalid
718 * DISP_E_OVERFLOW, if the value will not fit in the destination
719 * DISP_E_TYPEMISMATCH, if the type cannot be converted
720 */
721 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
722 {
723 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
724 }
725
726 /************************************************************************
727 * VarUI1FromDisp (OLEAUT32.137)
728 *
729 * Convert a VT_DISPATCH to a VT_UI1.
730 *
731 * PARAMS
732 * pdispIn [I] Source
733 * lcid [I] LCID for conversion
734 * pbOut [O] Destination
735 *
736 * RETURNS
737 * Success: S_OK.
738 * Failure: E_INVALIDARG, if the source value is invalid
739 * DISP_E_OVERFLOW, if the value will not fit in the destination
740 * DISP_E_TYPEMISMATCH, if the type cannot be converted
741 */
742 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
743 {
744 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1);
745 }
746
747 /************************************************************************
748 * VarUI1FromBool (OLEAUT32.138)
749 *
750 * Convert a VT_BOOL to a VT_UI1.
751 *
752 * PARAMS
753 * boolIn [I] Source
754 * pbOut [O] Destination
755 *
756 * RETURNS
757 * S_OK.
758 */
759 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
760 {
761 return _VarUI1FromBool(boolIn, pbOut);
762 }
763
764 /************************************************************************
765 * VarUI1FromI1 (OLEAUT32.237)
766 *
767 * Convert a VT_I1 to a VT_UI1.
768 *
769 * PARAMS
770 * cIn [I] Source
771 * pbOut [O] Destination
772 *
773 * RETURNS
774 * Success: S_OK.
775 * Failure: E_INVALIDARG, if the source value is invalid
776 * DISP_E_OVERFLOW, if the value will not fit in the destination
777 */
778 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
779 {
780 return _VarUI1FromI1(cIn, pbOut);
781 }
782
783 /************************************************************************
784 * VarUI1FromUI2 (OLEAUT32.238)
785 *
786 * Convert a VT_UI2 to a VT_UI1.
787 *
788 * PARAMS
789 * usIn [I] Source
790 * pbOut [O] Destination
791 *
792 * RETURNS
793 * Success: S_OK.
794 * Failure: E_INVALIDARG, if the source value is invalid
795 * DISP_E_OVERFLOW, if the value will not fit in the destination
796 */
797 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
798 {
799 return _VarUI1FromUI2(usIn, pbOut);
800 }
801
802 /************************************************************************
803 * VarUI1FromUI4 (OLEAUT32.239)
804 *
805 * Convert a VT_UI4 to a VT_UI1.
806 *
807 * PARAMS
808 * ulIn [I] Source
809 * pbOut [O] Destination
810 *
811 * RETURNS
812 * Success: S_OK.
813 * Failure: E_INVALIDARG, if the source value is invalid
814 * DISP_E_OVERFLOW, if the value will not fit in the destination
815 */
816 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
817 {
818 return _VarUI1FromUI4(ulIn, pbOut);
819 }
820
821 /************************************************************************
822 * VarUI1FromDec (OLEAUT32.240)
823 *
824 * Convert a VT_DECIMAL to a VT_UI1.
825 *
826 * PARAMS
827 * pDecIn [I] Source
828 * pbOut [O] Destination
829 *
830 * RETURNS
831 * Success: S_OK.
832 * Failure: E_INVALIDARG, if the source value is invalid
833 * DISP_E_OVERFLOW, if the value will not fit in the destination
834 */
835 HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut)
836 {
837 LONG64 i64;
838 HRESULT hRet;
839
840 hRet = VarI8FromDec(pdecIn, &i64);
841
842 if (SUCCEEDED(hRet))
843 hRet = _VarUI1FromI8(i64, pbOut);
844 return hRet;
845 }
846
847 /************************************************************************
848 * VarUI1FromI8 (OLEAUT32.372)
849 *
850 * Convert a VT_I8 to a VT_UI1.
851 *
852 * PARAMS
853 * llIn [I] Source
854 * pbOut [O] Destination
855 *
856 * RETURNS
857 * Success: S_OK.
858 * Failure: E_INVALIDARG, if the source value is invalid
859 * DISP_E_OVERFLOW, if the value will not fit in the destination
860 */
861 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
862 {
863 return _VarUI1FromI8(llIn, pbOut);
864 }
865
866 /************************************************************************
867 * VarUI1FromUI8 (OLEAUT32.373)
868 *
869 * Convert a VT_UI8 to a VT_UI1.
870 *
871 * PARAMS
872 * ullIn [I] Source
873 * pbOut [O] Destination
874 *
875 * RETURNS
876 * Success: S_OK.
877 * Failure: E_INVALIDARG, if the source value is invalid
878 * DISP_E_OVERFLOW, if the value will not fit in the destination
879 */
880 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
881 {
882 return _VarUI1FromUI8(ullIn, pbOut);
883 }
884
885
886 /* I2
887 */
888
889 /************************************************************************
890 * VarI2FromUI1 (OLEAUT32.48)
891 *
892 * Convert a VT_UI2 to a VT_I2.
893 *
894 * PARAMS
895 * bIn [I] Source
896 * psOut [O] Destination
897 *
898 * RETURNS
899 * S_OK.
900 */
901 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
902 {
903 return _VarI2FromUI1(bIn, psOut);
904 }
905
906 /************************************************************************
907 * VarI2FromI4 (OLEAUT32.49)
908 *
909 * Convert a VT_I4 to a VT_I2.
910 *
911 * PARAMS
912 * iIn [I] Source
913 * psOut [O] Destination
914 *
915 * RETURNS
916 * Success: S_OK.
917 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
918 */
919 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
920 {
921 return _VarI2FromI4(iIn, psOut);
922 }
923
924 /************************************************************************
925 * VarI2FromR4 (OLEAUT32.50)
926 *
927 * Convert a VT_R4 to a VT_I2.
928 *
929 * PARAMS
930 * fltIn [I] Source
931 * psOut [O] Destination
932 *
933 * RETURNS
934 * Success: S_OK.
935 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
936 */
937 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
938 {
939 return VarI2FromR8(fltIn, psOut);
940 }
941
942 /************************************************************************
943 * VarI2FromR8 (OLEAUT32.51)
944 *
945 * Convert a VT_R8 to a VT_I2.
946 *
947 * PARAMS
948 * dblIn [I] Source
949 * psOut [O] Destination
950 *
951 * RETURNS
952 * Success: S_OK.
953 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
954 *
955 * NOTES
956 * See VarI8FromR8() for details concerning rounding.
957 */
958 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
959 {
960 if (dblIn < (double)I2_MIN || dblIn > (double)I2_MAX)
961 return DISP_E_OVERFLOW;
962 VARIANT_DutchRound(SHORT, dblIn, *psOut);
963 return S_OK;
964 }
965
966 /************************************************************************
967 * VarI2FromCy (OLEAUT32.52)
968 *
969 * Convert a VT_CY to a VT_I2.
970 *
971 * PARAMS
972 * cyIn [I] Source
973 * psOut [O] Destination
974 *
975 * RETURNS
976 * Success: S_OK.
977 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
978 */
979 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
980 {
981 LONG i = I2_MAX + 1;
982
983 VarI4FromCy(cyIn, &i);
984 return _VarI2FromI4(i, psOut);
985 }
986
987 /************************************************************************
988 * VarI2FromDate (OLEAUT32.53)
989 *
990 * Convert a VT_DATE to a VT_I2.
991 *
992 * PARAMS
993 * dateIn [I] Source
994 * psOut [O] Destination
995 *
996 * RETURNS
997 * Success: S_OK.
998 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
999 */
1000 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
1001 {
1002 return VarI2FromR8(dateIn, psOut);
1003 }
1004
1005 /************************************************************************
1006 * VarI2FromStr (OLEAUT32.54)
1007 *
1008 * Convert a VT_BSTR to a VT_I2.
1009 *
1010 * PARAMS
1011 * strIn [I] Source
1012 * lcid [I] LCID for the conversion
1013 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1014 * psOut [O] Destination
1015 *
1016 * RETURNS
1017 * Success: S_OK.
1018 * Failure: E_INVALIDARG, if any parameter is invalid
1019 * DISP_E_OVERFLOW, if the value will not fit in the destination
1020 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1021 */
1022 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
1023 {
1024 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
1025 }
1026
1027 /************************************************************************
1028 * VarI2FromDisp (OLEAUT32.55)
1029 *
1030 * Convert a VT_DISPATCH to a VT_I2.
1031 *
1032 * PARAMS
1033 * pdispIn [I] Source
1034 * lcid [I] LCID for conversion
1035 * psOut [O] Destination
1036 *
1037 * RETURNS
1038 * Success: S_OK.
1039 * Failure: E_INVALIDARG, if pdispIn is invalid,
1040 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1041 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1042 */
1043 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
1044 {
1045 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2);
1046 }
1047
1048 /************************************************************************
1049 * VarI2FromBool (OLEAUT32.56)
1050 *
1051 * Convert a VT_BOOL to a VT_I2.
1052 *
1053 * PARAMS
1054 * boolIn [I] Source
1055 * psOut [O] Destination
1056 *
1057 * RETURNS
1058 * S_OK.
1059 */
1060 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
1061 {
1062 return _VarI2FromBool(boolIn, psOut);
1063 }
1064
1065 /************************************************************************
1066 * VarI2FromI1 (OLEAUT32.205)
1067 *
1068 * Convert a VT_I1 to a VT_I2.
1069 *
1070 * PARAMS
1071 * cIn [I] Source
1072 * psOut [O] Destination
1073 *
1074 * RETURNS
1075 * S_OK.
1076 */
1077 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
1078 {
1079 return _VarI2FromI1(cIn, psOut);
1080 }
1081
1082 /************************************************************************
1083 * VarI2FromUI2 (OLEAUT32.206)
1084 *
1085 * Convert a VT_UI2 to a VT_I2.
1086 *
1087 * PARAMS
1088 * usIn [I] Source
1089 * psOut [O] Destination
1090 *
1091 * RETURNS
1092 * Success: S_OK.
1093 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1094 */
1095 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
1096 {
1097 return _VarI2FromUI2(usIn, psOut);
1098 }
1099
1100 /************************************************************************
1101 * VarI2FromUI4 (OLEAUT32.207)
1102 *
1103 * Convert a VT_UI4 to a VT_I2.
1104 *
1105 * PARAMS
1106 * ulIn [I] Source
1107 * psOut [O] Destination
1108 *
1109 * RETURNS
1110 * Success: S_OK.
1111 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1112 */
1113 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
1114 {
1115 return _VarI2FromUI4(ulIn, psOut);
1116 }
1117
1118 /************************************************************************
1119 * VarI2FromDec (OLEAUT32.208)
1120 *
1121 * Convert a VT_DECIMAL to a VT_I2.
1122 *
1123 * PARAMS
1124 * pDecIn [I] Source
1125 * psOut [O] Destination
1126 *
1127 * RETURNS
1128 * Success: S_OK.
1129 * Failure: E_INVALIDARG, if the source value is invalid
1130 * DISP_E_OVERFLOW, if the value will not fit in the destination
1131 */
1132 HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut)
1133 {
1134 LONG64 i64;
1135 HRESULT hRet;
1136
1137 hRet = VarI8FromDec(pdecIn, &i64);
1138
1139 if (SUCCEEDED(hRet))
1140 hRet = _VarI2FromI8(i64, psOut);
1141 return hRet;
1142 }
1143
1144 /************************************************************************
1145 * VarI2FromI8 (OLEAUT32.346)
1146 *
1147 * Convert a VT_I8 to a VT_I2.
1148 *
1149 * PARAMS
1150 * llIn [I] Source
1151 * psOut [O] Destination
1152 *
1153 * RETURNS
1154 * Success: S_OK.
1155 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1156 */
1157 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
1158 {
1159 return _VarI2FromI8(llIn, psOut);
1160 }
1161
1162 /************************************************************************
1163 * VarI2FromUI8 (OLEAUT32.347)
1164 *
1165 * Convert a VT_UI8 to a VT_I2.
1166 *
1167 * PARAMS
1168 * ullIn [I] Source
1169 * psOut [O] Destination
1170 *
1171 * RETURNS
1172 * Success: S_OK.
1173 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1174 */
1175 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
1176 {
1177 return _VarI2FromUI8(ullIn, psOut);
1178 }
1179
1180 /* UI2
1181 */
1182
1183 /************************************************************************
1184 * VarUI2FromUI1 (OLEAUT32.257)
1185 *
1186 * Convert a VT_UI1 to a VT_UI2.
1187 *
1188 * PARAMS
1189 * bIn [I] Source
1190 * pusOut [O] Destination
1191 *
1192 * RETURNS
1193 * S_OK.
1194 */
1195 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
1196 {
1197 return _VarUI2FromUI1(bIn, pusOut);
1198 }
1199
1200 /************************************************************************
1201 * VarUI2FromI2 (OLEAUT32.258)
1202 *
1203 * Convert a VT_I2 to a VT_UI2.
1204 *
1205 * PARAMS
1206 * sIn [I] Source
1207 * pusOut [O] Destination
1208 *
1209 * RETURNS
1210 * Success: S_OK.
1211 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1212 */
1213 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
1214 {
1215 return _VarUI2FromI2(sIn, pusOut);
1216 }
1217
1218 /************************************************************************
1219 * VarUI2FromI4 (OLEAUT32.259)
1220 *
1221 * Convert a VT_I4 to a VT_UI2.
1222 *
1223 * PARAMS
1224 * iIn [I] Source
1225 * pusOut [O] Destination
1226 *
1227 * RETURNS
1228 * Success: S_OK.
1229 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1230 */
1231 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
1232 {
1233 return _VarUI2FromI4(iIn, pusOut);
1234 }
1235
1236 /************************************************************************
1237 * VarUI2FromR4 (OLEAUT32.260)
1238 *
1239 * Convert a VT_R4 to a VT_UI2.
1240 *
1241 * PARAMS
1242 * fltIn [I] Source
1243 * pusOut [O] Destination
1244 *
1245 * RETURNS
1246 * Success: S_OK.
1247 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1248 */
1249 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
1250 {
1251 return VarUI2FromR8(fltIn, pusOut);
1252 }
1253
1254 /************************************************************************
1255 * VarUI2FromR8 (OLEAUT32.261)
1256 *
1257 * Convert a VT_R8 to a VT_UI2.
1258 *
1259 * PARAMS
1260 * dblIn [I] Source
1261 * pusOut [O] Destination
1262 *
1263 * RETURNS
1264 * Success: S_OK.
1265 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1266 *
1267 * NOTES
1268 * See VarI8FromR8() for details concerning rounding.
1269 */
1270 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
1271 {
1272 if (dblIn < -0.5 || dblIn > (double)UI2_MAX)
1273 return DISP_E_OVERFLOW;
1274 VARIANT_DutchRound(USHORT, dblIn, *pusOut);
1275 return S_OK;
1276 }
1277
1278 /************************************************************************
1279 * VarUI2FromDate (OLEAUT32.262)
1280 *
1281 * Convert a VT_DATE to a VT_UI2.
1282 *
1283 * PARAMS
1284 * dateIn [I] Source
1285 * pusOut [O] Destination
1286 *
1287 * RETURNS
1288 * Success: S_OK.
1289 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1290 */
1291 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
1292 {
1293 return VarUI2FromR8(dateIn, pusOut);
1294 }
1295
1296 /************************************************************************
1297 * VarUI2FromCy (OLEAUT32.263)
1298 *
1299 * Convert a VT_CY to a VT_UI2.
1300 *
1301 * PARAMS
1302 * cyIn [I] Source
1303 * pusOut [O] Destination
1304 *
1305 * RETURNS
1306 * Success: S_OK.
1307 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1308 *
1309 * NOTES
1310 * Negative values >= -5000 will be converted to 0.
1311 */
1312 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
1313 {
1314 ULONG i = UI2_MAX + 1;
1315
1316 VarUI4FromCy(cyIn, &i);
1317 return _VarUI2FromUI4(i, pusOut);
1318 }
1319
1320 /************************************************************************
1321 * VarUI2FromStr (OLEAUT32.264)
1322 *
1323 * Convert a VT_BSTR to a VT_UI2.
1324 *
1325 * PARAMS
1326 * strIn [I] Source
1327 * lcid [I] LCID for the conversion
1328 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1329 * pusOut [O] Destination
1330 *
1331 * RETURNS
1332 * Success: S_OK.
1333 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1334 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1335 */
1336 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
1337 {
1338 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
1339 }
1340
1341 /************************************************************************
1342 * VarUI2FromDisp (OLEAUT32.265)
1343 *
1344 * Convert a VT_DISPATCH to a VT_UI2.
1345 *
1346 * PARAMS
1347 * pdispIn [I] Source
1348 * lcid [I] LCID for conversion
1349 * pusOut [O] Destination
1350 *
1351 * RETURNS
1352 * Success: S_OK.
1353 * Failure: E_INVALIDARG, if the source value is invalid
1354 * DISP_E_OVERFLOW, if the value will not fit in the destination
1355 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1356 */
1357 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
1358 {
1359 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2);
1360 }
1361
1362 /************************************************************************
1363 * VarUI2FromBool (OLEAUT32.266)
1364 *
1365 * Convert a VT_BOOL to a VT_UI2.
1366 *
1367 * PARAMS
1368 * boolIn [I] Source
1369 * pusOut [O] Destination
1370 *
1371 * RETURNS
1372 * S_OK.
1373 */
1374 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
1375 {
1376 return _VarUI2FromBool(boolIn, pusOut);
1377 }
1378
1379 /************************************************************************
1380 * VarUI2FromI1 (OLEAUT32.267)
1381 *
1382 * Convert a VT_I1 to a VT_UI2.
1383 *
1384 * PARAMS
1385 * cIn [I] Source
1386 * pusOut [O] Destination
1387 *
1388 * RETURNS
1389 * Success: S_OK.
1390 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1391 */
1392 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
1393 {
1394 return _VarUI2FromI1(cIn, pusOut);
1395 }
1396
1397 /************************************************************************
1398 * VarUI2FromUI4 (OLEAUT32.268)
1399 *
1400 * Convert a VT_UI4 to a VT_UI2.
1401 *
1402 * PARAMS
1403 * ulIn [I] Source
1404 * pusOut [O] Destination
1405 *
1406 * RETURNS
1407 * Success: S_OK.
1408 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1409 */
1410 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
1411 {
1412 return _VarUI2FromUI4(ulIn, pusOut);
1413 }
1414
1415 /************************************************************************
1416 * VarUI2FromDec (OLEAUT32.269)
1417 *
1418 * Convert a VT_DECIMAL to a VT_UI2.
1419 *
1420 * PARAMS
1421 * pDecIn [I] Source
1422 * pusOut [O] Destination
1423 *
1424 * RETURNS
1425 * Success: S_OK.
1426 * Failure: E_INVALIDARG, if the source value is invalid
1427 * DISP_E_OVERFLOW, if the value will not fit in the destination
1428 */
1429 HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut)
1430 {
1431 LONG64 i64;
1432 HRESULT hRet;
1433
1434 hRet = VarI8FromDec(pdecIn, &i64);
1435
1436 if (SUCCEEDED(hRet))
1437 hRet = _VarUI2FromI8(i64, pusOut);
1438 return hRet;
1439 }
1440
1441 /************************************************************************
1442 * VarUI2FromI8 (OLEAUT32.378)
1443 *
1444 * Convert a VT_I8 to a VT_UI2.
1445 *
1446 * PARAMS
1447 * llIn [I] Source
1448 * pusOut [O] Destination
1449 *
1450 * RETURNS
1451 * Success: S_OK.
1452 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1453 */
1454 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
1455 {
1456 return _VarUI2FromI8(llIn, pusOut);
1457 }
1458
1459 /************************************************************************
1460 * VarUI2FromUI8 (OLEAUT32.379)
1461 *
1462 * Convert a VT_UI8 to a VT_UI2.
1463 *
1464 * PARAMS
1465 * ullIn [I] Source
1466 * pusOut [O] Destination
1467 *
1468 * RETURNS
1469 * Success: S_OK.
1470 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1471 */
1472 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
1473 {
1474 return _VarUI2FromUI8(ullIn, pusOut);
1475 }
1476
1477 /* I4
1478 */
1479
1480 /************************************************************************
1481 * VarI4FromUI1 (OLEAUT32.58)
1482 *
1483 * Convert a VT_UI1 to a VT_I4.
1484 *
1485 * PARAMS
1486 * bIn [I] Source
1487 * piOut [O] Destination
1488 *
1489 * RETURNS
1490 * S_OK.
1491 */
1492 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
1493 {
1494 return _VarI4FromUI1(bIn, piOut);
1495 }
1496
1497 /************************************************************************
1498 * VarI4FromI2 (OLEAUT32.59)
1499 *
1500 * Convert a VT_I2 to a VT_I4.
1501 *
1502 * PARAMS
1503 * sIn [I] Source
1504 * piOut [O] Destination
1505 *
1506 * RETURNS
1507 * Success: S_OK.
1508 * Failure: E_INVALIDARG, if the source value is invalid
1509 * DISP_E_OVERFLOW, if the value will not fit in the destination
1510 */
1511 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
1512 {
1513 return _VarI4FromI2(sIn, piOut);
1514 }
1515
1516 /************************************************************************
1517 * VarI4FromR4 (OLEAUT32.60)
1518 *
1519 * Convert a VT_R4 to a VT_I4.
1520 *
1521 * PARAMS
1522 * fltIn [I] Source
1523 * piOut [O] Destination
1524 *
1525 * RETURNS
1526 * Success: S_OK.
1527 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1528 */
1529 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
1530 {
1531 return VarI4FromR8(fltIn, piOut);
1532 }
1533
1534 /************************************************************************
1535 * VarI4FromR8 (OLEAUT32.61)
1536 *
1537 * Convert a VT_R8 to a VT_I4.
1538 *
1539 * PARAMS
1540 * dblIn [I] Source
1541 * piOut [O] Destination
1542 *
1543 * RETURNS
1544 * Success: S_OK.
1545 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1546 *
1547 * NOTES
1548 * See VarI8FromR8() for details concerning rounding.
1549 */
1550 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
1551 {
1552 if (dblIn < (double)I4_MIN || dblIn > (double)I4_MAX)
1553 return DISP_E_OVERFLOW;
1554 VARIANT_DutchRound(LONG, dblIn, *piOut);
1555 return S_OK;
1556 }
1557
1558 /************************************************************************
1559 * VarI4FromCy (OLEAUT32.62)
1560 *
1561 * Convert a VT_CY to a VT_I4.
1562 *
1563 * PARAMS
1564 * cyIn [I] Source
1565 * piOut [O] Destination
1566 *
1567 * RETURNS
1568 * Success: S_OK.
1569 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1570 */
1571 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
1572 {
1573 double d = cyIn.int64 / CY_MULTIPLIER_F;
1574 return VarI4FromR8(d, piOut);
1575 }
1576
1577 /************************************************************************
1578 * VarI4FromDate (OLEAUT32.63)
1579 *
1580 * Convert a VT_DATE to a VT_I4.
1581 *
1582 * PARAMS
1583 * dateIn [I] Source
1584 * piOut [O] Destination
1585 *
1586 * RETURNS
1587 * Success: S_OK.
1588 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1589 */
1590 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
1591 {
1592 return VarI4FromR8(dateIn, piOut);
1593 }
1594
1595 /************************************************************************
1596 * VarI4FromStr (OLEAUT32.64)
1597 *
1598 * Convert a VT_BSTR to a VT_I4.
1599 *
1600 * PARAMS
1601 * strIn [I] Source
1602 * lcid [I] LCID for the conversion
1603 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1604 * piOut [O] Destination
1605 *
1606 * RETURNS
1607 * Success: S_OK.
1608 * Failure: E_INVALIDARG, if any parameter is invalid
1609 * DISP_E_OVERFLOW, if the value will not fit in the destination
1610 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1611 */
1612 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
1613 {
1614 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
1615 }
1616
1617 /************************************************************************
1618 * VarI4FromDisp (OLEAUT32.65)
1619 *
1620 * Convert a VT_DISPATCH to a VT_I4.
1621 *
1622 * PARAMS
1623 * pdispIn [I] Source
1624 * lcid [I] LCID for conversion
1625 * piOut [O] Destination
1626 *
1627 * RETURNS
1628 * Success: S_OK.
1629 * Failure: E_INVALIDARG, if the source value is invalid
1630 * DISP_E_OVERFLOW, if the value will not fit in the destination
1631 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1632 */
1633 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
1634 {
1635 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4);
1636 }
1637
1638 /************************************************************************
1639 * VarI4FromBool (OLEAUT32.66)
1640 *
1641 * Convert a VT_BOOL to a VT_I4.
1642 *
1643 * PARAMS
1644 * boolIn [I] Source
1645 * piOut [O] Destination
1646 *
1647 * RETURNS
1648 * S_OK.
1649 */
1650 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
1651 {
1652 return _VarI4FromBool(boolIn, piOut);
1653 }
1654
1655 /************************************************************************
1656 * VarI4FromI1 (OLEAUT32.209)
1657 *
1658 * Convert a VT_I4 to a VT_I4.
1659 *
1660 * PARAMS
1661 * cIn [I] Source
1662 * piOut [O] Destination
1663 *
1664 * RETURNS
1665 * S_OK.
1666 */
1667 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
1668 {
1669 return _VarI4FromI1(cIn, piOut);
1670 }
1671
1672 /************************************************************************
1673 * VarI4FromUI2 (OLEAUT32.210)
1674 *
1675 * Convert a VT_UI2 to a VT_I4.
1676 *
1677 * PARAMS
1678 * usIn [I] Source
1679 * piOut [O] Destination
1680 *
1681 * RETURNS
1682 * S_OK.
1683 */
1684 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
1685 {
1686 return _VarI4FromUI2(usIn, piOut);
1687 }
1688
1689 /************************************************************************
1690 * VarI4FromUI4 (OLEAUT32.211)
1691 *
1692 * Convert a VT_UI4 to a VT_I4.
1693 *
1694 * PARAMS
1695 * ulIn [I] Source
1696 * piOut [O] Destination
1697 *
1698 * RETURNS
1699 * Success: S_OK.
1700 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1701 */
1702 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
1703 {
1704 return _VarI4FromUI4(ulIn, piOut);
1705 }
1706
1707 /************************************************************************
1708 * VarI4FromDec (OLEAUT32.212)
1709 *
1710 * Convert a VT_DECIMAL to a VT_I4.
1711 *
1712 * PARAMS
1713 * pDecIn [I] Source
1714 * piOut [O] Destination
1715 *
1716 * RETURNS
1717 * Success: S_OK.
1718 * Failure: E_INVALIDARG, if pdecIn is invalid
1719 * DISP_E_OVERFLOW, if the value will not fit in the destination
1720 */
1721 HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut)
1722 {
1723 LONG64 i64;
1724 HRESULT hRet;
1725
1726 hRet = VarI8FromDec(pdecIn, &i64);
1727
1728 if (SUCCEEDED(hRet))
1729 hRet = _VarI4FromI8(i64, piOut);
1730 return hRet;
1731 }
1732
1733 /************************************************************************
1734 * VarI4FromI8 (OLEAUT32.348)
1735 *
1736 * Convert a VT_I8 to a VT_I4.
1737 *
1738 * PARAMS
1739 * llIn [I] Source
1740 * piOut [O] Destination
1741 *
1742 * RETURNS
1743 * Success: S_OK.
1744 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1745 */
1746 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
1747 {
1748 return _VarI4FromI8(llIn, piOut);
1749 }
1750
1751 /************************************************************************
1752 * VarI4FromUI8 (OLEAUT32.349)
1753 *
1754 * Convert a VT_UI8 to a VT_I4.
1755 *
1756 * PARAMS
1757 * ullIn [I] Source
1758 * piOut [O] Destination
1759 *
1760 * RETURNS
1761 * Success: S_OK.
1762 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1763 */
1764 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
1765 {
1766 return _VarI4FromUI8(ullIn, piOut);
1767 }
1768
1769 /* UI4
1770 */
1771
1772 /************************************************************************
1773 * VarUI4FromUI1 (OLEAUT32.270)
1774 *
1775 * Convert a VT_UI1 to a VT_UI4.
1776 *
1777 * PARAMS
1778 * bIn [I] Source
1779 * pulOut [O] Destination
1780 *
1781 * RETURNS
1782 * S_OK.
1783 */
1784 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
1785 {
1786 return _VarUI4FromUI1(bIn, pulOut);
1787 }
1788
1789 /************************************************************************
1790 * VarUI4FromI2 (OLEAUT32.271)
1791 *
1792 * Convert a VT_I2 to a VT_UI4.
1793 *
1794 * PARAMS
1795 * sIn [I] Source
1796 * pulOut [O] Destination
1797 *
1798 * RETURNS
1799 * Success: S_OK.
1800 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1801 */
1802 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
1803 {
1804 return _VarUI4FromI2(sIn, pulOut);
1805 }
1806
1807 /************************************************************************
1808 * VarUI4FromI4 (OLEAUT32.272)
1809 *
1810 * Convert a VT_I4 to a VT_UI4.
1811 *
1812 * PARAMS
1813 * iIn [I] Source
1814 * pulOut [O] Destination
1815 *
1816 * RETURNS
1817 * Success: S_OK.
1818 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1819 */
1820 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
1821 {
1822 return _VarUI4FromI4(iIn, pulOut);
1823 }
1824
1825 /************************************************************************
1826 * VarUI4FromR4 (OLEAUT32.273)
1827 *
1828 * Convert a VT_R4 to a VT_UI4.
1829 *
1830 * PARAMS
1831 * fltIn [I] Source
1832 * pulOut [O] Destination
1833 *
1834 * RETURNS
1835 * Success: S_OK.
1836 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1837 */
1838 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
1839 {
1840 return VarUI4FromR8(fltIn, pulOut);
1841 }
1842
1843 /************************************************************************
1844 * VarUI4FromR8 (OLEAUT32.274)
1845 *
1846 * Convert a VT_R8 to a VT_UI4.
1847 *
1848 * PARAMS
1849 * dblIn [I] Source
1850 * pulOut [O] Destination
1851 *
1852 * RETURNS
1853 * Success: S_OK.
1854 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1855 *
1856 * NOTES
1857 * See VarI8FromR8() for details concerning rounding.
1858 */
1859 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
1860 {
1861 if (dblIn < -0.5 || dblIn > (double)UI4_MAX)
1862 return DISP_E_OVERFLOW;
1863 VARIANT_DutchRound(ULONG, dblIn, *pulOut);
1864 return S_OK;
1865 }
1866
1867 /************************************************************************
1868 * VarUI4FromDate (OLEAUT32.275)
1869 *
1870 * Convert a VT_DATE to a VT_UI4.
1871 *
1872 * PARAMS
1873 * dateIn [I] Source
1874 * pulOut [O] Destination
1875 *
1876 * RETURNS
1877 * Success: S_OK.
1878 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1879 */
1880 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
1881 {
1882 return VarUI4FromR8(dateIn, pulOut);
1883 }
1884
1885 /************************************************************************
1886 * VarUI4FromCy (OLEAUT32.276)
1887 *
1888 * Convert a VT_CY to a VT_UI4.
1889 *
1890 * PARAMS
1891 * cyIn [I] Source
1892 * pulOut [O] Destination
1893 *
1894 * RETURNS
1895 * Success: S_OK.
1896 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1897 */
1898 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
1899 {
1900 double d = cyIn.int64 / CY_MULTIPLIER_F;
1901 return VarUI4FromR8(d, pulOut);
1902 }
1903
1904 /************************************************************************
1905 * VarUI4FromStr (OLEAUT32.277)
1906 *
1907 * Convert a VT_BSTR to a VT_UI4.
1908 *
1909 * PARAMS
1910 * strIn [I] Source
1911 * lcid [I] LCID for the conversion
1912 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1913 * pulOut [O] Destination
1914 *
1915 * RETURNS
1916 * Success: S_OK.
1917 * Failure: E_INVALIDARG, if any parameter is invalid
1918 * DISP_E_OVERFLOW, if the value will not fit in the destination
1919 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1920 */
1921 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
1922 {
1923 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
1924 }
1925
1926 /************************************************************************
1927 * VarUI4FromDisp (OLEAUT32.278)
1928 *
1929 * Convert a VT_DISPATCH to a VT_UI4.
1930 *
1931 * PARAMS
1932 * pdispIn [I] Source
1933 * lcid [I] LCID for conversion
1934 * pulOut [O] Destination
1935 *
1936 * RETURNS
1937 * Success: S_OK.
1938 * Failure: E_INVALIDARG, if the source value is invalid
1939 * DISP_E_OVERFLOW, if the value will not fit in the destination
1940 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1941 */
1942 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
1943 {
1944 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4);
1945 }
1946
1947 /************************************************************************
1948 * VarUI4FromBool (OLEAUT32.279)
1949 *
1950 * Convert a VT_BOOL to a VT_UI4.
1951 *
1952 * PARAMS
1953 * boolIn [I] Source
1954 * pulOut [O] Destination
1955 *
1956 * RETURNS
1957 * S_OK.
1958 */
1959 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
1960 {
1961 return _VarUI4FromBool(boolIn, pulOut);
1962 }
1963
1964 /************************************************************************
1965 * VarUI4FromI1 (OLEAUT32.280)
1966 *
1967 * Convert a VT_I1 to a VT_UI4.
1968 *
1969 * PARAMS
1970 * cIn [I] Source
1971 * pulOut [O] Destination
1972 *
1973 * RETURNS
1974 * Success: S_OK.
1975 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1976 */
1977 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
1978 {
1979 return _VarUI4FromI1(cIn, pulOut);
1980 }
1981
1982 /************************************************************************
1983 * VarUI4FromUI2 (OLEAUT32.281)
1984 *
1985 * Convert a VT_UI2 to a VT_UI4.
1986 *
1987 * PARAMS
1988 * usIn [I] Source
1989 * pulOut [O] Destination
1990 *
1991 * RETURNS
1992 * S_OK.
1993 */
1994 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
1995 {
1996 return _VarUI4FromUI2(usIn, pulOut);
1997 }
1998
1999 /************************************************************************
2000 * VarUI4FromDec (OLEAUT32.282)
2001 *
2002 * Convert a VT_DECIMAL to a VT_UI4.
2003 *
2004 * PARAMS
2005 * pDecIn [I] Source
2006 * pulOut [O] Destination
2007 *
2008 * RETURNS
2009 * Success: S_OK.
2010 * Failure: E_INVALIDARG, if pdecIn is invalid
2011 * DISP_E_OVERFLOW, if the value will not fit in the destination
2012 */
2013 HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut)
2014 {
2015 LONG64 i64;
2016 HRESULT hRet;
2017
2018 hRet = VarI8FromDec(pdecIn, &i64);
2019
2020 if (SUCCEEDED(hRet))
2021 hRet = _VarUI4FromI8(i64, pulOut);
2022 return hRet;
2023 }
2024
2025 /************************************************************************
2026 * VarUI4FromI8 (OLEAUT32.425)
2027 *
2028 * Convert a VT_I8 to a VT_UI4.
2029 *
2030 * PARAMS
2031 * llIn [I] Source
2032 * pulOut [O] Destination
2033 *
2034 * RETURNS
2035 * Success: S_OK.
2036 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2037 */
2038 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
2039 {
2040 return _VarUI4FromI8(llIn, pulOut);
2041 }
2042
2043 /************************************************************************
2044 * VarUI4FromUI8 (OLEAUT32.426)
2045 *
2046 * Convert a VT_UI8 to a VT_UI4.
2047 *
2048 * PARAMS
2049 * ullIn [I] Source
2050 * pulOut [O] Destination
2051 *
2052 * RETURNS
2053 * Success: S_OK.
2054 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2055 */
2056 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
2057 {
2058 return _VarUI4FromUI8(ullIn, pulOut);
2059 }
2060
2061 /* I8
2062 */
2063
2064 /************************************************************************
2065 * VarI8FromUI1 (OLEAUT32.333)
2066 *
2067 * Convert a VT_UI1 to a VT_I8.
2068 *
2069 * PARAMS
2070 * bIn [I] Source
2071 * pi64Out [O] Destination
2072 *
2073 * RETURNS
2074 * S_OK.
2075 */
2076 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
2077 {
2078 return _VarI8FromUI1(bIn, pi64Out);
2079 }
2080
2081
2082 /************************************************************************
2083 * VarI8FromI2 (OLEAUT32.334)
2084 *
2085 * Convert a VT_I2 to a VT_I8.
2086 *
2087 * PARAMS
2088 * sIn [I] Source
2089 * pi64Out [O] Destination
2090 *
2091 * RETURNS
2092 * S_OK.
2093 */
2094 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
2095 {
2096 return _VarI8FromI2(sIn, pi64Out);
2097 }
2098
2099 /************************************************************************
2100 * VarI8FromR4 (OLEAUT32.335)
2101 *
2102 * Convert a VT_R4 to a VT_I8.
2103 *
2104 * PARAMS
2105 * fltIn [I] Source
2106 * pi64Out [O] Destination
2107 *
2108 * RETURNS
2109 * Success: S_OK.
2110 * Failure: E_INVALIDARG, if the source value is invalid
2111 * DISP_E_OVERFLOW, if the value will not fit in the destination
2112 */
2113 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
2114 {
2115 return VarI8FromR8(fltIn, pi64Out);
2116 }
2117
2118 /************************************************************************
2119 * VarI8FromR8 (OLEAUT32.336)
2120 *
2121 * Convert a VT_R8 to a VT_I8.
2122 *
2123 * PARAMS
2124 * dblIn [I] Source
2125 * pi64Out [O] Destination
2126 *
2127 * RETURNS
2128 * Success: S_OK.
2129 * Failure: E_INVALIDARG, if the source value is invalid
2130 * DISP_E_OVERFLOW, if the value will not fit in the destination
2131 *
2132 * NOTES
2133 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2134 * very high or low values will not be accurately converted.
2135 *
2136 * Numbers are rounded using Dutch rounding, as follows:
2137 *
2138 *| Fractional Part Sign Direction Example
2139 *| --------------- ---- --------- -------
2140 *| < 0.5 + Down 0.4 -> 0.0
2141 *| < 0.5 - Up -0.4 -> 0.0
2142 *| > 0.5 + Up 0.6 -> 1.0
2143 *| < 0.5 - Up -0.6 -> -1.0
2144 *| = 0.5 + Up/Down Down if even, Up if odd
2145 *| = 0.5 - Up/Down Up if even, Down if odd
2146 *
2147 * This system is often used in supermarkets.
2148 */
2149 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
2150 {
2151 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
2152 return DISP_E_OVERFLOW;
2153 VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
2154 return S_OK;
2155 }
2156
2157 /************************************************************************
2158 * VarI8FromCy (OLEAUT32.337)
2159 *
2160 * Convert a VT_CY to a VT_I8.
2161 *
2162 * PARAMS
2163 * cyIn [I] Source
2164 * pi64Out [O] Destination
2165 *
2166 * RETURNS
2167 * S_OK.
2168 *
2169 * NOTES
2170 * All negative numbers are rounded down by 1, including those that are
2171 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2172 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2173 * for details.
2174 */
2175 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
2176 {
2177 *pi64Out = cyIn.int64 / CY_MULTIPLIER;
2178
2179 if (cyIn.int64 < 0)
2180 (*pi64Out)--; /* Mimic Win32 bug */
2181 else
2182 {
2183 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2184
2185 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1)))
2186 (*pi64Out)++;
2187 }
2188 return S_OK;
2189 }
2190
2191 /************************************************************************
2192 * VarI8FromDate (OLEAUT32.338)
2193 *
2194 * Convert a VT_DATE to a VT_I8.
2195 *
2196 * PARAMS
2197 * dateIn [I] Source
2198 * pi64Out [O] Destination
2199 *
2200 * RETURNS
2201 * Success: S_OK.
2202 * Failure: E_INVALIDARG, if the source value is invalid
2203 * DISP_E_OVERFLOW, if the value will not fit in the destination
2204 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2205 */
2206 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
2207 {
2208 return VarI8FromR8(dateIn, pi64Out);
2209 }
2210
2211 /************************************************************************
2212 * VarI8FromStr (OLEAUT32.339)
2213 *
2214 * Convert a VT_BSTR to a VT_I8.
2215 *
2216 * PARAMS
2217 * strIn [I] Source
2218 * lcid [I] LCID for the conversion
2219 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2220 * pi64Out [O] Destination
2221 *
2222 * RETURNS
2223 * Success: S_OK.
2224 * Failure: E_INVALIDARG, if the source value is invalid
2225 * DISP_E_OVERFLOW, if the value will not fit in the destination
2226 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2227 */
2228 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
2229 {
2230 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
2231 }
2232
2233 /************************************************************************
2234 * VarI8FromDisp (OLEAUT32.340)
2235 *
2236 * Convert a VT_DISPATCH to a VT_I8.
2237 *
2238 * PARAMS
2239 * pdispIn [I] Source
2240 * lcid [I] LCID for conversion
2241 * pi64Out [O] Destination
2242 *
2243 * RETURNS
2244 * Success: S_OK.
2245 * Failure: E_INVALIDARG, if the source value is invalid
2246 * DISP_E_OVERFLOW, if the value will not fit in the destination
2247 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2248 */
2249 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
2250 {
2251 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8);
2252 }
2253
2254 /************************************************************************
2255 * VarI8FromBool (OLEAUT32.341)
2256 *
2257 * Convert a VT_BOOL to a VT_I8.
2258 *
2259 * PARAMS
2260 * boolIn [I] Source
2261 * pi64Out [O] Destination
2262 *
2263 * RETURNS
2264 * S_OK.
2265 */
2266 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
2267 {
2268 return VarI8FromI2(boolIn, pi64Out);
2269 }
2270
2271 /************************************************************************
2272 * VarI8FromI1 (OLEAUT32.342)
2273 *
2274 * Convert a VT_I1 to a VT_I8.
2275 *
2276 * PARAMS
2277 * cIn [I] Source
2278 * pi64Out [O] Destination
2279 *
2280 * RETURNS
2281 * S_OK.
2282 */
2283 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
2284 {
2285 return _VarI8FromI1(cIn, pi64Out);
2286 }
2287
2288 /************************************************************************
2289 * VarI8FromUI2 (OLEAUT32.343)
2290 *
2291 * Convert a VT_UI2 to a VT_I8.
2292 *
2293 * PARAMS
2294 * usIn [I] Source
2295 * pi64Out [O] Destination
2296 *
2297 * RETURNS
2298 * S_OK.
2299 */
2300 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
2301 {
2302 return _VarI8FromUI2(usIn, pi64Out);
2303 }
2304
2305 /************************************************************************
2306 * VarI8FromUI4 (OLEAUT32.344)
2307 *
2308 * Convert a VT_UI4 to a VT_I8.
2309 *
2310 * PARAMS
2311 * ulIn [I] Source
2312 * pi64Out [O] Destination
2313 *
2314 * RETURNS
2315 * S_OK.
2316 */
2317 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
2318 {
2319 return _VarI8FromUI4(ulIn, pi64Out);
2320 }
2321
2322 /************************************************************************
2323 * VarI8FromDec (OLEAUT32.345)
2324 *
2325 * Convert a VT_DECIMAL to a VT_I8.
2326 *
2327 * PARAMS
2328 * pDecIn [I] Source
2329 * pi64Out [O] Destination
2330 *
2331 * RETURNS
2332 * Success: S_OK.
2333 * Failure: E_INVALIDARG, if the source value is invalid
2334 * DISP_E_OVERFLOW, if the value will not fit in the destination
2335 */
2336 HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out)
2337 {
2338 if (!DEC_SCALE(pdecIn))
2339 {
2340 /* This decimal is just a 96 bit integer */
2341 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2342 return E_INVALIDARG;
2343
2344 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000)
2345 return DISP_E_OVERFLOW;
2346
2347 if (DEC_SIGN(pdecIn))
2348 *pi64Out = -DEC_LO64(pdecIn);
2349 else
2350 *pi64Out = DEC_LO64(pdecIn);
2351 return S_OK;
2352 }
2353 else
2354 {
2355 /* Decimal contains a floating point number */
2356 HRESULT hRet;
2357 double dbl;
2358
2359 hRet = VarR8FromDec(pdecIn, &dbl);
2360 if (SUCCEEDED(hRet))
2361 hRet = VarI8FromR8(dbl, pi64Out);
2362 return hRet;
2363 }
2364 }
2365
2366 /************************************************************************
2367 * VarI8FromUI8 (OLEAUT32.427)
2368 *
2369 * Convert a VT_UI8 to a VT_I8.
2370 *
2371 * PARAMS
2372 * ullIn [I] Source
2373 * pi64Out [O] Destination
2374 *
2375 * RETURNS
2376 * Success: S_OK.
2377 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2378 */
2379 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
2380 {
2381 return _VarI8FromUI8(ullIn, pi64Out);
2382 }
2383
2384 /* UI8
2385 */
2386
2387 /************************************************************************
2388 * VarUI8FromI8 (OLEAUT32.428)
2389 *
2390 * Convert a VT_I8 to a VT_UI8.
2391 *
2392 * PARAMS
2393 * ulIn [I] Source
2394 * pui64Out [O] Destination
2395 *
2396 * RETURNS
2397 * Success: S_OK.
2398 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2399 */
2400 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
2401 {
2402 return _VarUI8FromI8(llIn, pui64Out);
2403 }
2404
2405 /************************************************************************
2406 * VarUI8FromUI1 (OLEAUT32.429)
2407 *
2408 * Convert a VT_UI1 to a VT_UI8.
2409 *
2410 * PARAMS
2411 * bIn [I] Source
2412 * pui64Out [O] Destination
2413 *
2414 * RETURNS
2415 * S_OK.
2416 */
2417 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
2418 {
2419 return _VarUI8FromUI1(bIn, pui64Out);
2420 }
2421
2422 /************************************************************************
2423 * VarUI8FromI2 (OLEAUT32.430)
2424 *
2425 * Convert a VT_I2 to a VT_UI8.
2426 *
2427 * PARAMS
2428 * sIn [I] Source
2429 * pui64Out [O] Destination
2430 *
2431 * RETURNS
2432 * S_OK.
2433 */
2434 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
2435 {
2436 return _VarUI8FromI2(sIn, pui64Out);
2437 }
2438
2439 /************************************************************************
2440 * VarUI8FromR4 (OLEAUT32.431)
2441 *
2442 * Convert a VT_R4 to a VT_UI8.
2443 *
2444 * PARAMS
2445 * fltIn [I] Source
2446 * pui64Out [O] Destination
2447 *
2448 * RETURNS
2449 * Success: S_OK.
2450 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2451 */
2452 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
2453 {
2454 return VarUI8FromR8(fltIn, pui64Out);
2455 }
2456
2457 /************************************************************************
2458 * VarUI8FromR8 (OLEAUT32.432)
2459 *
2460 * Convert a VT_R8 to a VT_UI8.
2461 *
2462 * PARAMS
2463 * dblIn [I] Source
2464 * pui64Out [O] Destination
2465 *
2466 * RETURNS
2467 * Success: S_OK.
2468 * Failure: E_INVALIDARG, if the source value is invalid
2469 * DISP_E_OVERFLOW, if the value will not fit in the destination
2470 *
2471 * NOTES
2472 * See VarI8FromR8() for details concerning rounding.
2473 */
2474 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
2475 {
2476 if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
2477 return DISP_E_OVERFLOW;
2478 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
2479 return S_OK;
2480 }
2481
2482 /************************************************************************
2483 * VarUI8FromCy (OLEAUT32.433)
2484 *
2485 * Convert a VT_CY to a VT_UI8.
2486 *
2487 * PARAMS
2488 * cyIn [I] Source
2489 * pui64Out [O] Destination
2490 *
2491 * RETURNS
2492 * Success: S_OK.
2493 * Failure: E_INVALIDARG, if the source value is invalid
2494 * DISP_E_OVERFLOW, if the value will not fit in the destination
2495 *
2496 * NOTES
2497 * Negative values >= -5000 will be converted to 0.
2498 */
2499 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
2500 {
2501 if (cyIn.int64 < 0)
2502 {
2503 if (cyIn.int64 < -CY_HALF)
2504 return DISP_E_OVERFLOW;
2505 *pui64Out = 0;
2506 }
2507 else
2508 {
2509 *pui64Out = cyIn.int64 / CY_MULTIPLIER;
2510
2511 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2512
2513 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1)))
2514 (*pui64Out)++;
2515 }
2516 return S_OK;
2517 }
2518
2519 /************************************************************************
2520 * VarUI8FromDate (OLEAUT32.434)
2521 *
2522 * Convert a VT_DATE to a VT_UI8.
2523 *
2524 * PARAMS
2525 * dateIn [I] Source
2526 * pui64Out [O] Destination
2527 *
2528 * RETURNS
2529 * Success: S_OK.
2530 * Failure: E_INVALIDARG, if the source value is invalid
2531 * DISP_E_OVERFLOW, if the value will not fit in the destination
2532 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2533 */
2534 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
2535 {
2536 return VarUI8FromR8(dateIn, pui64Out);
2537 }
2538
2539 /************************************************************************
2540 * VarUI8FromStr (OLEAUT32.435)
2541 *
2542 * Convert a VT_BSTR to a VT_UI8.
2543 *
2544 * PARAMS
2545 * strIn [I] Source
2546 * lcid [I] LCID for the conversion
2547 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2548 * pui64Out [O] Destination
2549 *
2550 * RETURNS
2551 * Success: S_OK.
2552 * Failure: E_INVALIDARG, if the source value is invalid
2553 * DISP_E_OVERFLOW, if the value will not fit in the destination
2554 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2555 */
2556 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
2557 {
2558 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
2559 }
2560
2561 /************************************************************************
2562 * VarUI8FromDisp (OLEAUT32.436)
2563 *
2564 * Convert a VT_DISPATCH to a VT_UI8.
2565 *
2566 * PARAMS
2567 * pdispIn [I] Source
2568 * lcid [I] LCID for conversion
2569 * pui64Out [O] Destination
2570 *
2571 * RETURNS
2572 * Success: S_OK.
2573 * Failure: E_INVALIDARG, if the source value is invalid
2574 * DISP_E_OVERFLOW, if the value will not fit in the destination
2575 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2576 */
2577 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
2578 {
2579 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8);
2580 }
2581
2582 /************************************************************************
2583 * VarUI8FromBool (OLEAUT32.437)
2584 *
2585 * Convert a VT_BOOL to a VT_UI8.
2586 *
2587 * PARAMS
2588 * boolIn [I] Source
2589 * pui64Out [O] Destination
2590 *
2591 * RETURNS
2592 * Success: S_OK.
2593 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2594 */
2595 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
2596 {
2597 return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
2598 }
2599 /************************************************************************
2600 * VarUI8FromI1 (OLEAUT32.438)
2601 *
2602 * Convert a VT_I1 to a VT_UI8.
2603 *
2604 * PARAMS
2605 * cIn [I] Source
2606 * pui64Out [O] Destination
2607 *
2608 * RETURNS
2609 * Success: S_OK.
2610 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2611 */
2612 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
2613 {
2614 return _VarUI8FromI1(cIn, pui64Out);
2615 }
2616
2617 /************************************************************************
2618 * VarUI8FromUI2 (OLEAUT32.439)
2619 *
2620 * Convert a VT_UI2 to a VT_UI8.
2621 *
2622 * PARAMS
2623 * usIn [I] Source
2624 * pui64Out [O] Destination
2625 *
2626 * RETURNS
2627 * S_OK.
2628 */
2629 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
2630 {
2631 return _VarUI8FromUI2(usIn, pui64Out);
2632 }
2633
2634 /************************************************************************
2635 * VarUI8FromUI4 (OLEAUT32.440)
2636 *
2637 * Convert a VT_UI4 to a VT_UI8.
2638 *
2639 * PARAMS
2640 * ulIn [I] Source
2641 * pui64Out [O] Destination
2642 *
2643 * RETURNS
2644 * S_OK.
2645 */
2646 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
2647 {
2648 return _VarUI8FromUI4(ulIn, pui64Out);
2649 }
2650
2651 /************************************************************************
2652 * VarUI8FromDec (OLEAUT32.441)
2653 *
2654 * Convert a VT_DECIMAL to a VT_UI8.
2655 *
2656 * PARAMS
2657 * pDecIn [I] Source
2658 * pui64Out [O] Destination
2659 *
2660 * RETURNS
2661 * Success: S_OK.
2662 * Failure: E_INVALIDARG, if the source value is invalid
2663 * DISP_E_OVERFLOW, if the value will not fit in the destination
2664 *
2665 * NOTES
2666 * Under native Win32, if the source value has a scale of 0, its sign is
2667 * ignored, i.e. this function takes the absolute value rather than fail
2668 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2669 * (use VarAbs() on pDecIn first if you really want this behaviour).
2670 */
2671 HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out)
2672 {
2673 if (!DEC_SCALE(pdecIn))
2674 {
2675 /* This decimal is just a 96 bit integer */
2676 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2677 return E_INVALIDARG;
2678
2679 if (DEC_HI32(pdecIn))
2680 return DISP_E_OVERFLOW;
2681
2682 if (DEC_SIGN(pdecIn))
2683 {
2684 WARN("Sign would be ignored under Win32!\n");
2685 return DISP_E_OVERFLOW;
2686 }
2687
2688 *pui64Out = DEC_LO64(pdecIn);
2689 return S_OK;
2690 }
2691 else
2692 {
2693 /* Decimal contains a floating point number */
2694 HRESULT hRet;
2695 double dbl;
2696
2697 hRet = VarR8FromDec(pdecIn, &dbl);
2698 if (SUCCEEDED(hRet))
2699 hRet = VarUI8FromR8(dbl, pui64Out);
2700 return hRet;
2701 }
2702 }
2703
2704 /* R4
2705 */
2706
2707 /************************************************************************
2708 * VarR4FromUI1 (OLEAUT32.68)
2709 *
2710 * Convert a VT_UI1 to a VT_R4.
2711 *
2712 * PARAMS
2713 * bIn [I] Source
2714 * pFltOut [O] Destination
2715 *
2716 * RETURNS
2717 * S_OK.
2718 */
2719 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
2720 {
2721 return _VarR4FromUI1(bIn, pFltOut);
2722 }
2723
2724 /************************************************************************
2725 * VarR4FromI2 (OLEAUT32.69)
2726 *
2727 * Convert a VT_I2 to a VT_R4.
2728 *
2729 * PARAMS
2730 * sIn [I] Source
2731 * pFltOut [O] Destination
2732 *
2733 * RETURNS
2734 * S_OK.
2735 */
2736 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
2737 {
2738 return _VarR4FromI2(sIn, pFltOut);
2739 }
2740
2741 /************************************************************************
2742 * VarR4FromI4 (OLEAUT32.70)
2743 *
2744 * Convert a VT_I4 to a VT_R4.
2745 *
2746 * PARAMS
2747 * sIn [I] Source
2748 * pFltOut [O] Destination
2749 *
2750 * RETURNS
2751 * S_OK.
2752 */
2753 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
2754 {
2755 return _VarR4FromI4(lIn, pFltOut);
2756 }
2757
2758 /************************************************************************
2759 * VarR4FromR8 (OLEAUT32.71)
2760 *
2761 * Convert a VT_R8 to a VT_R4.
2762 *
2763 * PARAMS
2764 * dblIn [I] Source
2765 * pFltOut [O] Destination
2766 *
2767 * RETURNS
2768 * Success: S_OK.
2769 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2770 */
2771 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
2772 {
2773 double d = dblIn < 0.0 ? -dblIn : dblIn;
2774 if (d > R4_MAX) return DISP_E_OVERFLOW;
2775 *pFltOut = dblIn;
2776 return S_OK;
2777 }
2778
2779 /************************************************************************
2780 * VarR4FromCy (OLEAUT32.72)
2781 *
2782 * Convert a VT_CY to a VT_R4.
2783 *
2784 * PARAMS
2785 * cyIn [I] Source
2786 * pFltOut [O] Destination
2787 *
2788 * RETURNS
2789 * S_OK.
2790 */
2791 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
2792 {
2793 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
2794 return S_OK;
2795 }
2796
2797 /************************************************************************
2798 * VarR4FromDate (OLEAUT32.73)
2799 *
2800 * Convert a VT_DATE to a VT_R4.
2801 *
2802 * PARAMS
2803 * dateIn [I] Source
2804 * pFltOut [O] Destination
2805 *
2806 * RETURNS
2807 * Success: S_OK.
2808 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2809 */
2810 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
2811 {
2812 return VarR4FromR8(dateIn, pFltOut);
2813 }
2814
2815 /************************************************************************
2816 * VarR4FromStr (OLEAUT32.74)
2817 *
2818 * Convert a VT_BSTR to a VT_R4.
2819 *
2820 * PARAMS
2821 * strIn [I] Source
2822 * lcid [I] LCID for the conversion
2823 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2824 * pFltOut [O] Destination
2825 *
2826 * RETURNS
2827 * Success: S_OK.
2828 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2829 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2830 */
2831 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
2832 {
2833 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
2834 }
2835
2836 /************************************************************************
2837 * VarR4FromDisp (OLEAUT32.75)
2838 *
2839 * Convert a VT_DISPATCH to a VT_R4.
2840 *
2841 * PARAMS
2842 * pdispIn [I] Source
2843 * lcid [I] LCID for conversion
2844 * pFltOut [O] Destination
2845 *
2846 * RETURNS
2847 * Success: S_OK.
2848 * Failure: E_INVALIDARG, if the source value is invalid
2849 * DISP_E_OVERFLOW, if the value will not fit in the destination
2850 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2851 */
2852 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
2853 {
2854 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4);
2855 }
2856
2857 /************************************************************************
2858 * VarR4FromBool (OLEAUT32.76)
2859 *
2860 * Convert a VT_BOOL to a VT_R4.
2861 *
2862 * PARAMS
2863 * boolIn [I] Source
2864 * pFltOut [O] Destination
2865 *
2866 * RETURNS
2867 * S_OK.
2868 */
2869 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2870 {
2871 return VarR4FromI2(boolIn, pFltOut);
2872 }
2873
2874 /************************************************************************
2875 * VarR4FromI1 (OLEAUT32.213)
2876 *
2877 * Convert a VT_I1 to a VT_R4.
2878 *
2879 * PARAMS
2880 * cIn [I] Source
2881 * pFltOut [O] Destination
2882 *
2883 * RETURNS
2884 * Success: S_OK.
2885 * Failure: E_INVALIDARG, if the source value is invalid
2886 * DISP_E_OVERFLOW, if the value will not fit in the destination
2887 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2888 */
2889 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2890 {
2891 return _VarR4FromI1(cIn, pFltOut);
2892 }
2893
2894 /************************************************************************
2895 * VarR4FromUI2 (OLEAUT32.214)
2896 *
2897 * Convert a VT_UI2 to a VT_R4.
2898 *
2899 * PARAMS
2900 * usIn [I] Source
2901 * pFltOut [O] Destination
2902 *
2903 * RETURNS
2904 * Success: S_OK.
2905 * Failure: E_INVALIDARG, if the source value is invalid
2906 * DISP_E_OVERFLOW, if the value will not fit in the destination
2907 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2908 */
2909 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2910 {
2911 return _VarR4FromUI2(usIn, pFltOut);
2912 }
2913
2914 /************************************************************************
2915 * VarR4FromUI4 (OLEAUT32.215)
2916 *
2917 * Convert a VT_UI4 to a VT_R4.
2918 *
2919 * PARAMS
2920 * ulIn [I] Source
2921 * pFltOut [O] Destination
2922 *
2923 * RETURNS
2924 * Success: S_OK.
2925 * Failure: E_INVALIDARG, if the source value is invalid
2926 * DISP_E_OVERFLOW, if the value will not fit in the destination
2927 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2928 */
2929 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2930 {
2931 return _VarR4FromUI4(ulIn, pFltOut);
2932 }
2933
2934 /************************************************************************
2935 * VarR4FromDec (OLEAUT32.216)
2936 *
2937 * Convert a VT_DECIMAL to a VT_R4.
2938 *
2939 * PARAMS
2940 * pDecIn [I] Source
2941 * pFltOut [O] Destination
2942 *
2943 * RETURNS
2944 * Success: S_OK.
2945 * Failure: E_INVALIDARG, if the source value is invalid.
2946 */
2947 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
2948 {
2949 BYTE scale = DEC_SCALE(pDecIn);
2950 int divisor = 1;
2951 double highPart;
2952
2953 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2954 return E_INVALIDARG;
2955
2956 while (scale--)
2957 divisor *= 10;
2958
2959 if (DEC_SIGN(pDecIn))
2960 divisor = -divisor;
2961
2962 if (DEC_HI32(pDecIn))
2963 {
2964 highPart = (double)DEC_HI32(pDecIn) / (double)divisor;
2965 highPart *= 4294967296.0F;
2966 highPart *= 4294967296.0F;
2967 }
2968 else
2969 highPart = 0.0;
2970
2971 *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart;
2972 return S_OK;
2973 }
2974
2975 /************************************************************************
2976 * VarR4FromI8 (OLEAUT32.360)
2977 *
2978 * Convert a VT_I8 to a VT_R4.
2979 *
2980 * PARAMS
2981 * ullIn [I] Source
2982 * pFltOut [O] Destination
2983 *
2984 * RETURNS
2985 * S_OK.
2986 */
2987 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2988 {
2989 return _VarR4FromI8(llIn, pFltOut);
2990 }
2991
2992 /************************************************************************
2993 * VarR4FromUI8 (OLEAUT32.361)
2994 *
2995 * Convert a VT_UI8 to a VT_R4.
2996 *
2997 * PARAMS
2998 * ullIn [I] Source
2999 * pFltOut [O] Destination
3000 *
3001 * RETURNS
3002 * S_OK.
3003 */
3004 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
3005 {
3006 return _VarR4FromUI8(ullIn, pFltOut);
3007 }
3008
3009 /************************************************************************
3010 * VarR4CmpR8 (OLEAUT32.316)
3011 *
3012 * Compare a VT_R4 to a VT_R8.
3013 *
3014 * PARAMS
3015 * fltLeft [I] Source
3016 * dblRight [I] Value to compare
3017 *
3018 * RETURNS
3019 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3020 * equal to or greater than dblRight respectively.
3021 */
3022 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3023 {
3024 if (fltLeft < dblRight)
3025 return VARCMP_LT;
3026 else if (fltLeft > dblRight)
3027 return VARCMP_GT;
3028 return VARCMP_EQ;
3029 }
3030
3031 /* R8
3032 */
3033
3034 /************************************************************************
3035 * VarR8FromUI1 (OLEAUT32.78)
3036 *
3037 * Convert a VT_UI1 to a VT_R8.
3038 *
3039 * PARAMS
3040 * bIn [I] Source
3041 * pDblOut [O] Destination
3042 *
3043 * RETURNS
3044 * S_OK.
3045 */
3046 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3047 {
3048 return _VarR8FromUI1(bIn, pDblOut);
3049 }
3050
3051 /************************************************************************
3052 * VarR8FromI2 (OLEAUT32.79)
3053 *
3054 * Convert a VT_I2 to a VT_R8.
3055 *
3056 * PARAMS
3057 * sIn [I] Source
3058 * pDblOut [O] Destination
3059 *
3060 * RETURNS
3061 * S_OK.
3062 */
3063 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3064 {
3065 return _VarR8FromI2(sIn, pDblOut);
3066 }
3067
3068 /************************************************************************
3069 * VarR8FromI4 (OLEAUT32.80)
3070 *
3071 * Convert a VT_I4 to a VT_R8.
3072 *
3073 * PARAMS
3074 * sIn [I] Source
3075 * pDblOut [O] Destination
3076 *
3077 * RETURNS
3078 * S_OK.
3079 */
3080 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3081 {
3082 return _VarR8FromI4(lIn, pDblOut);
3083 }
3084
3085 /************************************************************************
3086 * VarR8FromR4 (OLEAUT32.81)
3087 *
3088 * Convert a VT_R4 to a VT_R8.
3089 *
3090 * PARAMS
3091 * fltIn [I] Source
3092 * pDblOut [O] Destination
3093 *
3094 * RETURNS
3095 * S_OK.
3096 */
3097 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3098 {
3099 return _VarR8FromR4(fltIn, pDblOut);
3100 }
3101
3102 /************************************************************************
3103 * VarR8FromCy (OLEAUT32.82)
3104 *
3105 * Convert a VT_CY to a VT_R8.
3106 *
3107 * PARAMS
3108 * cyIn [I] Source
3109 * pDblOut [O] Destination
3110 *
3111 * RETURNS
3112 * S_OK.
3113 */
3114 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3115 {
3116 return _VarR8FromCy(cyIn, pDblOut);
3117 }
3118
3119 /************************************************************************
3120 * VarR8FromDate (OLEAUT32.83)
3121 *
3122 * Convert a VT_DATE to a VT_R8.
3123 *
3124 * PARAMS
3125 * dateIn [I] Source
3126 * pDblOut [O] Destination
3127 *
3128 * RETURNS
3129 * S_OK.
3130 */
3131 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3132 {
3133 return _VarR8FromDate(dateIn, pDblOut);
3134 }
3135
3136 /************************************************************************
3137 * VarR8FromStr (OLEAUT32.84)
3138 *
3139 * Convert a VT_BSTR to a VT_R8.
3140 *
3141 * PARAMS
3142 * strIn [I] Source
3143 * lcid [I] LCID for the conversion
3144 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3145 * pDblOut [O] Destination
3146 *
3147 * RETURNS
3148 * Success: S_OK.
3149 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3150 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3151 */
3152 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3153 {
3154 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3155 }
3156
3157 /************************************************************************
3158 * VarR8FromDisp (OLEAUT32.85)
3159 *
3160 * Convert a VT_DISPATCH to a VT_R8.
3161 *
3162 * PARAMS
3163 * pdispIn [I] Source
3164 * lcid [I] LCID for conversion
3165 * pDblOut [O] Destination
3166 *
3167 * RETURNS
3168 * Success: S_OK.
3169 * Failure: E_INVALIDARG, if the source value is invalid
3170 * DISP_E_OVERFLOW, if the value will not fit in the destination
3171 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3172 */
3173 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3174 {
3175 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8);
3176 }
3177
3178 /************************************************************************
3179 * VarR8FromBool (OLEAUT32.86)
3180 *
3181 * Convert a VT_BOOL to a VT_R8.
3182 *
3183 * PARAMS
3184 * boolIn [I] Source
3185 * pDblOut [O] Destination
3186 *
3187 * RETURNS
3188 * S_OK.
3189 */
3190 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3191 {
3192 return VarR8FromI2(boolIn, pDblOut);
3193 }
3194
3195 /************************************************************************
3196 * VarR8FromI1 (OLEAUT32.217)
3197 *
3198 * Convert a VT_I1 to a VT_R8.
3199 *
3200 * PARAMS
3201 * cIn [I] Source
3202 * pDblOut [O] Destination
3203 *
3204 * RETURNS
3205 * Success: S_OK.
3206 * Failure: E_INVALIDARG, if the source value is invalid
3207 * DISP_E_OVERFLOW, if the value will not fit in the destination
3208 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3209 */
3210 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3211 {
3212 return _VarR8FromI1(cIn, pDblOut);
3213 }
3214
3215 /************************************************************************
3216 * VarR8FromUI2 (OLEAUT32.218)
3217 *
3218 * Convert a VT_UI2 to a VT_R8.
3219 *
3220 * PARAMS
3221 * usIn [I] Source
3222 * pDblOut [O] Destination
3223 *
3224 * RETURNS
3225 * Success: S_OK.
3226 * Failure: E_INVALIDARG, if the source value is invalid
3227 * DISP_E_OVERFLOW, if the value will not fit in the destination
3228 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3229 */
3230 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3231 {
3232 return _VarR8FromUI2(usIn, pDblOut);
3233 }
3234
3235 /************************************************************************
3236 * VarR8FromUI4 (OLEAUT32.219)
3237 *
3238 * Convert a VT_UI4 to a VT_R8.
3239 *
3240 * PARAMS
3241 * ulIn [I] Source
3242 * pDblOut [O] Destination
3243 *
3244 * RETURNS
3245 * Success: S_OK.
3246 * Failure: E_INVALIDARG, if the source value is invalid
3247 * DISP_E_OVERFLOW, if the value will not fit in the destination
3248 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3249 */
3250 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3251 {
3252 return _VarR8FromUI4(ulIn, pDblOut);
3253 }
3254
3255 /************************************************************************
3256 * VarR8FromDec (OLEAUT32.220)
3257 *
3258 * Convert a VT_DECIMAL to a VT_R8.
3259 *
3260 * PARAMS
3261 * pDecIn [I] Source
3262 * pDblOut [O] Destination
3263 *
3264 * RETURNS
3265 * Success: S_OK.
3266 * Failure: E_INVALIDARG, if the source value is invalid.
3267 */
3268 HRESULT WINAPI VarR8FromDec(DECIMAL* pDecIn, double *pDblOut)
3269 {
3270 BYTE scale = DEC_SCALE(pDecIn);
3271 double divisor = 1.0, highPart;
3272
3273 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3274 return E_INVALIDARG;
3275
3276 while (scale--)
3277 divisor *= 10;
3278
3279 if (DEC_SIGN(pDecIn))
3280 divisor = -divisor;
3281
3282 if (DEC_HI32(pDecIn))
3283 {
3284 highPart = (double)DEC_HI32(pDecIn) / divisor;
3285 highPart *= 4294967296.0F;
3286 highPart *= 4294967296.0F;
3287 }
3288 else
3289 highPart = 0.0;
3290
3291 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3292 return S_OK;
3293 }
3294
3295 /************************************************************************
3296 * VarR8FromI8 (OLEAUT32.362)
3297 *
3298 * Convert a VT_I8 to a VT_R8.
3299 *
3300 * PARAMS
3301 * ullIn [I] Source
3302 * pDblOut [O] Destination
3303 *
3304 * RETURNS
3305 * S_OK.
3306 */
3307 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3308 {
3309 return _VarR8FromI8(llIn, pDblOut);
3310 }
3311
3312 /************************************************************************
3313 * VarR8FromUI8 (OLEAUT32.363)
3314 *
3315 * Convert a VT_UI8 to a VT_R8.
3316 *
3317 * PARAMS
3318 * ullIn [I] Source
3319 * pDblOut [O] Destination
3320 *
3321 * RETURNS
3322 * S_OK.
3323 */
3324 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3325 {
3326 return _VarR8FromUI8(ullIn, pDblOut);
3327 }
3328
3329 /************************************************************************
3330 * VarR8Pow (OLEAUT32.315)
3331 *
3332 * Raise a VT_R8 to a power.
3333 *
3334 * PARAMS
3335 * dblLeft [I] Source
3336 * dblPow [I] Power to raise dblLeft by
3337 * pDblOut [O] Destination
3338 *
3339 * RETURNS
3340 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3341 */
3342 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3343 {
3344 *pDblOut = pow(dblLeft, dblPow);
3345 return S_OK;
3346 }
3347
3348 /************************************************************************
3349 * VarR8Round (OLEAUT32.317)
3350 *
3351 * Round a VT_R8 to a given number of decimal points.
3352 *
3353 * PARAMS
3354 * dblIn [I] Source
3355 * nDig [I] Number of decimal points to round to
3356 * pDblOut [O] Destination for rounded number
3357 *
3358 * RETURNS
3359 * Success: S_OK. pDblOut is rounded to nDig digits.
3360 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3361 *
3362 * NOTES
3363 * The native version of this function rounds using the internal
3364 * binary representation of the number. Wine uses the dutch rounding
3365 * convention, so therefore small differences can occur in the value returned.
3366 * MSDN says that you should use your own rounding function if you want
3367 * rounding to be predictable in your application.
3368 */
3369 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3370 {
3371 double scale, whole, fract;
3372
3373 if (nDig < 0)
3374 return E_INVALIDARG;
3375
3376 scale = pow(10.0, nDig);
3377
3378 dblIn *= scale;
3379 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3380 fract = dblIn - whole;
3381
3382 if (fract > 0.5)
3383 dblIn = whole + 1.0;
3384 else if (fract == 0.5)
3385 dblIn = whole + fmod(whole, 2.0);
3386 else if (fract >= 0.0)
3387 dblIn = whole;
3388 else if (fract == -0.5)
3389 dblIn = whole - fmod(whole, 2.0);
3390 else if (fract > -0.5)
3391 dblIn = whole;
3392 else
3393 dblIn = whole - 1.0;
3394
3395 *pDblOut = dblIn / scale;
3396 return S_OK;
3397 }
3398
3399 /* CY
3400 */
3401
3402 /* Powers of 10 from 0..4 D.P. */
3403 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3404 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3405
3406 /************************************************************************
3407 * VarCyFromUI1 (OLEAUT32.98)
3408 *
3409 * Convert a VT_UI1 to a VT_CY.
3410 *
3411 * PARAMS
3412 * bIn [I] Source
3413 * pCyOut [O] Destination
3414 *
3415 * RETURNS
3416 * Success: S_OK.
3417 * Failure: E_INVALIDARG, if the source value is invalid
3418 * DISP_E_OVERFLOW, if the value will not fit in the destination
3419 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3420 */
3421 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3422 {
3423 return VarCyFromR8(bIn, pCyOut);
3424 }
3425
3426 /************************************************************************
3427 * VarCyFromI2 (OLEAUT32.99)
3428 *
3429 * Convert a VT_I2 to a VT_CY.
3430 *
3431 * PARAMS
3432 * sIn [I] Source
3433 * pCyOut [O] Destination
3434 *
3435 * RETURNS
3436 * Success: S_OK.
3437 * Failure: E_INVALIDARG, if the source value is invalid
3438 * DISP_E_OVERFLOW, if the value will not fit in the destination
3439 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3440 */
3441 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3442 {
3443 return VarCyFromR8(sIn, pCyOut);
3444 }
3445
3446 /************************************************************************
3447 * VarCyFromI4 (OLEAUT32.100)
3448 *
3449 * Convert a VT_I4 to a VT_CY.
3450 *
3451 * PARAMS
3452 * sIn [I] Source
3453 * pCyOut [O] Destination
3454 *
3455 * RETURNS
3456 * Success: S_OK.
3457 * Failure: E_INVALIDARG, if the source value is invalid
3458 * DISP_E_OVERFLOW, if the value will not fit in the destination
3459 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3460 */
3461 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3462 {
3463 return VarCyFromR8(lIn, pCyOut);
3464 }
3465
3466 /************************************************************************
3467 * VarCyFromR4 (OLEAUT32.101)
3468 *
3469 * Convert a VT_R4 to a VT_CY.
3470 *
3471 * PARAMS
3472 * fltIn [I] Source
3473 * pCyOut [O] Destination
3474 *
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
3480 */
3481 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3482 {
3483 return VarCyFromR8(fltIn, pCyOut);
3484 }
3485
3486 /************************************************************************
3487 * VarCyFromR8 (OLEAUT32.102)
3488 *
3489 * Convert a VT_R8 to a VT_CY.
3490 *
3491 * PARAMS
3492 * dblIn [I] Source
3493 * pCyOut [O] Destination
3494 *
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
3500 */
3501 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3502 {
3503 #if defined(__GNUC__) && defined(__i386__)
3504 /* This code gives identical results to Win32 on Intel.
3505 * Here we use fp exceptions to catch overflows when storing the value.
3506 */
3507 static const unsigned short r8_fpcontrol = 0x137f;
3508 static const double r8_multiplier = CY_MULTIPLIER_F;
3509 unsigned short old_fpcontrol, result_fpstatus;
3510
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) );
3523
3524 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3525 return DISP_E_OVERFLOW;
3526 return S_OK;
3527 #else
3528 /* This version produces slightly different results for boundary cases */
3529 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3530 return DISP_E_OVERFLOW;
3531 dblIn *= CY_MULTIPLIER_F;
3532 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3533 #endif
3534 return S_OK;
3535 }
3536
3537 /************************************************************************
3538 * VarCyFromDate (OLEAUT32.103)
3539 *
3540 * Convert a VT_DATE to a VT_CY.
3541 *
3542 * PARAMS
3543 * dateIn [I] Source
3544 * pCyOut [O] Destination
3545 *
3546 * RETURNS
3547 * Success: S_OK.
3548 * Failure: E_INVALIDARG, if the source value is invalid
3549 * DISP_E_OVERFLOW, if the value will not fit in the destination
3550 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3551 */
3552 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3553 {
3554 return VarCyFromR8(dateIn, pCyOut);
3555 }
3556
3557 /************************************************************************
3558 * VarCyFromStr (OLEAUT32.104)
3559 *
3560 * Convert a VT_BSTR to a VT_CY.
3561 *
3562 * PARAMS
3563 * strIn [I] Source
3564 * lcid [I] LCID for the conversion
3565 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3566 * pCyOut [O] Destination
3567 *
3568 * RETURNS
3569 * Success: S_OK.
3570 * Failure: E_INVALIDARG, if the source value is invalid
3571 * DISP_E_OVERFLOW, if the value will not fit in the destination
3572 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3573 */
3574 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3575 {
3576 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3577 }
3578
3579 /************************************************************************
3580 * VarCyFromDisp (OLEAUT32.105)
3581 *
3582 * Convert a VT_DISPATCH to a VT_CY.
3583 *
3584 * PARAMS
3585 * pdispIn [I] Source
3586 * lcid [I] LCID for conversion
3587 * pCyOut [O] Destination
3588 *
3589 * RETURNS
3590 * Success: S_OK.
3591 * Failure: E_INVALIDARG, if the source value is invalid
3592 * DISP_E_OVERFLOW, if the value will not fit in the destination
3593 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3594 */
3595 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3596 {
3597 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY);
3598 }
3599
3600 /************************************************************************
3601 * VarCyFromBool (OLEAUT32.106)
3602 *
3603 * Convert a VT_BOOL to a VT_CY.
3604 *
3605 * PARAMS
3606 * boolIn [I] Source
3607 * pCyOut [O] Destination
3608 *
3609 * RETURNS
3610 * Success: S_OK.
3611 * Failure: E_INVALIDARG, if the source value is invalid
3612 * DISP_E_OVERFLOW, if the value will not fit in the destination
3613 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3614 *
3615 * NOTES
3616 * While the sign of the boolean is stored in the currency, the value is
3617 * converted to either 0 or 1.
3618 */
3619 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3620 {
3621 return VarCyFromR8(boolIn, pCyOut);
3622 }
3623
3624 /************************************************************************
3625 * VarCyFromI1 (OLEAUT32.225)
3626 *
3627 * Convert a VT_I1 to a VT_CY.
3628 *
3629 * PARAMS
3630 * cIn [I] Source
3631 * pCyOut [O] Destination
3632 *
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
3638 */
3639 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3640 {
3641 return VarCyFromR8(cIn, pCyOut);
3642 }
3643
3644 /************************************************************************
3645 * VarCyFromUI2 (OLEAUT32.226)
3646 *
3647 * Convert a VT_UI2 to a VT_CY.
3648 *
3649 * PARAMS
3650 * usIn [I] Source
3651 * pCyOut [O] Destination
3652 *
3653 * RETURNS
3654 * Success: S_OK.
3655 * Failure: E_INVALIDARG, if the source value is invalid
3656 * DISP_E_OVERFLOW, if the value will not fit in the destination
3657 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3658 */
3659 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3660 {
3661 return VarCyFromR8(usIn, pCyOut);
3662 }
3663
3664 /************************************************************************
3665 * VarCyFromUI4 (OLEAUT32.227)
3666 *
3667 * Convert a VT_UI4 to a VT_CY.
3668 *
3669 * PARAMS
3670 * ulIn [I] Source
3671 * pCyOut [O] Destination
3672 *
3673 * RETURNS
3674 * Success: S_OK.
3675 * Failure: E_INVALIDARG, if the source value is invalid
3676 * DISP_E_OVERFLOW, if the value will not fit in the destination
3677 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3678 */
3679 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3680 {
3681 return VarCyFromR8(ulIn, pCyOut);
3682 }
3683
3684 /************************************************************************
3685 * VarCyFromDec (OLEAUT32.228)
3686 *
3687 * Convert a VT_DECIMAL to a VT_CY.
3688 *
3689 * PARAMS
3690 * pdecIn [I] Source
3691 * pCyOut [O] Destination
3692 *
3693 * RETURNS
3694 * Success: S_OK.
3695 * Failure: E_INVALIDARG, if the source value is invalid
3696 * DISP_E_OVERFLOW, if the value will not fit in the destination
3697 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3698 */
3699 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
3700 {
3701 DECIMAL rounded;
3702 HRESULT hRet;
3703
3704 hRet = VarDecRound(pdecIn, 4, &rounded);
3705
3706 if (SUCCEEDED(hRet))
3707 {
3708 double d;
3709
3710 if (DEC_HI32(&rounded))
3711 return DISP_E_OVERFLOW;
3712
3713 /* Note: Without the casts this promotes to int64 which loses precision */
3714 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3715 if (DEC_SIGN(&rounded))
3716 d = -d;
3717 return VarCyFromR8(d, pCyOut);
3718 }
3719 return hRet;
3720 }
3721
3722 /************************************************************************
3723 * VarCyFromI8 (OLEAUT32.366)
3724 *
3725 * Convert a VT_I8 to a VT_CY.
3726 *
3727 * PARAMS
3728 * ullIn [I] Source
3729 * pCyOut [O] Destination
3730 *
3731 * RETURNS
3732 * Success: S_OK.
3733 * Failure: E_INVALIDARG, if the source value is invalid
3734 * DISP_E_OVERFLOW, if the value will not fit in the destination
3735 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3736 */
3737 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3738 {
3739 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3740 pCyOut->int64 = llIn * CY_MULTIPLIER;
3741 return S_OK;
3742 }
3743
3744 /************************************************************************
3745 * VarCyFromUI8 (OLEAUT32.375)
3746 *
3747 * Convert a VT_UI8 to a VT_CY.
3748 *
3749 * PARAMS
3750 * ullIn [I] Source
3751 * pCyOut [O] Destination
3752 *
3753 * RETURNS
3754 * Success: S_OK.
3755 * Failure: E_INVALIDARG, if the source value is invalid
3756 * DISP_E_OVERFLOW, if the value will not fit in the destination
3757 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3758 */
3759 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3760 {
3761 return VarCyFromR8(ullIn, pCyOut);
3762 }
3763
3764 /************************************************************************
3765 * VarCyAdd (OLEAUT32.299)
3766 *
3767 * Add one CY to another.
3768 *
3769 * PARAMS
3770 * cyLeft [I] Source
3771 * cyRight [I] Value to add
3772 * pCyOut [O] Destination
3773 *
3774 * RETURNS
3775 * Success: S_OK.
3776 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3777 */
3778 HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut)
3779 {
3780 double l,r;
3781 _VarR8FromCy(cyLeft, &l);
3782 _VarR8FromCy(cyRight, &r);
3783 l = l + r;
3784 return VarCyFromR8(l, pCyOut);
3785 }
3786
3787 /************************************************************************
3788 * VarCyMul (OLEAUT32.303)
3789 *
3790 * Multiply one CY by another.
3791 *
3792 * PARAMS
3793 * cyLeft [I] Source
3794 * cyRight [I] Value to multiply by
3795 * pCyOut [O] Destination
3796 *
3797 * RETURNS
3798 * Success: S_OK.
3799 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3800 */
3801 HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut)
3802 {
3803 double l,r;
3804 _VarR8FromCy(cyLeft, &l);
3805 _VarR8FromCy(cyRight, &r);
3806 l = l * r;
3807 return VarCyFromR8(l, pCyOut);
3808 }
3809
3810 /************************************************************************
3811 * VarCyMulI4 (OLEAUT32.304)
3812 *
3813 * Multiply one CY by a VT_I4.
3814 *
3815 * PARAMS
3816 * cyLeft [I] Source
3817 * lRight [I] Value to multiply by
3818 * pCyOut [O] Destination
3819 *
3820 * RETURNS
3821 * Success: S_OK.
3822 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3823 */
3824 HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut)
3825 {
3826 double d;
3827
3828 _VarR8FromCy(cyLeft, &d);
3829 d = d * lRight;
3830 return VarCyFromR8(d, pCyOut);
3831 }
3832
3833 /************************************************************************
3834 * VarCySub (OLEAUT32.305)
3835 *
3836 * Subtract one CY from another.
3837 *
3838 * PARAMS
3839 * cyLeft [I] Source
3840 * cyRight [I] Value to subtract
3841 * pCyOut [O] Destination
3842 *
3843 * RETURNS
3844 * Success: S_OK.
3845 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3846 */
3847 HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut)
3848 {
3849 double l,r;
3850 _VarR8FromCy(cyLeft, &l);
3851 _VarR8FromCy(cyRight, &r);
3852 l = l - r;
3853 return VarCyFromR8(l, pCyOut);
3854 }
3855
3856 /************************************************************************
3857 * VarCyAbs (OLEAUT32.306)
3858 *
3859 * Convert a VT_CY into its absolute value.
3860 *
3861 * PARAMS
3862 * cyIn [I] Source
3863 * pCyOut [O] Destination
3864 *
3865 * RETURNS
3866 * Success: S_OK. pCyOut contains the absolute value.
3867 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3868 */
3869 HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut)
3870 {
3871 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3872 return DISP_E_OVERFLOW;
3873
3874 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3875 return S_OK;
3876 }
3877
3878 /************************************************************************
3879 * VarCyFix (OLEAUT32.307)
3880 *
3881 * Return the integer part of a VT_CY.
3882 *
3883 * PARAMS
3884 * cyIn [I] Source
3885 * pCyOut [O] Destination
3886 *
3887 * RETURNS
3888 * Success: S_OK.
3889 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3890 *
3891 * NOTES
3892 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3893 * negative numbers away from 0, while this function rounds them towards zero.
3894 */
3895 HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut)
3896 {
3897 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3898 pCyOut->int64 *= CY_MULTIPLIER;
3899 return S_OK;
3900 }
3901
3902 /************************************************************************
3903 * VarCyInt (OLEAUT32.308)
3904 *
3905 * Return the integer part of a VT_CY.
3906 *
3907 * PARAMS
3908 * cyIn [I] Source
3909 * pCyOut [O] Destination
3910 *
3911 * RETURNS
3912 * Success: S_OK.
3913 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3914 *
3915 * NOTES
3916 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3917 * negative numbers towards 0, while this function rounds them away from zero.
3918 */
3919 HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut)
3920 {
3921 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3922 pCyOut->int64 *= CY_MULTIPLIER;
3923
3924 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3925 {
3926 pCyOut->int64 -= CY_MULTIPLIER;
3927 }
3928 return S_OK;
3929 }
3930
3931 /************************************************************************
3932 * VarCyNeg (OLEAUT32.309)
3933 *
3934 * Change the sign of a VT_CY.
3935 *
3936 * PARAMS
3937 * cyIn [I] Source
3938 * pCyOut [O] Destination
3939 *
3940 * RETURNS
3941 * Success: S_OK.
3942 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3943 */
3944 HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut)
3945 {
3946 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3947 return DISP_E_OVERFLOW;
3948
3949 pCyOut->int64 = -cyIn.int64;
3950 return S_OK;
3951 }
3952
3953 /************************************************************************
3954 * VarCyRound (OLEAUT32.310)
3955 *
3956 * Change the precision of a VT_CY.
3957 *
3958 * PARAMS
3959 * cyIn [I] Source
3960 * cDecimals [I] New number of decimals to keep
3961 * pCyOut [O] Destination
3962 *
3963 * RETURNS
3964 * Success: S_OK.
3965 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3966 */
3967 HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
3968 {
3969 if (cDecimals < 0)
3970 return E_INVALIDARG;
3971
3972 if (cDecimals > 3)
3973 {
3974 /* Rounding to more precision than we have */
3975 *pCyOut = cyIn;
3976 return S_OK;
3977 }
3978 else
3979 {
3980 double d, div = CY_Divisors[cDecimals];
3981
3982 _VarR8FromCy(cyIn, &d);
3983 d = d * div;
3984 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3985 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3986 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64)
3987 return S_OK;
3988 }
3989 }
3990
3991 /************************************************************************
3992 * VarCyCmp (OLEAUT32.311)
3993 *
3994 * Compare two VT_CY values.
3995 *
3996 * PARAMS
3997 * cyLeft [I] Source
3998 * cyRight [I] Value to compare
3999 *
4000 * RETURNS
4001 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4002 * compare is less, equal or greater than source respectively.
4003 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4004 */
4005 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
4006 {
4007 HRESULT hRet;
4008 CY result;
4009
4010 /* Subtract right from left, and compare the result to 0 */
4011 hRet = VarCySub(cyLeft, cyRight, &result);
4012
4013 if (SUCCEEDED(hRet))
4014 {
4015 if (result.int64 < 0)
4016 hRet = (HRESULT)VARCMP_LT;
4017 else if (result.int64 > 0)
4018 hRet = (HRESULT)VARCMP_GT;
4019 else
4020 hRet = (HRESULT)VARCMP_EQ;
4021 }
4022 return hRet;
4023 }
4024
4025 /************************************************************************
4026 * VarCyCmpR8 (OLEAUT32.312)
4027 *
4028 * Compare a VT_CY to a double
4029 *
4030 * PARAMS
4031 * cyLeft [I] Currency Source
4032 * dblRight [I] double to compare to cyLeft
4033 *
4034 * RETURNS
4035 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4036 * less than, equal to or greater than cyLeft respectively.
4037 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4038 */
4039 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight)
4040 {
4041 HRESULT hRet;
4042 CY cyRight;
4043
4044 hRet = VarCyFromR8(dblRight, &cyRight);
4045
4046 if (SUCCEEDED(hRet))
4047 hRet = VarCyCmp(cyLeft, cyRight);
4048
4049 return hRet;
4050 }
4051
4052 /************************************************************************
4053 * VarCyMulI8 (OLEAUT32.329)
4054 *
4055 * Multiply a VT_CY by a VT_I8.
4056 *
4057 * PARAMS
4058 * cyLeft [I] Source
4059 * llRight [I] Value to multiply by
4060 * pCyOut [O] Destination
4061 *
4062 * RETURNS
4063 * Success: S_OK.
4064 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4065 */
4066 HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
4067 {
4068 double d;
4069
4070 _VarR8FromCy(cyLeft, &d);
4071 d = d * (double)llRight;
4072 return VarCyFromR8(d, pCyOut);
4073 }
4074
4075 /* DECIMAL
4076 */
4077
4078 /************************************************************************
4079 * VarDecFromUI1 (OLEAUT32.190)
4080 *
4081 * Convert a VT_UI1 to a DECIMAL.
4082 *
4083 * PARAMS
4084 * bIn [I] Source
4085 * pDecOut [O] Destination
4086 *
4087 * RETURNS
4088 * S_OK.
4089 */
4090 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4091 {
4092 return VarDecFromUI4(bIn, pDecOut);
4093 }
4094
4095 /************************************************************************
4096 * VarDecFromI2 (OLEAUT32.191)
4097 *
4098 * Convert a VT_I2 to a DECIMAL.
4099 *
4100 * PARAMS
4101 * sIn [I] Source
4102 * pDecOut [O] Destination
4103 *
4104 * RETURNS
4105 * S_OK.
4106 */
4107 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4108 {
4109 return VarDecFromI4(sIn, pDecOut);
4110 }
4111
4112 /************************************************************************
4113 * VarDecFromI4 (OLEAUT32.192)
4114 *
4115 * Convert a VT_I4 to a DECIMAL.
4116 *
4117 * PARAMS
4118 * sIn [I] Source
4119 * pDecOut [O] Destination
4120 *
4121 * RETURNS
4122 * S_OK.
4123 */
4124 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4125 {
4126 DEC_HI32(pDecOut) = 0;
4127 DEC_MID32(pDecOut) = 0;
4128
4129 if (lIn < 0)
4130 {
4131 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4132 DEC_LO32(pDecOut) = -lIn;
4133 }
4134 else
4135 {
4136 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4137 DEC_LO32(pDecOut) = lIn;
4138 }
4139 return S_OK;
4140 }
4141
4142 #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT))
4143
4144 /************************************************************************
4145 * VarDecFromR4 (OLEAUT32.193)
4146 *
4147 * Convert a VT_R4 to a DECIMAL.
4148 *
4149 * PARAMS
4150 * fltIn [I] Source
4151 * pDecOut [O] Destination
4152 *
4153 * RETURNS
4154 * S_OK.
4155 */
4156 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4157 {
4158 WCHAR buff[256];
4159
4160 sprintfW( buff, szFloatFormatW, fltIn );
4161 return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut);
4162 }
4163
4164 /************************************************************************
4165 * VarDecFromR8 (OLEAUT32.194)
4166 *
4167 * Convert a VT_R8 to a DECIMAL.
4168 *
4169 * PARAMS
4170 * dblIn [I] Source
4171 * pDecOut [O] Destination
4172 *
4173 * RETURNS
4174 * S_OK.
4175 */
4176 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4177 {
4178 WCHAR buff[256];
4179
4180 sprintfW( buff, szDoubleFormatW, dblIn );
4181 return VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut);
4182 }
4183
4184 /************************************************************************
4185 * VarDecFromDate (OLEAUT32.195)
4186 *
4187 * Convert a VT_DATE to a DECIMAL.
4188 *
4189 * PARAMS
4190 * dateIn [I] Source
4191 * pDecOut [O] Destination
4192 *
4193 * RETURNS
4194 * S_OK.
4195 */
4196 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4197 {
4198 return VarDecFromR8(dateIn, pDecOut);
4199 }
4200
4201 /************************************************************************
4202 * VarDecFromCy (OLEAUT32.196)
4203 *
4204 * Convert a VT_CY to a DECIMAL.
4205 *
4206 * PARAMS
4207 * cyIn [I] Source
4208 * pDecOut [O] Destination
4209 *
4210 * RETURNS
4211 * S_OK.
4212 */
4213 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4214 {
4215 DEC_HI32(pDecOut) = 0;
4216
4217 /* Note: This assumes 2s complement integer representation */
4218 if (cyIn.s.Hi & 0x80000000)
4219 {
4220 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4221 DEC_LO64(pDecOut) = -cyIn.int64;
4222 }
4223 else
4224 {
4225 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4226 DEC_MID32(pDecOut) = cyIn.s.Hi;
4227 DEC_LO32(pDecOut) = cyIn.s.Lo;
4228 }
4229 return S_OK;
4230 }
4231
4232 /************************************************************************
4233 * VarDecFromStr (OLEAUT32.197)
4234 *
4235 * Convert a VT_BSTR to a DECIMAL.
4236 *
4237 * PARAMS
4238 * strIn [I] Source
4239 * lcid [I] LCID for the conversion
4240 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4241 * pDecOut [O] Destination
4242 *
4243 * RETURNS
4244 * Success: S_OK.
4245 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4246 */
4247 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4248 {
4249 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4250 }
4251
4252 /************************************************************************
4253 * VarDecFromDisp (OLEAUT32.198)
4254 *
4255 * Convert a VT_DISPATCH to a DECIMAL.
4256 *
4257 * PARAMS
4258 * pdispIn [I] Source
4259 * lcid [I] LCID for conversion
4260 * pDecOut [O] Destination
4261 *
4262 * RETURNS
4263 * Success: S_OK.
4264 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4265 */
4266 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4267 {
4268 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL);
4269 }
4270
4271 /************************************************************************
4272 * VarDecFromBool (OLEAUT32.199)
4273 *
4274 * Convert a VT_BOOL to a DECIMAL.
4275 *
4276 * PARAMS
4277 * bIn [I] Source
4278 * pDecOut [O] Destination
4279 *
4280 * RETURNS
4281 * S_OK.
4282 *
4283 * NOTES
4284 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4285 */
4286 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4287 {
4288 DEC_HI32(pDecOut) = 0;
4289 DEC_MID32(pDecOut) = 0;
4290 if (bIn)
4291 {
4292 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4293 DEC_LO32(pDecOut) = 1;
4294 }
4295 else
4296 {
4297 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4298 DEC_LO32(pDecOut) = 0;
4299 }
4300 return S_OK;
4301 }
4302
4303 /************************************************************************
4304 * VarDecFromI1 (OLEAUT32.241)
4305 *
4306 * Convert a VT_I1 to a DECIMAL.
4307 *
4308 * PARAMS
4309 * cIn [I] Source
4310 * pDecOut [O] Destination
4311 *
4312 * RETURNS
4313 * S_OK.
4314 */
4315 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4316 {
4317 return VarDecFromI4(cIn, pDecOut);
4318 }
4319
4320 /************************************************************************
4321 * VarDecFromUI2 (OLEAUT32.242)
4322 *
4323 * Convert a VT_UI2 to a DECIMAL.
4324 *
4325 * PARAMS
4326 * usIn [I] Source
4327 * pDecOut [O] Destination
4328 *
4329 * RETURNS
4330 * S_OK.
4331 */
4332 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4333 {
4334 return VarDecFromUI4(usIn, pDecOut);
4335 }
4336
4337 /************************************************************************
4338 * VarDecFromUI4 (OLEAUT32.243)
4339 *
4340 * Convert a VT_UI4 to a DECIMAL.
4341 *
4342 * PARAMS
4343 * ulIn [I] Source
4344 * pDecOut [O] Destination
4345 *
4346 * RETURNS
4347 * S_OK.
4348 */
4349 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4350 {
4351 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4352 DEC_HI32(pDecOut) = 0;
4353 DEC_MID32(pDecOut) = 0;
4354 DEC_LO32(pDecOut) = ulIn;
4355 return S_OK;
4356 }
4357
4358 /************************************************************************
4359 * VarDecFromI8 (OLEAUT32.374)
4360 *
4361 * Convert a VT_I8 to a DECIMAL.
4362 *
4363 * PARAMS
4364 * llIn [I] Source
4365 * pDecOut [O] Destination
4366 *
4367 * RETURNS
4368 * S_OK.
4369 */
4370 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4371 {
4372 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4373
4374 DEC_HI32(pDecOut) = 0;
4375
4376 /* Note: This assumes 2s complement integer representation */
4377 if (pLi->u.HighPart & 0x80000000)
4378 {
4379 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4380 DEC_LO64(pDecOut) = -pLi->QuadPart;
4381 }
4382 else
4383 {
4384 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4385 DEC_MID32(pDecOut) = pLi->u.HighPart;
4386 DEC_LO32(pDecOut) = pLi->u.LowPart;
4387 }
4388 return S_OK;
4389 }
4390
4391 /************************************************************************
4392 * VarDecFromUI8 (OLEAUT32.375)
4393 *
4394 * Convert a VT_UI8 to a DECIMAL.
4395 *
4396 * PARAMS
4397 * ullIn [I] Source
4398 * pDecOut [O] Destination
4399 *
4400 * RETURNS
4401 * S_OK.
4402 */
4403 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4404 {
4405 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4406 DEC_HI32(pDecOut) = 0;
4407 DEC_LO64(pDecOut) = ullIn;
4408 return S_OK;
4409 }
4410
4411 /* Make two DECIMALS the same scale; used by math functions below */
4412 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4413 const DECIMAL** ppDecRight,
4414 DECIMAL* pDecOut)
4415 {
4416 static DECIMAL scaleFactor;
4417 DECIMAL decTemp;
4418 int scaleAmount, i;
4419 HRESULT hRet = S_OK;
4420
4421 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4422 return E_INVALIDARG;
4423
4424 DEC_LO32(&scaleFactor) = 10;
4425
4426 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4427
4428 if (!scaleAmount)
4429 return S_OK; /* Same scale */
4430
4431 if (scaleAmount > 0)
4432 {
4433 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4434 *ppDecRight = pDecOut;
4435 }
4436 else
4437 {
4438 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4439 *ppDecLeft = pDecOut;
4440 i = scaleAmount = -scaleAmount;
4441 }
4442
4443 if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE)
4444 return DISP_E_OVERFLOW; /* Can't scale up */
4445
4446 /* Multiply up the value to be scaled by the correct amount */
4447 while (SUCCEEDED(hRet) && i--)
4448 {
4449 /* Note we are multiplying by a value with a scale of 0, so we don't recurse */
4450 hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut);
4451 decTemp = *pDecOut;
4452 }
4453 DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */
4454 return hRet;
4455 }
4456
4457 /* Add two unsigned 32 bit values with overflow */
4458 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4459 {
4460 ULARGE_INTEGER ul64;
4461
4462 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4463 *pulHigh = ul64.u.HighPart;
4464 return ul64.u.LowPart;
4465 }
4466
4467 /* Subtract two unsigned 32 bit values with underflow */
4468 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4469 {
4470 int invert = 0;
4471 ULARGE_INTEGER ul64;
4472
4473 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4474 if (ulLeft < ulRight)
4475 invert = 1;
4476
4477 if (ul64.QuadPart > (ULONG64)*pulHigh)
4478 ul64.QuadPart -= (ULONG64)*pulHigh;
4479 else
4480 {
4481 ul64.QuadPart -= (ULONG64)*pulHigh;
4482 invert = 1;
4483 }
4484 if (invert)
4485 ul64.u.HighPart = -ul64.u.HighPart ;
4486
4487 *pulHigh = ul64.u.HighPart;
4488 return ul64.u.LowPart;
4489 }
4490
4491 /* Multiply two unsigned 32 bit values with overflow */
4492 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4493 {
4494 ULARGE_INTEGER ul64;
4495
4496 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4497 *pulHigh = ul64.u.HighPart;
4498 return ul64.u.LowPart;
4499 }
4500
4501 /* Compare two decimals that have the same scale */
4502 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4503 {
4504 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4505 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4506 return -1;
4507 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4508 return 0;
4509 return 1;
4510 }
4511
4512 /************************************************************************
4513 * VarDecAdd (OLEAUT32.177)
4514 *
4515 * Add one DECIMAL to another.
4516 *
4517 * PARAMS
4518 * pDecLeft [I] Source
4519 * pDecRight [I] Value to add
4520 * pDecOut [O] Destination
4521 *
4522 * RETURNS
4523 * Success: S_OK.
4524 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4525 */
4526 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4527 {
4528 HRESULT hRet;
4529 DECIMAL scaled;
4530
4531 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled);
4532
4533 if (SUCCEEDED(hRet))
4534 {
4535 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4536 ULONG overflow = 0;
4537 BYTE sign = DECIMAL_POS;
4538
4539 /* Correct for the sign of the result */
4540 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4541 {
4542 /* -x + -y : Negative */
4543 sign = DECIMAL_NEG;
4544 goto VarDecAdd_AsPositive;
4545 }
4546 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4547 {
4548 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4549
4550 /* -x + y : Negative if x > y */
4551 if (cmp > 0)
4552 {
4553 sign = DECIMAL_NEG;
4554 VarDecAdd_AsNegative:
4555 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4556 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4557 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4558 }
4559 else
4560 {
4561 VarDecAdd_AsInvertedNegative:
4562 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4563 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4564 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4565 }
4566 }
4567 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4568 {
4569 int cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4570
4571 /* x + -y : Negative if x <= y */
4572 if (cmp <= 0)
4573 {
4574 sign = DECIMAL_NEG;
4575 goto VarDecAdd_AsInvertedNegative;
4576 }
4577 goto VarDecAdd_AsNegative;
4578 }
4579 else
4580 {
4581 /* x + y : Positive */
4582 VarDecAdd_AsPositive:
4583 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4584 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4585 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4586 }
4587
4588 if (overflow)
4589 return DISP_E_OVERFLOW; /* overflowed */
4590
4591 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4592 DEC_SIGN(pDecOut) = sign;
4593 }
4594 return hRet;
4595 }
4596
4597 /* internal representation of the value stored in a DECIMAL. The bytes are
4598 stored from LSB at index 0 to MSB at index 11
4599 */
4600 typedef struct DECIMAL_internal
4601 {
4602 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4603 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4604 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4605 } VARIANT_DI;
4606
4607 /* translate from external DECIMAL format into an internal representation */
4608 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4609 {
4610 to->scale = DEC_SCALE(from);
4611 to->sign = DEC_SIGN(from) ? 1 : 0;
4612
4613 to->bitsnum[0] = DEC_LO32(from);
4614 to->bitsnum[1] = DEC_MID32(from);
4615 to->bitsnum[2] = DEC_HI32(from);
4616 }
4617
4618 static void VARIANT_DecFromDI(VARIANT_DI * from, DECIMAL * to)
4619 {
4620 if (from->sign) {
4621 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4622 } else {
4623 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4624 }
4625
4626 DEC_LO32(to) = from->bitsnum[0];
4627 DEC_MID32(to) = from->bitsnum[1];
4628 DEC_HI32(to) = from->bitsnum[2];
4629 }
4630
4631 /* clear an internal representation of a DECIMAL */
4632 static void VARIANT_DI_clear(VARIANT_DI * i)
4633 {
4634 memset(i, 0, sizeof(VARIANT_DI));
4635 }
4636
4637 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4638 size is supported. The value in p is replaced by the quotient of the division, and
4639 the remainder is returned as a result. This routine is most often used with a divisor
4640 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4641 */
4642 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4643 {
4644 if (divisor == 0) {
4645 /* division by 0 */
4646 return 0xFF;
4647 } else if (divisor == 1) {
4648 /* dividend remains unchanged */
4649 return 0;
4650 } else {
4651 unsigned char remainder = 0;
4652 ULONGLONG iTempDividend;
4653 signed int i;
4654
4655 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4656 for (; i >= 0; i--) {
4657 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4658 remainder = iTempDividend % divisor;
4659 p[i] = iTempDividend / divisor;
4660 }
4661
4662 return remainder;
4663 }
4664 }
4665
4666 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4667 static int VARIANT_int_iszero(DWORD * p, unsigned int n)
4668 {
4669 for (; n > 0; n--) if (*p++ != 0) return 0;
4670 return 1;
4671 }
4672
4673 /* multiply two DECIMALS, without changing either one, and place result in third
4674 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4675 digits when scale > 0 in order to fit an overflowing result. Final overflow
4676 flag is returned.
4677 */
4678 static int VARIANT_DI_mul(VARIANT_DI * a, VARIANT_DI * b, VARIANT_DI * result)
4679 {
4680 int r_overflow = 0;
4681 DWORD running[6];
4682 signed int mulstart;
4683
4684 VARIANT_DI_clear(result);
4685 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4686
4687 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4688 of the result is formed by adding the scales of the operands.
4689 */
4690 result->scale = a->scale + b->scale;
4691 memset(running, 0, sizeof(running));
4692
4693 /* count number of leading zero-bytes in operand A */
4694 for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4695 if (mulstart < 0) {
4696 /* result is 0, because operand A is 0 */
4697 result->scale = 0;
4698 result->sign = 0;
4699 } else {
4700 unsigned char remainder = 0;
4701 int iA;
4702
4703 /* perform actual multiplication */
4704 for (iA = 0; iA <= mulstart; iA++) {
4705 ULONG iOverflowMul;
4706 int iB;
4707
4708 for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
4709 ULONG iRV;
4710 int iR;
4711
4712 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4713 iR = iA + iB;
4714 do {
4715 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4716 iR++;
4717 } while (iRV);
4718 }
4719 }
4720
4721 /* Too bad - native oleaut does not do this, so we should not either */
4722 #if 0
4723 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4724 This operation should not lose significant digits, and gives an
4725 opportunity to reduce the possibility of overflows in future
4726 operations issued by the application.
4727 */
4728 while (result->scale > 0) {
4729 memcpy(quotient, running, sizeof(quotient));
4730 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4731 if (remainder > 0) break;
4732 memcpy(running, quotient, sizeof(quotient));
4733 result->scale--;
4734 }
4735 #endif
4736 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4737 This operation *will* lose significant digits of the result because
4738 all the factors of 10 were consumed by the previous operation.
4739 */
4740 while (result->scale > 0 && !VARIANT_int_iszero(
4741 running + sizeof(result->bitsnum) / sizeof(DWORD),
4742 (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
4743
4744 remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
4745 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4746 result->scale--;
4747 }
4748
4749 /* round up the result - native oleaut32 does this */
4750 if (remainder >= 5) {
4751 unsigned int i;
4752 for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
4753 ULONGLONG digit = running[i] + 1;
4754 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4755 running[i] = digit & 0xFFFFFFFF;
4756 }
4757 }
4758
4759 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4760 and copy result bits into result structure
4761 */
4762 r_overflow = !VARIANT_int_iszero(
4763 running + sizeof(result->bitsnum)/sizeof(DWORD),
4764 (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
4765 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4766 }
4767 return r_overflow;
4768 }
4769
4770 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4771 hardcoded (period for decimal separator, dash as negative sign). Returns 0 for
4772 success, nonzero if insufficient space in output buffer.
4773 */
4774 static int VARIANT_DI_tostringW(VARIANT_DI * a, WCHAR * s, unsigned int n)
4775 {
4776 int overflow = 0;
4777 DWORD quotient[3];
4778 unsigned char remainder;
4779 unsigned int i;
4780
4781 /* place negative sign */
4782 if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
4783 if (n > 0) {
4784 *s++ = '-';
4785 n--;
4786 }
4787 else overflow = 1;
4788 }
4789
4790 /* prepare initial 0 */
4791 if (!overflow) {
4792 if (n >= 2) {
4793 s[0] = '0';
4794 s[1] = '\0';
4795 } else overflow = 1;
4796 }
4797
4798 i = 0;
4799 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4800 while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
4801 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4802 if (i + 2 > n) {
4803 overflow = 1;
4804 } else {
4805 s[i++] = '0' + remainder;
4806 s[i] = '\0';
4807 }
4808 }
4809
4810 if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
4811
4812 /* reverse order of digits */
4813 WCHAR * x = s; WCHAR * y = s + i - 1;
4814 while (x < y) {
4815 *x ^= *y;
4816 *y ^= *x;
4817 *x++ ^= *y--;
4818 }
4819
4820 /* check for decimal point. "i" now has string length */
4821 if (i <= a->scale) {
4822 unsigned int numzeroes = a->scale + 1 - i;
4823 if (i + 1 + numzeroes >= n) {
4824 overflow = 1;
4825 } else {
4826 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4827 i += numzeroes;
4828 while (numzeroes > 0) {
4829 s[--numzeroes] = '0';
4830 }
4831 }
4832 }
4833
4834 /* place decimal point */
4835 if (a->scale > 0) {
4836 unsigned int periodpos = i - a->scale;
4837 if (i + 2 >= n) {
4838 overflow = 1;
4839 } else {
4840 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4841 s[periodpos] = '.'; i++;
4842
4843 /* remove extra zeros at the end, if any */
4844 while (s[i - 1] == '0') s[--i] = '\0';
4845 if (s[i - 1] == '.') s[--i] = '\0';
4846 }
4847 }
4848 }
4849
4850 return overflow;
4851 }
4852
4853 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4854 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4855 {
4856 DWORD shifted;
4857 unsigned int i;
4858
4859 /* shift whole DWORDs to the left */
4860 while (shift >= 32)
4861 {
4862 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4863 *p = 0; shift -= 32;
4864 }
4865
4866 /* shift remainder (1..31 bits) */
4867 shifted = 0;
4868 if (shift > 0) for (i = 0; i < n; i++)
4869 {
4870 DWORD b;
4871 b = p[i] >> (32 - shift);
4872 p[i] = (p[i] << shift) | shifted;
4873 shifted = b;
4874 }
4875 }
4876
4877 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4878 Value at v is incremented by the value at p. Any size is supported, provided
4879 that v is not shorter than p. Any unapplied carry is returned as a result.
4880 */
4881 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, DWORD * p,
4882 unsigned int np)
4883 {
4884 unsigned char carry = 0;
4885
4886 if (nv >= np) {
4887 ULONGLONG sum;
4888 unsigned int i;
4889
4890 for (i = 0; i < np; i++) {
4891 sum = (ULONGLONG)v[i]
4892 + (ULONGLONG)p[i]
4893 + (ULONGLONG)carry;
4894 v[i] = sum & 0xffffffff;
4895 carry = sum >> 32;
4896 }
4897 for (; i < nv && carry; i++) {
4898 sum = (ULONGLONG)v[i]
4899 + (ULONGLONG)carry;
4900 v[i] = sum & 0xffffffff;
4901 carry = sum >> 32;
4902 }
4903 }
4904 return carry;
4905 }
4906
4907 /* perform integral division with operand p as dividend. Parameter n indicates
4908 number of available DWORDs in divisor p, but available space in p must be
4909 actually at least 2 * n DWORDs, because the remainder of the integral
4910 division is built in the next n DWORDs past the start of the quotient. This
4911 routine replaces the dividend in p with the quotient, and appends n
4912 additional DWORDs for the remainder.
4913
4914 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4915 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4916 source code to the VLI (Very Large Integer) division operator. This algorithm
4917 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4918 variably-scaled integers such as the MS DECIMAL representation.
4919 */
4920 static void VARIANT_int_div(DWORD * p, unsigned int n, DWORD * divisor,
4921 unsigned int dn)
4922 {
4923 unsigned int i;
4924 DWORD tempsub[8];
4925 DWORD * negdivisor = tempsub + n;
4926
4927 /* build 2s-complement of divisor */
4928 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
4929 p[n] = 1;
4930 VARIANT_int_add(negdivisor, n, p + n, 1);
4931 memset(p + n, 0, n * sizeof(DWORD));
4932
4933 /* skip all leading zero DWORDs in quotient */
4934 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
4935 /* i is now number of DWORDs left to process */
4936 for (i <<= 5; i < (n << 5); i++) {
4937 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
4938
4939 /* trial subtraction */
4940 memcpy(tempsub, p + n, n * sizeof(DWORD));
4941 VARIANT_int_add(tempsub, n, negdivisor, n);
4942
4943 /* check whether result of subtraction was negative */
4944 if ((tempsub[n - 1] & 0x80000000) == 0) {
4945 memcpy(p + n, tempsub, n * sizeof(DWORD));
4946 p[0] |= 1;
4947 }
4948 }
4949 }
4950
4951 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4952 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
4953 {
4954 unsigned int i;
4955 ULONG iOverflowMul;
4956
4957 for (iOverflowMul = 0, i = 0; i < n; i++)
4958 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
4959 return (unsigned char)iOverflowMul;
4960 }
4961
4962 /* increment value in A by the value indicated in B, with scale adjusting.
4963 Modifies parameters by adjusting scales. Returns 0 if addition was
4964 successful, nonzero if a parameter underflowed before it could be
4965 successfully used in the addition.
4966 */
4967 static int VARIANT_int_addlossy(
4968 DWORD * a, int * ascale, unsigned int an,
4969 DWORD * b, int * bscale, unsigned int bn)
4970 {
4971 int underflow = 0;
4972
4973 if (VARIANT_int_iszero(a, an)) {
4974 /* if A is zero, copy B into A, after removing digits */
4975 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
4976 VARIANT_int_divbychar(b, bn, 10);
4977 (*bscale)--;
4978 }
4979 memcpy(a, b, an * sizeof(DWORD));
4980 *ascale = *bscale;
4981 } else if (!VARIANT_int_iszero(b, bn)) {
4982 unsigned int tn = an + 1;
4983 DWORD t[5];
4984
4985 if (bn + 1 > tn) tn = bn + 1;
4986 if (*ascale != *bscale) {
4987 /* first (optimistic) try - try to scale down the one with the bigger
4988 scale, while this number is divisible by 10 */
4989 DWORD * digitchosen;
4990 unsigned int nchosen;
4991 int * scalechosen;
4992 int targetscale;
4993
4994 if (*ascale < *bscale) {
4995 targetscale = *ascale;
4996 scalechosen = bscale;
4997 digitchosen = b;
4998 nchosen = bn;
4999 } else {
5000 targetscale = *bscale;
5001 scalechosen = ascale;
5002 digitchosen = a;
5003 nchosen = an;
5004 }
5005 memset(t, 0, tn * sizeof(DWORD));
5006 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5007
5008 /* divide by 10 until target scale is reached */
5009 while (*scalechosen > targetscale) {
5010 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5011 if (!remainder) {
5012 (*scalechosen)--;
5013 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5014 } else break;
5015 }
5016 }
5017
5018 if (*ascale != *bscale) {
5019 DWORD * digitchosen;
5020 unsigned int nchosen;
5021 int * scalechosen;
5022 int targetscale;
5023
5024 /* try to scale up the one with the smaller scale */
5025 if (*ascale > *bscale) {
5026 targetscale = *ascale;
5027 scalechosen = bscale;
5028 digitchosen = b;
5029 nchosen = bn;
5030 } else {
5031 targetscale = *bscale;
5032 scalechosen = ascale;
5033 digitchosen = a;
5034 nchosen = an;
5035 }
5036 memset(t, 0, tn * sizeof(DWORD));
5037 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5038
5039 /* multiply by 10 until target scale is reached, or
5040 significant bytes overflow the number
5041 */
5042 while (*scalechosen < targetscale && t[nchosen] == 0) {
5043 VARIANT_int_mulbychar(t, tn, 10);
5044 if (t[nchosen] == 0) {
5045 /* still does not overflow */
5046 (*scalechosen)++;
5047 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5048 }
5049 }
5050 }
5051
5052 if (*ascale != *bscale) {
5053 /* still different? try to scale down the one with the bigger scale
5054 (this *will* lose significant digits) */
5055 DWORD * digitchosen;
5056 unsigned int nchosen;
5057 int * scalechosen;
5058 int targetscale;
5059
5060 if (*ascale < *bscale) {
5061 targetscale = *ascale;
5062 scalechosen = bscale;
5063 digitchosen = b;
5064 nchosen = bn;
5065 } else {
5066 targetscale = *bscale;
5067 scalechosen = ascale;
5068 digitchosen = a;
5069 nchosen = an;
5070 }
5071 memset(t, 0, tn * sizeof(DWORD));
5072 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5073
5074 /* divide by 10 until target scale is reached */
5075 while (*scalechosen > targetscale) {
5076 VARIANT_int_divbychar(t, tn, 10);
5077 (*scalechosen)--;
5078 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5079 }
5080 }
5081
5082 /* check whether any of the operands still has significant digits
5083 (underflow case 1)
5084 */
5085 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5086 underflow = 1;
5087 } else {
5088 /* at this step, both numbers have the same scale and can be added
5089 as integers. However, the result might not fit in A, so further
5090 scaling down might be necessary.
5091 */
5092 while (!underflow) {
5093 memset(t, 0, tn * sizeof(DWORD));
5094 memcpy(t, a, an * sizeof(DWORD));
5095
5096 VARIANT_int_add(t, tn, b, bn);
5097 if (VARIANT_int_iszero(t + an, tn - an)) {
5098 /* addition was successful */
5099 memcpy(a, t, an * sizeof(DWORD));
5100 break;
5101 } else {
5102 /* addition overflowed - remove significant digits
5103 from both operands and try again */
5104 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5105 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5106 /* check whether any operand keeps significant digits after
5107 scaledown (underflow case 2)
5108 */
5109 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5110 }
5111 }
5112 }
5113 }
5114 return underflow;
5115 }
5116
5117 /* perform complete DECIMAL division in the internal representation. Returns
5118 0 if the division was completed (even if quotient is set to 0), or nonzero
5119 in case of quotient overflow.
5120 */
5121 static HRESULT VARIANT_DI_div(VARIANT_DI * dividend, VARIANT_DI * divisor, VARIANT_DI * quotient)
5122 {
5123 HRESULT r_overflow = S_OK;
5124
5125 if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
5126 /* division by 0 */
5127 r_overflow = DISP_E_DIVBYZERO;
5128 } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
5129 VARIANT_DI_clear(quotient);
5130 } else {
5131 int quotientscale, remainderscale, tempquotientscale;
5132 DWORD remainderplusquotient[8];
5133 int underflow;
5134
5135 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5136 tempquotientscale = quotientscale;
5137 VARIANT_DI_clear(quotient);
5138 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5139
5140 /* The following strategy is used for division
5141 1) if there was a nonzero remainder from previous iteration, use it as
5142 dividend for this iteration, else (for first iteration) use intended
5143 dividend
5144 2) perform integer division in temporary buffer, develop quotient in
5145 low-order part, remainder in high-order part
5146 3) add quotient from step 2 to final result, with possible loss of
5147 significant digits
5148 4) multiply integer part of remainder by 10, while incrementing the
5149 scale of the remainder. This operation preserves the intended value
5150 of the remainder.
5151 5) loop to step 1 until one of the following is true:
5152 a) remainder is zero (exact division achieved)
5153 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5154 */
5155 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5156 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5157 do {
5158 VARIANT_int_div(
5159 remainderplusquotient, 4,
5160 divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
5161 underflow = VARIANT_int_addlossy(
5162 quotient->bitsnum, &quotientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
5163 remainderplusquotient, &tempquotientscale, 4);
5164 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5165 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5166 tempquotientscale = ++remainderscale;
5167 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5168
5169 /* quotient scale might now be negative (extremely big number). If, so, try
5170 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5171 until scale is 0. If this cannot be done, it is a real overflow.
5172 */
5173 while (!r_overflow && quotientscale < 0) {
5174 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5175 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5176 VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
5177 if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
5178 (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
5179 quotientscale++;
5180 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5181 } else r_overflow = DISP_E_OVERFLOW;
5182 }
5183 if (!r_overflow) {
5184 if (quotientscale <= 255) quotient->scale = quotientscale;
5185 else VARIANT_DI_clear(quotient);
5186 }
5187 }
5188 return r_overflow;
5189 }
5190
5191 /************************************************************************
5192 * VarDecDiv (OLEAUT32.178)
5193 *
5194 * Divide one DECIMAL by another.
5195 *
5196 * PARAMS
5197 * pDecLeft [I] Source
5198 * pDecRight [I] Value to divide by
5199 * pDecOut [O] Destination
5200 *
5201 * RETURNS
5202 * Success: S_OK.
5203 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5204 */
5205 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5206 {
5207 HRESULT hRet = S_OK;
5208 VARIANT_DI di_left, di_right, di_result;
5209 HRESULT divresult;
5210
5211 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5212
5213 VARIANT_DIFromDec(pDecLeft, &di_left);
5214 VARIANT_DIFromDec(pDecRight, &di_right);
5215 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result);
5216 if (divresult)
5217 {
5218 /* division actually overflowed */
5219 hRet = divresult;
5220 }
5221 else
5222 {
5223 hRet = S_OK;
5224
5225 if (di_result.scale > DEC_MAX_SCALE)
5226 {
5227 unsigned char remainder = 0;
5228
5229 /* division underflowed. In order to comply with the MSDN
5230 specifications for DECIMAL ranges, some significant digits
5231 must be removed
5232 */
5233 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5234 di_result.scale);
5235 while (di_result.scale > DEC_MAX_SCALE &&
5236 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
5237 {
5238 remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
5239 di_result.scale--;
5240 }
5241 if (di_result.scale > DEC_MAX_SCALE)
5242 {
5243 WARN("result underflowed, setting to 0\n");
5244 di_result.scale = 0;
5245 di_result.sign = 0;
5246 }
5247 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5248 {
5249 unsigned int i;
5250 for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
5251 ULONGLONG digit = di_result.bitsnum[i] + 1;
5252 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5253 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5254 }
5255 }
5256 }
5257 VARIANT_DecFromDI(&di_result, pDecOut);
5258 }
5259 return hRet;
5260 }
5261
5262 /************************************************************************
5263 * VarDecMul (OLEAUT32.179)
5264 *
5265 * Multiply one DECIMAL by another.
5266 *
5267 * PARAMS
5268 * pDecLeft [I] Source
5269 * pDecRight [I] Value to multiply by
5270 * pDecOut [O] Destination
5271 *
5272 * RETURNS
5273 * Success: S_OK.
5274 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5275 */
5276 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5277 {
5278 HRESULT hRet = S_OK;
5279 VARIANT_DI di_left, di_right, di_result;
5280 int mulresult;
5281
5282 VARIANT_DIFromDec(pDecLeft, &di_left);
5283 VARIANT_DIFromDec(pDecRight, &di_right);
5284 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5285 if (mulresult)
5286 {
5287 /* multiplication actually overflowed */
5288 hRet = DISP_E_OVERFLOW;
5289 }
5290 else
5291 {
5292 if (di_result.scale > DEC_MAX_SCALE)
5293 {
5294 /* multiplication underflowed. In order to comply with the MSDN
5295 specifications for DECIMAL ranges, some significant digits
5296 must be removed
5297 */
5298 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5299 di_result.scale);
5300 while (di_result.scale > DEC_MAX_SCALE &&
5301 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
5302 {
5303 VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
5304 di_result.scale--;
5305 }
5306 if (di_result.scale > DEC_MAX_SCALE)
5307 {
5308 WARN("result underflowed, setting to 0\n");
5309 di_result.scale = 0;
5310 di_result.sign = 0;
5311 }
5312 }
5313 VARIANT_DecFromDI(&di_result, pDecOut);
5314 }
5315 return hRet;
5316 }
5317
5318 /************************************************************************
5319 * VarDecSub (OLEAUT32.181)
5320 *
5321 * Subtract one DECIMAL from another.
5322 *
5323 * PARAMS
5324 * pDecLeft [I] Source
5325 * pDecRight [I] DECIMAL to subtract from pDecLeft
5326 * pDecOut [O] Destination
5327 *
5328 * RETURNS
5329 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5330 */
5331 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5332 {
5333 DECIMAL decRight;
5334
5335 /* Implement as addition of the negative */
5336 VarDecNeg(pDecRight, &decRight);
5337 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5338 }
5339
5340 /************************************************************************
5341 * VarDecAbs (OLEAUT32.182)
5342 *
5343 * Convert a DECIMAL into its absolute value.
5344 *
5345 * PARAMS
5346 * pDecIn [I] Source
5347 * pDecOut [O] Destination
5348 *
5349 * RETURNS
5350 * S_OK. This function does not fail.
5351 */
5352 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5353 {
5354 *pDecOut = *pDecIn;
5355 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5356 return S_OK;
5357 }
5358
5359 /************************************************************************
5360 * VarDecFix (OLEAUT32.187)
5361 *
5362 * Return the integer portion of a DECIMAL.
5363 *
5364 * PARAMS
5365 * pDecIn [I] Source
5366 * pDecOut [O] Destination
5367 *
5368 * RETURNS
5369 * Success: S_OK.
5370 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5371 *
5372 * NOTES
5373 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5374 * negative numbers away from 0, while this function rounds them towards zero.
5375 */
5376 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5377 {
5378 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5379 return E_INVALIDARG;
5380
5381 if (!DEC_SCALE(pDecIn))
5382 {
5383 *pDecOut = *pDecIn; /* Already an integer */
5384 return S_OK;
5385 }
5386
5387 FIXME("semi-stub!\n");
5388 return DISP_E_OVERFLOW;
5389 }
5390
5391 /************************************************************************
5392 * VarDecInt (OLEAUT32.188)
5393 *
5394 * Return the integer portion of a DECIMAL.
5395 *
5396 * PARAMS
5397 * pDecIn [I] Source
5398 * pDecOut [O] Destination
5399 *
5400 * RETURNS
5401 * Success: S_OK.
5402 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5403 *
5404 * NOTES
5405 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5406 * negative numbers towards 0, while this function rounds them away from zero.
5407 */
5408 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5409 {
5410 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5411 return E_INVALIDARG;
5412
5413 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5414 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5415
5416 FIXME("semi-stub!\n");
5417 return DISP_E_OVERFLOW;
5418 }
5419
5420 /************************************************************************
5421 * VarDecNeg (OLEAUT32.189)
5422 *
5423 * Change the sign of a DECIMAL.
5424 *
5425 * PARAMS
5426 * pDecIn [I] Source
5427 * pDecOut [O] Destination
5428 *
5429 * RETURNS
5430 * S_OK. This function does not fail.
5431 */
5432 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5433 {
5434 *pDecOut = *pDecIn;
5435 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5436 return S_OK;
5437 }
5438
5439 /************************************************************************
5440 * VarDecRound (OLEAUT32.203)
5441 *
5442 * Change the precision of a DECIMAL.
5443 *
5444 * PARAMS
5445 * pDecIn [I] Source
5446 * cDecimals [I] New number of decimals to keep
5447 * pDecOut [O] Destination
5448 *
5449 * RETURNS
5450 * Success: S_OK. pDecOut contains the rounded value.
5451 * Failure: E_INVALIDARG if any argument is invalid.
5452 */
5453 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5454 {
5455 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5456 return E_INVALIDARG;
5457
5458 if (cDecimals >= DEC_SCALE(pDecIn))
5459 {
5460 *pDecOut = *pDecIn; /* More precision than we have */
5461 return S_OK;
5462 }
5463
5464 FIXME("semi-stub!\n");
5465
5466 return DISP_E_OVERFLOW;
5467 }
5468
5469 /************************************************************************
5470 * VarDecCmp (OLEAUT32.204)
5471 *
5472 * Compare two DECIMAL values.
5473 *
5474 * PARAMS
5475 * pDecLeft [I] Source
5476 * pDecRight [I] Value to compare
5477 *
5478 * RETURNS
5479 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5480 * is less than, equal to or greater than pDecRight respectively.
5481 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5482 */
5483 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5484 {
5485 HRESULT hRet;
5486 DECIMAL result;
5487
5488 /* Subtract right from left, and compare the result to 0 */
5489 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5490
5491 if (SUCCEEDED(hRet))
5492 {
5493 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5494
5495 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5496 hRet = (HRESULT)VARCMP_LT;
5497 else if (non_zero)
5498 hRet = (HRESULT)VARCMP_GT;
5499 else
5500 hRet = (HRESULT)VARCMP_EQ;
5501 }
5502 return hRet;
5503 }
5504
5505 /************************************************************************
5506 * VarDecCmpR8 (OLEAUT32.298)
5507 *
5508 * Compare a DECIMAL to a double
5509 *
5510 * PARAMS
5511 * pDecLeft [I] DECIMAL Source
5512 * dblRight [I] double to compare to pDecLeft
5513 *
5514 * RETURNS
5515 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5516 * is less than, equal to or greater than pDecLeft respectively.
5517 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5518 */
5519 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5520 {
5521 HRESULT hRet;
5522 DECIMAL decRight;
5523
5524 hRet = VarDecFromR8(dblRight, &decRight);
5525
5526 if (SUCCEEDED(hRet))
5527 hRet = VarDecCmp(pDecLeft, &decRight);
5528
5529 return hRet;
5530 }
5531
5532 /* BOOL
5533 */
5534
5535 /************************************************************************
5536 * VarBoolFromUI1 (OLEAUT32.118)
5537 *
5538 * Convert a VT_UI1 to a VT_BOOL.
5539 *
5540 * PARAMS
5541 * bIn [I] Source
5542 * pBoolOut [O] Destination
5543 *
5544 * RETURNS
5545 * S_OK.
5546 */
5547 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5548 {
5549 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5550 return S_OK;
5551 }
5552
5553 /************************************************************************
5554 * VarBoolFromI2 (OLEAUT32.119)
5555 *
5556 * Convert a VT_I2 to a VT_BOOL.
5557 *
5558 * PARAMS
5559 * sIn [I] Source
5560 * pBoolOut [O] Destination
5561 *
5562 * RETURNS
5563 * S_OK.
5564 */
5565 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5566 {
5567 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5568 return S_OK;
5569 }
5570
5571 /************************************************************************
5572 * VarBoolFromI4 (OLEAUT32.120)
5573 *
5574 * Convert a VT_I4 to a VT_BOOL.
5575 *
5576 * PARAMS
5577 * sIn [I] Source
5578 * pBoolOut [O] Destination
5579 *
5580 * RETURNS
5581 * S_OK.
5582 */
5583 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
5584 {
5585 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
5586 return S_OK;
5587 }
5588
5589 /************************************************************************
5590 * VarBoolFromR4 (OLEAUT32.121)
5591 *
5592 * Convert a VT_R4 to a VT_BOOL.
5593 *
5594 * PARAMS
5595 * fltIn [I] Source
5596 * pBoolOut [O] Destination
5597 *
5598 * RETURNS
5599 * S_OK.
5600 */
5601 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
5602 {
5603 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
5604 return S_OK;
5605 }
5606
5607 /************************************************************************
5608 * VarBoolFromR8 (OLEAUT32.122)
5609 *
5610 * Convert a VT_R8 to a VT_BOOL.
5611 *
5612 * PARAMS
5613 * dblIn [I] Source
5614 * pBoolOut [O] Destination
5615 *
5616 * RETURNS
5617 * S_OK.
5618 */
5619 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
5620 {
5621 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
5622 return S_OK;
5623 }
5624
5625 /************************************************************************
5626 * VarBoolFromDate (OLEAUT32.123)
5627 *
5628 * Convert a VT_DATE to a VT_BOOL.
5629 *
5630 * PARAMS
5631 * dateIn [I] Source
5632 * pBoolOut [O] Destination
5633 *
5634 * RETURNS
5635 * S_OK.
5636 */
5637 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
5638 {
5639 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
5640 return S_OK;
5641 }
5642
5643 /************************************************************************
5644 * VarBoolFromCy (OLEAUT32.124)
5645 *
5646 * Convert a VT_CY to a VT_BOOL.
5647 *
5648 * PARAMS
5649 * cyIn [I] Source
5650 * pBoolOut [O] Destination
5651 *
5652 * RETURNS
5653 * S_OK.
5654 */
5655 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
5656 {
5657 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
5658 return S_OK;
5659 }
5660
5661 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
5662 {
5663 HRSRC hrsrc;
5664
5665 hrsrc = FindResourceExW( OLEAUT32_hModule, (LPWSTR)RT_STRING,
5666 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
5667 if (hrsrc)
5668 {
5669 HGLOBAL hmem = LoadResource( OLEAUT32_hModule, hrsrc );
5670
5671 if (hmem)
5672 {
5673 const WCHAR *p;
5674 unsigned int i;
5675
5676 p = LockResource( hmem );
5677 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
5678
5679 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
5680 lpszDest[*p] = '\0';
5681 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
5682 return TRUE;
5683 }
5684 }
5685 return FALSE;
5686 }
5687
5688 /************************************************************************
5689 * VarBoolFromStr (OLEAUT32.125)
5690 *
5691 * Convert a VT_BSTR to a VT_BOOL.
5692 *
5693 * PARAMS
5694 * strIn [I] Source
5695 * lcid [I] LCID for the conversion
5696 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5697 * pBoolOut [O] Destination
5698 *
5699 * RETURNS
5700 * Success: S_OK.
5701 * Failure: E_INVALIDARG, if pBoolOut is invalid.
5702 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5703 *
5704 * NOTES
5705 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
5706 * it may contain (in any case mapping) the text "true" or "false".
5707 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
5708 * localised text of "True" or "False" in the language specified by lcid.
5709 * - If none of these matches occur, the string is treated as a numeric string
5710 * and the boolean pBoolOut will be set according to whether the number is zero
5711 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
5712 * - If the text is not numeric and does not match any of the above, then
5713 * DISP_E_TYPEMISMATCH is returned.
5714 */
5715 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
5716 {
5717 /* Any VB/VBA programmers out there should recognise these strings... */
5718 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
5719 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
5720 WCHAR szBuff[64];
5721 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5722 HRESULT hRes = S_OK;
5723
5724 if (!strIn || !pBoolOut)
5725 return DISP_E_TYPEMISMATCH;
5726
5727 /* Check if we should be comparing against localised text */
5728 if (dwFlags & VAR_LOCALBOOL)
5729 {
5730 /* Convert our LCID into a usable value */
5731 lcid = ConvertDefaultLocale(lcid);
5732
5733 langId = LANGIDFROMLCID(lcid);
5734
5735 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
5736 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5737
5738 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
5739 * I don't think this is needed unless any of the localised text strings
5740 * contain characters that can be so mapped. In the event that this is
5741 * true for a given language (possibly some Asian languages), then strIn
5742 * should be mapped here _only_ if langId is an Id for which this can occur.
5743 */
5744 }
5745
5746 /* Note that if we are not comparing against localised strings, langId
5747 * will have its default value of LANG_ENGLISH. This allows us to mimic
5748 * the native behaviour of always checking against English strings even
5749 * after we've checked for localised ones.
5750 */
5751 VarBoolFromStr_CheckLocalised:
5752 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
5753 {
5754 /* Compare against localised strings, ignoring case */
5755 if (!strcmpiW(strIn, szBuff))
5756 {
5757 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
5758 return hRes;
5759 }
5760 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
5761 if (!strcmpiW(strIn, szBuff))
5762 {
5763 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
5764 return hRes;
5765 }
5766 }
5767
5768 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
5769 {
5770 /* We have checked the localised text, now check English */
5771 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
5772 goto VarBoolFromStr_CheckLocalised;
5773 }
5774
5775 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
5776 if (!strcmpW(strIn, szFalse))
5777 *pBoolOut = VARIANT_FALSE;
5778 else if (!strcmpW(strIn, szTrue))
5779 *pBoolOut = VARIANT_TRUE;
5780 else
5781 {
5782 double d;
5783
5784 /* If this string is a number, convert it as one */
5785 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
5786 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
5787 }
5788 return hRes;
5789 }
5790
5791 /************************************************************************
5792 * VarBoolFromDisp (OLEAUT32.126)
5793 *
5794 * Convert a VT_DISPATCH to a VT_BOOL.
5795 *
5796 * PARAMS
5797 * pdispIn [I] Source
5798 * lcid [I] LCID for conversion
5799 * pBoolOut [O] Destination
5800 *
5801 * RETURNS
5802 * Success: S_OK.
5803 * Failure: E_INVALIDARG, if the source value is invalid
5804 * DISP_E_OVERFLOW, if the value will not fit in the destination
5805 * DISP_E_TYPEMISMATCH, if the type cannot be converted
5806 */
5807 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
5808 {
5809 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL);
5810 }
5811
5812 /************************************************************************
5813 * VarBoolFromI1 (OLEAUT32.233)
5814 *
5815 * Convert a VT_I1 to a VT_BOOL.
5816 *
5817 * PARAMS
5818 * cIn [I] Source
5819 * pBoolOut [O] Destination
5820 *
5821 * RETURNS
5822 * S_OK.
5823 */
5824 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
5825 {
5826 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
5827 return S_OK;
5828 }
5829
5830 /************************************************************************
5831 * VarBoolFromUI2 (OLEAUT32.234)
5832 *
5833 * Convert a VT_UI2 to a VT_BOOL.
5834 *
5835 * PARAMS
5836 * usIn [I] Source
5837 * pBoolOut [O] Destination
5838 *
5839 * RETURNS
5840 * S_OK.
5841 */
5842 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
5843 {
5844 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
5845 return S_OK;
5846 }
5847
5848 /************************************************************************
5849 * VarBoolFromUI4 (OLEAUT32.235)
5850 *
5851 * Convert a VT_UI4 to a VT_BOOL.
5852 *
5853 * PARAMS
5854 * ulIn [I] Source
5855 * pBoolOut [O] Destination
5856 *
5857 * RETURNS
5858 * S_OK.
5859 */
5860 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
5861 {
5862 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
5863 return S_OK;
5864 }
5865
5866 /************************************************************************
5867 * VarBoolFromDec (OLEAUT32.236)
5868 *
5869 * Convert a VT_DECIMAL to a VT_BOOL.
5870 *
5871 * PARAMS
5872 * pDecIn [I] Source
5873 * pBoolOut [O] Destination
5874 *
5875 * RETURNS
5876 * Success: S_OK.
5877 * Failure: E_INVALIDARG, if pDecIn is invalid.
5878 */
5879 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
5880 {
5881 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
5882 return E_INVALIDARG;
5883
5884 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
5885 *pBoolOut = VARIANT_TRUE;
5886 else
5887 *pBoolOut = VARIANT_FALSE;
5888 return S_OK;
5889 }
5890
5891 /************************************************************************
5892 * VarBoolFromI8 (OLEAUT32.370)
5893 *
5894 * Convert a VT_I8 to a VT_BOOL.
5895 *
5896 * PARAMS
5897 * ullIn [I] Source
5898 * pBoolOut [O] Destination
5899 *
5900 * RETURNS
5901 * S_OK.
5902 */
5903 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
5904 {
5905 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
5906 return S_OK;
5907 }
5908
5909 /************************************************************************
5910 * VarBoolFromUI8 (OLEAUT32.371)
5911 *
5912 * Convert a VT_UI8 to a VT_BOOL.
5913 *
5914 * PARAMS
5915 * ullIn [I] Source
5916 * pBoolOut [O] Destination
5917 *
5918 * RETURNS
5919 * S_OK.
5920 */
5921 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
5922 {
5923 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
5924 return S_OK;
5925 }
5926
5927 /* BSTR
5928 */
5929
5930 /* Write a number from a UI8 and sign */
5931 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
5932 {
5933 do
5934 {
5935 WCHAR ulNextDigit = ulVal % 10;
5936
5937 *szOut-- = '0' + ulNextDigit;
5938 ulVal = (ulVal - ulNextDigit) / 10;
5939 } while (ulVal);
5940
5941 szOut++;
5942 return szOut;
5943 }
5944
5945 /* Create a (possibly localised) BSTR from a UI8 and sign */
5946 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
5947 {
5948 WCHAR szConverted[256];
5949
5950 if (dwFlags & VAR_NEGATIVE)
5951 *--szOut = '-';
5952
5953 if (dwFlags & LOCALE_USE_NLS)
5954 {
5955 /* Format the number for the locale */
5956 szConverted[0] = '\0';
5957 GetNumberFormatW(lcid,
5958 dwFlags & LOCALE_NOUSEROVERRIDE,
5959 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
5960 szOut = szConverted;
5961 }
5962 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
5963 }
5964
5965 /* Create a (possibly localised) BSTR from a UI8 and sign */
5966 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
5967 {
5968 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
5969
5970 if (!pbstrOut)
5971 return E_INVALIDARG;
5972
5973 /* Create the basic number string */
5974 *szOut-- = '\0';
5975 szOut = VARIANT_WriteNumber(ulVal, szOut);
5976
5977 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
5978 TRACE("returning %s\n", debugstr_w(*pbstrOut));
5979 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
5980 }
5981
5982 /******************************************************************************
5983 * VarBstrFromUI1 (OLEAUT32.108)
5984 *
5985 * Convert a VT_UI1 to a VT_BSTR.
5986 *
5987 * PARAMS
5988 * bIn [I] Source
5989 * lcid [I] LCID for the conversion
5990 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
5991 * pbstrOut [O] Destination
5992 *
5993 * RETURNS
5994 * Success: S_OK.
5995 * Failure: E_INVALIDARG, if pbstrOut is invalid.
5996 * E_OUTOFMEMORY, if memory allocation fails.
5997 */
5998 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
5999 {
6000 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6001 }
6002
6003 /******************************************************************************
6004 * VarBstrFromI2 (OLEAUT32.109)
6005 *
6006 * Convert a VT_I2 to a VT_BSTR.
6007 *
6008 * PARAMS
6009 * sIn [I] Source
6010 * lcid [I] LCID for the conversion
6011 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6012 * pbstrOut [O] Destination
6013 *
6014 * RETURNS
6015 * Success: S_OK.
6016 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6017 * E_OUTOFMEMORY, if memory allocation fails.
6018 */
6019 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6020 {
6021 ULONG64 ul64 = sIn;
6022
6023 if (sIn < 0)
6024 {
6025 ul64 = -sIn;
6026 dwFlags |= VAR_NEGATIVE;
6027 }
6028 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6029 }
6030
6031 /******************************************************************************
6032 * VarBstrFromI4 (OLEAUT32.110)
6033 *
6034 * Convert a VT_I4 to a VT_BSTR.
6035 *
6036 * PARAMS
6037 * lIn [I] Source
6038 * lcid [I] LCID for the conversion
6039 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6040 * pbstrOut [O] Destination
6041 *
6042 * RETURNS
6043 * Success: S_OK.
6044 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6045 * E_OUTOFMEMORY, if memory allocation fails.
6046 */
6047 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6048 {
6049 ULONG64 ul64 = lIn;
6050
6051 if (lIn < 0)
6052 {
6053 ul64 = (ULONG)-lIn;
6054 dwFlags |= VAR_NEGATIVE;
6055 }
6056 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6057 }
6058
6059 static BSTR VARIANT_BstrReplaceDecimal(WCHAR * buff, LCID lcid, ULONG dwFlags)
6060 {
6061 BSTR bstrOut;
6062 WCHAR lpDecimalSep[16];
6063
6064 /* Native oleaut32 uses the locale-specific decimal separator even in the
6065 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6066 American locales will see "one thousand and one tenth" as "1000,1"
6067 instead of "1000.1" (notice the comma). The following code checks for
6068 the need to replace the decimal separator, and if so, will prepare an
6069 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6070 */
6071 GetLocaleInfoW(lcid, LOCALE_SDECIMAL, lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
6072 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6073 {
6074 /* locale is compatible with English - return original string */
6075 bstrOut = SysAllocString(buff);
6076 }
6077 else
6078 {
6079 WCHAR *p;
6080 WCHAR numbuff[256];
6081 WCHAR empty[1] = {'\0'};
6082 NUMBERFMTW minFormat;
6083
6084 minFormat.NumDigits = 0;
6085 minFormat.LeadingZero = 0;
6086 minFormat.Grouping = 0;
6087 minFormat.lpDecimalSep = lpDecimalSep;
6088 minFormat.lpThousandSep = empty;
6089 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6090
6091 /* count number of decimal digits in string */
6092 p = strchrW( buff, '.' );
6093 if (p) minFormat.NumDigits = strlenW(p + 1);
6094
6095 numbuff[0] = '\0';
6096 if (!GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6097 buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
6098 {
6099 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6100 bstrOut = SysAllocString(buff);
6101 }
6102 else
6103 {
6104 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6105 bstrOut = SysAllocString(numbuff);
6106 }
6107 }
6108 return bstrOut;
6109 }
6110
6111 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6112 BSTR* pbstrOut, LPCWSTR lpszFormat)
6113 {
6114 WCHAR buff[256];
6115
6116 if (!pbstrOut)
6117 return E_INVALIDARG;
6118
6119 sprintfW( buff, lpszFormat, dblIn );
6120
6121 /* Negative zeroes are disallowed (some applications depend on this).
6122 If buff starts with a minus, and then nothing follows but zeroes
6123 and/or a period, it is a negative zero and is replaced with a
6124 canonical zero. This duplicates native oleaut32 behavior.
6125 */
6126 if (buff[0] == '-')
6127 {
6128 const WCHAR szAccept[] = {'0', '.', '\0'};
6129 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
6130 { buff[0] = '0'; buff[1] = '\0'; }
6131 }
6132
6133 TRACE("created string %s\n", debugstr_w(buff));
6134 if (dwFlags & LOCALE_USE_NLS)
6135 {
6136 WCHAR numbuff[256];
6137
6138 /* Format the number for the locale */
6139 numbuff[0] = '\0';
6140 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6141 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6142 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6143 *pbstrOut = SysAllocString(numbuff);
6144 }
6145 else
6146 {
6147 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6148 }
6149 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6150 }
6151
6152 /******************************************************************************
6153 * VarBstrFromR4 (OLEAUT32.111)
6154 *
6155 * Convert a VT_R4 to a VT_BSTR.
6156 *
6157 * PARAMS
6158 * fltIn [I] Source
6159 * lcid [I] LCID for the conversion
6160 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6161 * pbstrOut [O] Destination
6162 *
6163 * RETURNS
6164 * Success: S_OK.
6165 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6166 * E_OUTOFMEMORY, if memory allocation fails.
6167 */
6168 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6169 {
6170 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
6171 }
6172
6173 /******************************************************************************
6174 * VarBstrFromR8 (OLEAUT32.112)
6175 *
6176 * Convert a VT_R8 to a VT_BSTR.
6177 *
6178 * PARAMS
6179 * dblIn [I] Source
6180 * lcid [I] LCID for the conversion
6181 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6182 * pbstrOut [O] Destination
6183 *
6184 * RETURNS
6185 * Success: S_OK.
6186 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6187 * E_OUTOFMEMORY, if memory allocation fails.
6188 */
6189 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6190 {
6191 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
6192 }
6193
6194 /******************************************************************************
6195 * VarBstrFromCy [OLEAUT32.113]
6196 *
6197 * Convert a VT_CY to a VT_BSTR.
6198 *
6199 * PARAMS
6200 * cyIn [I] Source
6201 * lcid [I] LCID for the conversion
6202 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6203 * pbstrOut [O] Destination
6204 *
6205 * RETURNS
6206 * Success: S_OK.
6207 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6208 * E_OUTOFMEMORY, if memory allocation fails.
6209 */
6210 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6211 {
6212 WCHAR buff[256];
6213 double dblVal;
6214
6215 if (!pbstrOut)
6216 return E_INVALIDARG;
6217
6218 VarR8FromCy(cyIn, &dblVal);
6219 sprintfW(buff, szDoubleFormatW, dblVal);
6220
6221 if (dwFlags & LOCALE_USE_NLS)
6222 {
6223 WCHAR cybuff[256];
6224
6225 /* Format the currency for the locale */
6226 cybuff[0] = '\0';
6227 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6228 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR));
6229 *pbstrOut = SysAllocString(cybuff);
6230 }
6231 else
6232 *pbstrOut = SysAllocString(buff);
6233
6234 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6235 }
6236
6237 /******************************************************************************
6238 * VarBstrFromDate [OLEAUT32.114]
6239 *
6240 * Convert a VT_DATE to a VT_BSTR.
6241 *
6242 * PARAMS
6243 * dateIn [I] Source
6244 * lcid [I] LCID for the conversion
6245 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6246 * pbstrOut [O] Destination
6247 *
6248 * RETURNS
6249 * Success: S_OK.
6250 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6251 * E_OUTOFMEMORY, if memory allocation fails.
6252 */
6253 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6254 {
6255 SYSTEMTIME st;
6256 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6257 WCHAR date[128], *time;
6258
6259 TRACE("(%g,0x%08lx,0x%08lx,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
6260
6261 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6262 return E_INVALIDARG;
6263
6264 *pbstrOut = NULL;
6265
6266 if (dwFlags & VAR_CALENDAR_THAI)
6267 st.wYear += 553; /* Use the Thai buddhist calendar year */
6268 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6269 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6270
6271 if (dwFlags & LOCALE_USE_NLS)
6272 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6273 else
6274 {
6275 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6276 double partial = dateIn - whole;
6277
6278 if (whole == 0.0)
6279 dwFlags |= VAR_TIMEVALUEONLY;
6280 else if (partial < 1e-12)
6281 dwFlags |= VAR_DATEVALUEONLY;
6282 }
6283
6284 if (dwFlags & VAR_TIMEVALUEONLY)
6285 date[0] = '\0';
6286 else
6287 if (!GetDateFormatW(lcid, dwFormatFlags|DATE_SHORTDATE, &st, NULL, date,
6288 sizeof(date)/sizeof(WCHAR)))
6289 return E_INVALIDARG;
6290
6291 if (!(dwFlags & VAR_DATEVALUEONLY))
6292 {
6293 time = date + strlenW(date);
6294 if (time != date)
6295 *time++ = ' ';
6296 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
6297 sizeof(date)/sizeof(WCHAR)-(time-date)))
6298 return E_INVALIDARG;
6299 }
6300
6301 *pbstrOut = SysAllocString(date);
6302 if (*pbstrOut)
6303 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6304 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6305 }
6306
6307 /******************************************************************************
6308 * VarBstrFromBool (OLEAUT32.116)
6309 *
6310 * Convert a VT_BOOL to a VT_BSTR.
6311 *
6312 * PARAMS
6313 * boolIn [I] Source
6314 * lcid [I] LCID for the conversion
6315 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6316 * pbstrOut [O] Destination
6317 *
6318 * RETURNS
6319 * Success: S_OK.
6320 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6321 * E_OUTOFMEMORY, if memory allocation fails.
6322 *
6323 * NOTES
6324 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6325 * localised text of "True" or "False". To convert a bool into a
6326 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6327 */
6328 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6329 {
6330 WCHAR szBuff[64];
6331 DWORD dwResId = IDS_TRUE;
6332 LANGID langId;
6333
6334 TRACE("%d,0x%08lx,0x%08lx,%p\n", boolIn, lcid, dwFlags, pbstrOut);
6335
6336 if (!pbstrOut)
6337 return E_INVALIDARG;
6338
6339 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6340 * for variant formatting */
6341 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6342 {
6343 case VAR_BOOLONOFF:
6344 dwResId = IDS_ON;
6345 break;
6346 case VAR_BOOLYESNO:
6347 dwResId = IDS_YES;
6348 break;
6349 case VAR_LOCALBOOL:
6350 break;
6351 default:
6352 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6353 }
6354
6355 lcid = ConvertDefaultLocale(lcid);
6356 langId = LANGIDFROMLCID(lcid);
6357 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6358 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6359
6360 if (boolIn == VARIANT_FALSE)
6361 dwResId++; /* Use negative form */
6362
6363 VarBstrFromBool_GetLocalised:
6364 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6365 {
6366 *pbstrOut = SysAllocString(szBuff);
6367 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6368 }
6369
6370 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6371 {
6372 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6373 goto VarBstrFromBool_GetLocalised;
6374 }
6375
6376 /* Should never get here */
6377 WARN("Failed to load bool text!\n");
6378 return E_OUTOFMEMORY;
6379 }
6380
6381 /******************************************************************************
6382 * VarBstrFromI1 (OLEAUT32.229)
6383 *
6384 * Convert a VT_I1 to a VT_BSTR.
6385 *
6386 * PARAMS
6387 * cIn [I] Source
6388 * lcid [I] LCID for the conversion
6389 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6390 * pbstrOut [O] Destination
6391 *
6392 * RETURNS
6393 * Success: S_OK.
6394 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6395 * E_OUTOFMEMORY, if memory allocation fails.
6396 */
6397 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6398 {
6399 ULONG64 ul64 = cIn;
6400
6401 if (cIn < 0)
6402 {
6403 ul64 = -cIn;
6404 dwFlags |= VAR_NEGATIVE;
6405 }
6406 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6407 }
6408
6409 /******************************************************************************
6410 * VarBstrFromUI2 (OLEAUT32.230)
6411 *
6412 * Convert a VT_UI2 to a VT_BSTR.
6413 *
6414 * PARAMS
6415 * usIn [I] Source
6416 * lcid [I] LCID for the conversion
6417 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6418 * pbstrOut [O] Destination
6419 *
6420 * RETURNS
6421 * Success: S_OK.
6422 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6423 * E_OUTOFMEMORY, if memory allocation fails.
6424 */
6425 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6426 {
6427 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6428 }
6429
6430 /******************************************************************************
6431 * VarBstrFromUI4 (OLEAUT32.231)
6432 *
6433 * Convert a VT_UI4 to a VT_BSTR.
6434 *
6435 * PARAMS
6436 * ulIn [I] Source
6437 * lcid [I] LCID for the conversion
6438 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6439 * pbstrOut [O] Destination
6440 *
6441 * RETURNS
6442 * Success: S_OK.
6443 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6444 * E_OUTOFMEMORY, if memory allocation fails.
6445 */
6446 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6447 {
6448 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
6449 }
6450
6451 /******************************************************************************
6452 * VarBstrFromDec (OLEAUT32.232)
6453 *
6454 * Convert a VT_DECIMAL to a VT_BSTR.
6455 *
6456 * PARAMS
6457 * pDecIn [I] Source
6458 * lcid [I] LCID for the conversion
6459 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6460 * pbstrOut [O] Destination
6461 *
6462 * RETURNS
6463 * Success: S_OK.
6464 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6465 * E_OUTOFMEMORY, if memory allocation fails.
6466 */
6467 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6468 {
6469 WCHAR buff[256];
6470 VARIANT_DI temp;
6471
6472 if (!pbstrOut)
6473 return E_INVALIDARG;
6474
6475 VARIANT_DIFromDec(pDecIn, &temp);
6476 VARIANT_DI_tostringW(&temp, buff, 256);
6477
6478 if (dwFlags & LOCALE_USE_NLS)
6479 {
6480 WCHAR numbuff[256];
6481
6482 /* Format the number for the locale */
6483 numbuff[0] = '\0';
6484 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6485 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6486 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6487 *pbstrOut = SysAllocString(numbuff);
6488 }
6489 else
6490 {
6491 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6492 }
6493
6494 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6495 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6496 }
6497
6498 /************************************************************************
6499 * VarBstrFromI8 (OLEAUT32.370)
6500 *
6501 * Convert a VT_I8 to a VT_BSTR.
6502 *
6503 * PARAMS
6504 * llIn [I] Source
6505 * lcid [I] LCID for the conversion
6506 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6507 * pbstrOut [O] Destination
6508 *
6509 * RETURNS
6510 * Success: S_OK.
6511 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6512 * E_OUTOFMEMORY, if memory allocation fails.
6513 */
6514 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6515 {
6516 ULONG64 ul64 = llIn;
6517
6518 if (llIn < 0)
6519 {
6520 ul64 = -llIn;
6521 dwFlags |= VAR_NEGATIVE;
6522 }
6523 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6524 }
6525
6526 /************************************************************************
6527 * VarBstrFromUI8 (OLEAUT32.371)
6528 *
6529 * Convert a VT_UI8 to a VT_BSTR.
6530 *
6531 * PARAMS
6532 * ullIn [I] Source
6533 * lcid [I] LCID for the conversion
6534 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6535 * pbstrOut [O] Destination
6536 *
6537 * RETURNS
6538 * Success: S_OK.
6539 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6540 * E_OUTOFMEMORY, if memory allocation fails.
6541 */
6542 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6543 {
6544 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
6545 }
6546
6547 /**********************************************************************
6548 * VarBstrCat (OLEAUT32.313)
6549 *
6550 * Concatenate two BSTR values.
6551 *
6552 * PARAMS
6553 * pbstrLeft [I] Source
6554 * pbstrRight [I] Value to concatenate
6555 * pbstrOut [O] Destination
6556 *
6557 * RETURNS
6558 * Success: S_OK.
6559 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6560 * E_OUTOFMEMORY, if memory allocation fails.
6561 */
6562 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
6563 {
6564 unsigned int len;
6565
6566 if (!pbstrOut)
6567 return E_INVALIDARG;
6568
6569 len = pbstrLeft ? strlenW(pbstrLeft) : 0;
6570 if (pbstrRight)
6571 len += strlenW(pbstrRight);
6572
6573 *pbstrOut = SysAllocStringLen(NULL, len);
6574 if (!*pbstrOut)
6575 return E_OUTOFMEMORY;
6576
6577 (*pbstrOut)[0] = '\0';
6578
6579 if (pbstrLeft)
6580 strcpyW(*pbstrOut, pbstrLeft);
6581
6582 if (pbstrRight)
6583 strcatW(*pbstrOut, pbstrRight);
6584
6585 return S_OK;
6586 }
6587
6588 /**********************************************************************
6589 * VarBstrCmp (OLEAUT32.314)
6590 *
6591 * Compare two BSTR values.
6592 *
6593 * PARAMS
6594 * pbstrLeft [I] Source
6595 * pbstrRight [I] Value to compare
6596 * lcid [I] LCID for the comparison
6597 * dwFlags [I] Flags to pass directly to CompareStringW().
6598 *
6599 * RETURNS
6600 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
6601 * than, equal to or greater than pbstrRight respectively.
6602 *
6603 * NOTES
6604 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
6605 * states. A NULL BSTR pointer is equivalent to an empty string.
6606 */
6607 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
6608 {
6609 if (!pbstrLeft || !*pbstrLeft)
6610 {
6611 if (!pbstrRight || !*pbstrRight)
6612 return VARCMP_EQ;
6613 return VARCMP_LT;
6614 }
6615 else if (!pbstrRight || !*pbstrRight)
6616 return VARCMP_GT;
6617
6618 return CompareStringW(lcid, dwFlags, pbstrLeft, -1, pbstrRight, -1) - 1;
6619 }
6620
6621 /*
6622 * DATE
6623 */
6624
6625 /******************************************************************************
6626 * VarDateFromUI1 (OLEAUT32.88)
6627 *
6628 * Convert a VT_UI1 to a VT_DATE.
6629 *
6630 * PARAMS
6631 * bIn [I] Source
6632 * pdateOut [O] Destination
6633 *
6634 * RETURNS
6635 * S_OK.
6636 */
6637 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
6638 {
6639 return VarR8FromUI1(bIn, pdateOut);
6640 }
6641
6642 /******************************************************************************
6643 * VarDateFromI2 (OLEAUT32.89)
6644 *
6645 * Convert a VT_I2 to a VT_DATE.
6646 *
6647 * PARAMS
6648 * sIn [I] Source
6649 * pdateOut [O] Destination
6650 *
6651 * RETURNS
6652 * S_OK.
6653 */
6654 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
6655 {
6656 return VarR8FromI2(sIn, pdateOut);
6657 }
6658
6659 /******************************************************************************
6660 * VarDateFromI4 (OLEAUT32.90)
6661 *
6662 * Convert a VT_I4 to a VT_DATE.
6663 *
6664 * PARAMS
6665 * lIn [I] Source
6666 * pdateOut [O] Destination
6667 *
6668 * RETURNS
6669 * S_OK.
6670 */
6671 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
6672 {
6673 return VarDateFromR8(lIn, pdateOut);
6674 }
6675
6676 /******************************************************************************
6677 * VarDateFromR4 (OLEAUT32.91)
6678 *
6679 * Convert a VT_R4 to a VT_DATE.
6680 *
6681 * PARAMS
6682 * fltIn [I] Source
6683 * pdateOut [O] Destination
6684 *
6685 * RETURNS
6686 * S_OK.
6687 */
6688 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
6689 {
6690 return VarR8FromR4(fltIn, pdateOut);
6691 }
6692
6693 /******************************************************************************
6694 * VarDateFromR8 (OLEAUT32.92)
6695 *
6696 * Convert a VT_R8 to a VT_DATE.
6697 *
6698 * PARAMS
6699 * dblIn [I] Source
6700 * pdateOut [O] Destination
6701 *
6702 * RETURNS
6703 * S_OK.
6704 */
6705 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
6706 {
6707 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
6708 *pdateOut = (DATE)dblIn;
6709 return S_OK;
6710 }
6711
6712 /**********************************************************************
6713 * VarDateFromDisp (OLEAUT32.95)
6714 *
6715 * Convert a VT_DISPATCH to a VT_DATE.
6716 *
6717 * PARAMS
6718 * pdispIn [I] Source
6719 * lcid [I] LCID for conversion
6720 * pdateOut [O] Destination
6721 *
6722 * RETURNS
6723 * Success: S_OK.
6724 * Failure: E_INVALIDARG, if the source value is invalid
6725 * DISP_E_OVERFLOW, if the value will not fit in the destination
6726 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6727 */
6728 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
6729 {
6730 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE);
6731 }
6732
6733 /******************************************************************************
6734 * VarDateFromBool (OLEAUT32.96)
6735 *
6736 * Convert a VT_BOOL to a VT_DATE.
6737 *
6738 * PARAMS
6739 * boolIn [I] Source
6740 * pdateOut [O] Destination
6741 *
6742 * RETURNS
6743 * S_OK.
6744 */
6745 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
6746 {
6747 return VarR8FromBool(boolIn, pdateOut);
6748 }
6749
6750 /**********************************************************************
6751 * VarDateFromCy (OLEAUT32.93)
6752 *
6753 * Convert a VT_CY to a VT_DATE.
6754 *
6755 * PARAMS
6756 * lIn [I] Source
6757 * pdateOut [O] Destination
6758 *
6759 * RETURNS
6760 * S_OK.
6761 */
6762 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
6763 {
6764 return VarR8FromCy(cyIn, pdateOut);
6765 }
6766
6767 /* Date string parsing */
6768 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
6769 #define DP_DATESEP 0x02 /* Date separator */
6770 #define DP_MONTH 0x04 /* Month name */
6771 #define DP_AM 0x08 /* AM */
6772 #define DP_PM 0x10 /* PM */
6773
6774 typedef struct tagDATEPARSE
6775 {
6776 DWORD dwCount; /* Number of fields found so far (maximum 6) */
6777 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
6778 DWORD dwFlags[6]; /* Flags for each field */
6779 DWORD dwValues[6]; /* Value of each field */
6780 } DATEPARSE;
6781
6782 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
6783
6784 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
6785
6786 /* Determine if a day is valid in a given month of a given year */
6787 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
6788 {
6789 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
6790
6791 if (day && month && month < 13)
6792 {
6793 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
6794 return TRUE;
6795 }
6796 return FALSE;
6797 }
6798
6799 /* Possible orders for 3 numbers making up a date */
6800 #define ORDER_MDY 0x01
6801 #define ORDER_YMD 0x02
6802 #define ORDER_YDM 0x04
6803 #define ORDER_DMY 0x08
6804 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
6805
6806 /* Determine a date for a particular locale, from 3 numbers */
6807 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
6808 DWORD offset, SYSTEMTIME *st)
6809 {
6810 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
6811
6812 if (!dp->dwCount)
6813 {
6814 v1 = 30; /* Default to (Variant) 0 date part */
6815 v2 = 12;
6816 v3 = 1899;
6817 goto VARIANT_MakeDate_OK;
6818 }
6819
6820 v1 = dp->dwValues[offset + 0];
6821 v2 = dp->dwValues[offset + 1];
6822 if (dp->dwCount == 2)
6823 {
6824 SYSTEMTIME current;
6825 GetSystemTime(&current);
6826 v3 = current.wYear;
6827 }
6828 else
6829 v3 = dp->dwValues[offset + 2];
6830
6831 TRACE("(%ld,%ld,%ld,%ld,%ld)\n", v1, v2, v3, iDate, offset);
6832
6833 /* If one number must be a month (Because a month name was given), then only
6834 * consider orders with the month in that position.
6835 * If we took the current year as 'v3', then only allow a year in that position.
6836 */
6837 if (dp->dwFlags[offset + 0] & DP_MONTH)
6838 {
6839 dwAllOrders = ORDER_MDY;
6840 }
6841 else if (dp->dwFlags[offset + 1] & DP_MONTH)
6842 {
6843 dwAllOrders = ORDER_DMY;
6844 if (dp->dwCount > 2)
6845 dwAllOrders |= ORDER_YMD;
6846 }
6847 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
6848 {
6849 dwAllOrders = ORDER_YDM;
6850 }
6851 else
6852 {
6853 dwAllOrders = ORDER_MDY|ORDER_DMY;
6854 if (dp->dwCount > 2)
6855 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
6856 }
6857
6858 VARIANT_MakeDate_Start:
6859 TRACE("dwAllOrders is 0x%08lx\n", dwAllOrders);
6860
6861 while (dwAllOrders)
6862 {
6863 DWORD dwTemp;
6864
6865 if (dwCount == 0)
6866 {
6867 /* First: Try the order given by iDate */
6868 switch (iDate)
6869 {
6870 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
6871 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
6872 default: dwTry = dwAllOrders & ORDER_YMD; break;
6873 }
6874 }
6875 else if (dwCount == 1)
6876 {
6877 /* Second: Try all the orders compatible with iDate */
6878 switch (iDate)
6879 {
6880 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
6881 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break;
6882 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
6883 }
6884 }
6885 else
6886 {
6887 /* Finally: Try any remaining orders */
6888 dwTry = dwAllOrders;
6889 }
6890
6891 TRACE("Attempt %ld, dwTry is 0x%08lx\n", dwCount, dwTry);
6892
6893 dwCount++;
6894 if (!dwTry)
6895 continue;
6896
6897 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
6898
6899 if (dwTry & ORDER_MDY)
6900 {
6901 if (VARIANT_IsValidMonthDay(v2,v1,v3))
6902 {
6903 DATE_SWAP(v1,v2);
6904 goto VARIANT_MakeDate_OK;
6905 }
6906 dwAllOrders &= ~ORDER_MDY;
6907 }
6908 if (dwTry & ORDER_YMD)
6909 {
6910 if (VARIANT_IsValidMonthDay(v3,v2,v1))
6911 {
6912 DATE_SWAP(v1,v3);
6913 goto VARIANT_MakeDate_OK;
6914 }
6915 dwAllOrders &= ~ORDER_YMD;
6916 }
6917 if (dwTry & ORDER_YDM)
6918 {
6919 if (VARIANT_IsValidMonthDay(v2,v3,v1))
6920 {
6921 DATE_SWAP(v1,v2);
6922 DATE_SWAP(v2,v3);
6923 goto VARIANT_MakeDate_OK;
6924 }
6925 dwAllOrders &= ~ORDER_YDM;
6926 }
6927 if (dwTry & ORDER_DMY)
6928 {
6929 if (VARIANT_IsValidMonthDay(v1,v2,v3))
6930 goto VARIANT_MakeDate_OK;
6931 dwAllOrders &= ~ORDER_DMY;
6932 }
6933 if (dwTry & ORDER_MYD)
6934 {
6935 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
6936 if (VARIANT_IsValidMonthDay(v3,v1,v2))
6937 {
6938 DATE_SWAP(v1,v3);
6939 DATE_SWAP(v2,v3);
6940 goto VARIANT_MakeDate_OK;
6941 }
6942 dwAllOrders &= ~ORDER_MYD;
6943 }
6944 }
6945
6946 if (dp->dwCount == 2)
6947 {
6948 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
6949 v3 = 1; /* 1st of the month */
6950 dwAllOrders = ORDER_YMD|ORDER_MYD;
6951 dp->dwCount = 0; /* Don't return to this code path again */
6952 dwCount = 0;
6953 goto VARIANT_MakeDate_Start;
6954 }
6955
6956 /* No valid dates were able to be constructed */
6957 return DISP_E_TYPEMISMATCH;
6958
6959 VARIANT_MakeDate_OK:
6960
6961 /* Check that the time part is ok */
6962 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
6963 return DISP_E_TYPEMISMATCH;
6964
6965 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
6966 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
6967 st->wHour += 12;
6968 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
6969 st->wHour = 0;
6970 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
6971
6972 st->wDay = v1;
6973 st->wMonth = v2;
6974 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
6975 * be retrieved from:
6976 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
6977 * But Wine doesn't have/use that key as at the time of writing.
6978 */
6979 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
6980 TRACE("Returning date %ld/%ld/%d\n", v1, v2, st->wYear);
6981 return S_OK;
6982 }
6983
6984 /******************************************************************************
6985 * VarDateFromStr [OLEAUT32.94]
6986 *
6987 * Convert a VT_BSTR to at VT_DATE.
6988 *
6989 * PARAMS
6990 * strIn [I] String to convert
6991 * lcid [I] Locale identifier for the conversion
6992 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
6993 * pdateOut [O] Destination for the converted value
6994 *
6995 * RETURNS
6996 * Success: S_OK. pdateOut contains the converted value.
6997 * FAILURE: An HRESULT error code indicating the prolem.
6998 *
6999 * NOTES
7000 * Any date format that can be created using the date formats from lcid
7001 * (Either from kernel Nls functions, variant conversion or formatting) is a
7002 * valid input to this function. In addition, a few more esoteric formats are
7003 * also supported for compatibility with the native version. The date is
7004 * interpreted according to the date settings in the control panel, unless
7005 * the date is invalid in that format, in which the most compatible format
7006 * that produces a valid date will be used.
7007 */
7008 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7009 {
7010 static const USHORT ParseDateTokens[] =
7011 {
7012 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7013 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7014 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7015 LOCALE_SMONTHNAME13,
7016 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7017 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7018 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7019 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7020 LOCALE_SABBREVMONTHNAME13,
7021 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7022 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7023 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7024 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7025 LOCALE_SABBREVDAYNAME7,
7026 LOCALE_S1159, LOCALE_S2359
7027 };
7028 static const BYTE ParseDateMonths[] =
7029 {
7030 1,2,3,4,5,6,7,8,9,10,11,12,13,
7031 1,2,3,4,5,6,7,8,9,10,11,12,13
7032 };
7033 size_t i;
7034 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
7035 DATEPARSE dp;
7036 DWORD dwDateSeps = 0, iDate = 0;
7037 HRESULT hRet = S_OK;
7038
7039 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7040 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7041 return E_INVALIDARG;
7042
7043 if (!strIn)
7044 return DISP_E_TYPEMISMATCH;
7045
7046 *pdateOut = 0.0;
7047
7048 TRACE("(%s,0x%08lx,0x%08lx,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7049
7050 memset(&dp, 0, sizeof(dp));
7051
7052 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7053 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7054 TRACE("iDate is %ld\n", iDate);
7055
7056 /* Get the month/day/am/pm tokens for this locale */
7057 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7058 {
7059 WCHAR buff[128];
7060 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7061
7062 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7063 * GetAltMonthNames(). We should really cache these strings too.
7064 */
7065 buff[0] = '\0';
7066 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
7067 tokens[i] = SysAllocString(buff);
7068 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7069 }
7070
7071 /* Parse the string into our structure */
7072 while (*strIn)
7073 {
7074 if (dp.dwCount > 6)
7075 break;
7076
7077 if (isdigitW(*strIn))
7078 {
7079 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
7080 dp.dwCount++;
7081 strIn--;
7082 }
7083 else if (isalpha(*strIn))
7084 {
7085 BOOL bFound = FALSE;
7086
7087 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7088 {
7089 DWORD dwLen = strlenW(tokens[i]);
7090 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
7091 {
7092 if (i <= 25)
7093 {
7094 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7095 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7096 dp.dwCount++;
7097 }
7098 else if (i > 39)
7099 {
7100 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7101 hRet = DISP_E_TYPEMISMATCH;
7102 else
7103 {
7104 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7105 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7106 }
7107 }
7108 strIn += (dwLen - 1);
7109 bFound = TRUE;
7110 break;
7111 }
7112 }
7113
7114 if (!bFound)
7115 {
7116 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7117 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7118 {
7119 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7120 if (*strIn == 'a' || *strIn == 'A')
7121 {
7122 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7123 dp.dwParseFlags |= DP_AM;
7124 }
7125 else
7126 {
7127 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7128 dp.dwParseFlags |= DP_PM;
7129 }
7130 strIn++;
7131 }
7132 else
7133 {
7134 TRACE("No matching token for %s\n", debugstr_w(strIn));
7135 hRet = DISP_E_TYPEMISMATCH;
7136 break;
7137 }
7138 }
7139 }
7140 else if (*strIn == ':' || *strIn == '.')
7141 {
7142 if (!dp.dwCount || !strIn[1])
7143 hRet = DISP_E_TYPEMISMATCH;
7144 else
7145 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7146 }
7147 else if (*strIn == '-' || *strIn == '/')
7148 {
7149 dwDateSeps++;
7150 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7151 hRet = DISP_E_TYPEMISMATCH;
7152 else
7153 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7154 }
7155 else if (*strIn == ',' || isspaceW(*strIn))
7156 {
7157 if (*strIn == ',' && !strIn[1])
7158 hRet = DISP_E_TYPEMISMATCH;
7159 }
7160 else
7161 {
7162 hRet = DISP_E_TYPEMISMATCH;
7163 }
7164 strIn++;
7165 }
7166
7167 if (!dp.dwCount || dp.dwCount > 6 ||
7168 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7169 hRet = DISP_E_TYPEMISMATCH;
7170
7171 if (SUCCEEDED(hRet))
7172 {
7173 SYSTEMTIME st;
7174 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7175
7176 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7177
7178 /* Figure out which numbers correspond to which fields.
7179 *
7180 * This switch statement works based on the fact that native interprets any
7181 * fields that are not joined with a time separator ('.' or ':') as date
7182 * fields. Thus we construct a value from 0-32 where each set bit indicates
7183 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7184 * For valid permutations, we set dwOffset to point to the first date field
7185 * and shorten dp.dwCount by the number of time fields found. The real
7186 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7187 * each date number must represent in the context of iDate.
7188 */
7189 TRACE("0x%08lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7190
7191 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7192 {
7193 case 0x1: /* TT TTDD TTDDD */
7194 if (dp.dwCount > 3 &&
7195 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7196 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7197 hRet = DISP_E_TYPEMISMATCH;
7198 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7199 hRet = DISP_E_TYPEMISMATCH;
7200 st.wHour = dp.dwValues[0];
7201 st.wMinute = dp.dwValues[1];
7202 dp.dwCount -= 2;
7203 dwOffset = 2;
7204 break;
7205
7206 case 0x3: /* TTT TTTDD TTTDDD */
7207 if (dp.dwCount > 4 &&
7208 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7209 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7210 hRet = DISP_E_TYPEMISMATCH;
7211 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7212 hRet = DISP_E_TYPEMISMATCH;
7213 st.wHour = dp.dwValues[0];
7214 st.wMinute = dp.dwValues[1];
7215 st.wSecond = dp.dwValues[2];
7216 dwOffset = 3;
7217 dp.dwCount -= 3;
7218 break;
7219
7220 case 0x4: /* DDTT */
7221 if (dp.dwCount != 4 ||
7222 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7223 hRet = DISP_E_TYPEMISMATCH;
7224
7225 st.wHour = dp.dwValues[2];
7226 st.wMinute = dp.dwValues[3];
7227 dp.dwCount -= 2;
7228 break;
7229
7230 case 0x0: /* T DD DDD TDDD TDDD */
7231 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7232 {
7233 st.wHour = dp.dwValues[0]; /* T */
7234 dp.dwCount = 0;
7235 break;
7236 }
7237 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7238 {
7239 hRet = DISP_E_TYPEMISMATCH;
7240 }
7241 else if (dp.dwCount == 3)
7242 {
7243 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7244 {
7245 dp.dwCount = 2;
7246 st.wHour = dp.dwValues[0];
7247 dwOffset = 1;
7248 break;
7249 }
7250 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7251 {
7252 dp.dwCount = 2;
7253 st.wHour = dp.dwValues[2];
7254 break;
7255 }
7256 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7257 hRet = DISP_E_TYPEMISMATCH;
7258 }
7259 else if (dp.dwCount == 4)
7260 {
7261 dp.dwCount = 3;
7262 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7263 {
7264 st.wHour = dp.dwValues[0];
7265 dwOffset = 1;
7266 }
7267 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7268 {
7269 st.wHour = dp.dwValues[3];
7270 }
7271 else
7272 hRet = DISP_E_TYPEMISMATCH;
7273 break;
7274 }
7275 /* .. fall through .. */
7276
7277 case 0x8: /* DDDTT */
7278 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7279 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7280 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7281 dp.dwCount == 4 || dp.dwCount == 6)
7282 hRet = DISP_E_TYPEMISMATCH;
7283 st.wHour = dp.dwValues[3];
7284 st.wMinute = dp.dwValues[4];
7285 if (dp.dwCount == 5)
7286 dp.dwCount -= 2;
7287 break;
7288
7289 case 0xC: /* DDTTT */
7290 if (dp.dwCount != 5 ||
7291 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7292 hRet = DISP_E_TYPEMISMATCH;
7293 st.wHour = dp.dwValues[2];
7294 st.wMinute = dp.dwValues[3];
7295 st.wSecond = dp.dwValues[4];
7296 dp.dwCount -= 3;
7297 break;
7298
7299 case 0x18: /* DDDTTT */
7300 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7301 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7302 hRet = DISP_E_TYPEMISMATCH;
7303 st.wHour = dp.dwValues[3];
7304 st.wMinute = dp.dwValues[4];
7305 st.wSecond = dp.dwValues[5];
7306 dp.dwCount -= 3;
7307 break;
7308
7309 default:
7310 hRet = DISP_E_TYPEMISMATCH;
7311 break;
7312 }
7313
7314 if (SUCCEEDED(hRet))
7315 {
7316 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7317
7318 if (dwFlags & VAR_TIMEVALUEONLY)
7319 {
7320 st.wYear = 1899;
7321 st.wMonth = 12;
7322 st.wDay = 30;
7323 }
7324 else if (dwFlags & VAR_DATEVALUEONLY)
7325 st.wHour = st.wMinute = st.wSecond = 0;
7326
7327 /* Finally, convert the value to a VT_DATE */
7328 if (SUCCEEDED(hRet))
7329 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7330 }
7331 }
7332
7333 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7334 SysFreeString(tokens[i]);
7335 return hRet;
7336 }
7337
7338 /******************************************************************************
7339 * VarDateFromI1 (OLEAUT32.221)
7340 *
7341 * Convert a VT_I1 to a VT_DATE.
7342 *
7343 * PARAMS
7344 * cIn [I] Source
7345 * pdateOut [O] Destination
7346 *
7347 * RETURNS
7348 * S_OK.
7349 */
7350 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7351 {
7352 return VarR8FromI1(cIn, pdateOut);
7353 }
7354
7355 /******************************************************************************
7356 * VarDateFromUI2 (OLEAUT32.222)
7357 *
7358 * Convert a VT_UI2 to a VT_DATE.
7359 *
7360 * PARAMS
7361 * uiIn [I] Source
7362 * pdateOut [O] Destination
7363 *
7364 * RETURNS
7365 * S_OK.
7366 */
7367 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7368 {
7369 return VarR8FromUI2(uiIn, pdateOut);
7370 }
7371
7372 /******************************************************************************
7373 * VarDateFromUI4 (OLEAUT32.223)
7374 *
7375 * Convert a VT_UI4 to a VT_DATE.
7376 *
7377 * PARAMS
7378 * ulIn [I] Source
7379 * pdateOut [O] Destination
7380 *
7381 * RETURNS
7382 * S_OK.
7383 */
7384 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7385 {
7386 return VarDateFromR8(ulIn, pdateOut);
7387 }
7388
7389 /**********************************************************************
7390 * VarDateFromDec (OLEAUT32.224)
7391 *
7392 * Convert a VT_DECIMAL to a VT_DATE.
7393 *
7394 * PARAMS
7395 * pdecIn [I] Source
7396 * pdateOut [O] Destination
7397 *
7398 * RETURNS
7399 * S_OK.
7400 */
7401 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
7402 {
7403 return VarR8FromDec(pdecIn, pdateOut);
7404 }
7405
7406 /******************************************************************************
7407 * VarDateFromI8 (OLEAUT32.364)
7408 *
7409 * Convert a VT_I8 to a VT_DATE.
7410 *
7411 * PARAMS
7412 * llIn [I] Source
7413 * pdateOut [O] Destination
7414 *
7415 * RETURNS
7416 * Success: S_OK.
7417 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7418 */
7419 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
7420 {
7421 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
7422 *pdateOut = (DATE)llIn;
7423 return S_OK;
7424 }
7425
7426 /******************************************************************************
7427 * VarDateFromUI8 (OLEAUT32.365)
7428 *
7429 * Convert a VT_UI8 to a VT_DATE.
7430 *
7431 * PARAMS
7432 * ullIn [I] Source
7433 * pdateOut [O] Destination
7434 *
7435 * RETURNS
7436 * Success: S_OK.
7437 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7438 */
7439 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
7440 {
7441 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
7442 *pdateOut = (DATE)ullIn;
7443 return S_OK;
7444 }