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