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