Use the current window visual only.
[wine] / dlls / oleaut32 / variant.c
1 /*
2  * VARIANT
3  *
4  * Copyright 1998 Jean-Claude Cote
5  * Copyright 2003 Jon Griffiths
6  * The alorithm for conversion from Julian days to day/month/year is based on
7  * that devised by Henry Fliegel, as implemented in PostgreSQL, which is
8  * Copyright 1994-7 Regents of the University of California
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  * NOTES
25  *   This implements the low-level and hi-level APIs for manipulating VARIANTs.
26  *   The low-level APIs are used to do data coercion between different data types.
27  *   The hi-level APIs are built on top of these low-level APIs and handle
28  *   initialization, copying, destroying and changing the type of VARIANTs.
29  *
30  * TODO:
31  *   - The Variant APIs do not support international languages, currency
32  *     types, number formating and calendar.  They only support U.S. English format.
33  *   - The Variant APIs do not the following types: IUknown, IDispatch, DECIMAL and SafeArray.
34  *   - The parsing of date for the VarDateFromStr is not complete.
35  *   - The date manipulations do not support dates prior to 1900.
36  *   - The parsing does not accept as many formats as the Windows implementation.
37  */
38
39 #include "config.h"
40
41 #include <string.h>
42 #include <stdlib.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <math.h>
46 #include <time.h>
47
48 #ifdef HAVE_FLOAT_H
49 # include <float.h>
50 #endif
51
52 #define NONAMELESSUNION
53 #define NONAMELESSSTRUCT
54 #include "windef.h"
55 #include "winbase.h"
56 #include "oleauto.h"
57 #include "winreg.h"
58 #include "heap.h"
59 #include "wine/debug.h"
60 #include "wine/unicode.h"
61 #include "winerror.h"
62 #include "parsedt.h"
63 #include "typelib.h"
64 #include "winternl.h"
65 #include "variant.h"
66
67 WINE_DEFAULT_DEBUG_CHANNEL(ole);
68
69 #define SYSDUPSTRING(str) SysAllocStringByteLen((LPCSTR)(str), SysStringByteLen(str))
70
71 /* Flags set in V_VT, other than the actual type value */
72 #define VT_EXTRA_TYPE (VT_VECTOR|VT_ARRAY|VT_BYREF|VT_RESERVED)
73
74 /* Get the extra flags from a variant pointer */
75 #define V_EXTRA_TYPE(v) (V_VT(v) & VT_EXTRA_TYPE)
76
77 /* the largest valid type
78  */
79 #define VT_MAXVALIDTYPE VT_CLSID
80
81 /* This mask is used to set a flag in wReserved1 of
82  * the VARIANTARG structure. The flag indicates if
83  * the API function is using an inner variant or not.
84  */
85 #define PROCESSING_INNER_VARIANT 0x0001
86
87 /* General use buffer.
88  */
89 #define BUFFER_MAX 1024
90 static char pBuffer[BUFFER_MAX];
91
92 /*
93  * Note a leap year is one that is a multiple of 4
94  * but not of a 100.  Except if it is a multiple of
95  * 400 then it is a leap year.
96  */
97
98 /*
99  * Use 365 days/year and a manual calculation for leap year days
100  * to keep arithmetic simple
101  */
102 static const double DAYS_IN_ONE_YEAR = 365.0;
103
104 /*
105  * Token definitions for Varient Formatting
106  * Worked out by experimentation on a w2k machine. Doesnt appear to be
107  *   documented anywhere obviously so keeping definitions internally
108  *
109  */
110 /* Pre defined tokens */
111 #define TOK_COPY 0x00
112 #define TOK_END  0x02
113 #define LARGEST_TOKENID 6
114
115 /* Mapping of token name to id put into the tokenized form
116    Note testing on W2K shows aaaa and oooo are not parsed??!! */
117 #define TOK_COLON  0x03
118 #define TOK_SLASH  0x04
119 #define TOK_c      0x05
120 #define TOK_d      0x08
121 #define TOK_dd     0x09
122 #define TOK_ddd    0x0a
123 #define TOK_dddd   0x0b
124 #define TOK_ddddd  0x0c
125 #define TOK_dddddd 0x0d
126 #define TOK_w      0x0f
127 #define TOK_ww     0x10
128 #define TOK_m      0x11
129 #define TOK_mm     0x12
130 #define TOK_mmm    0x13
131 #define TOK_mmmm   0x14
132 #define TOK_q      0x06
133 #define TOK_y      0x15
134 #define TOK_yy     0x16
135 #define TOK_yyyy   0x18
136 #define TOK_h      0x1e
137 #define TOK_Hh     0x1f
138 #define TOK_N      0x1a
139 #define TOK_Nn     0x1b
140 #define TOK_S      0x1c
141 #define TOK_Ss     0x1d
142 #define TOK_ttttt  0x07
143 #define TOK_AMsPM  0x2f
144 #define TOK_amspm  0x32
145 #define TOK_AsP    0x30
146 #define TOK_asp    0x33
147 #define TOK_AMPM   0x2e
148
149 typedef struct tagFORMATTOKEN {
150     const char  *str;
151     BYTE        tokenSize;
152     BYTE        tokenId;
153     int         varTypeRequired;
154 } FORMATTOKEN;
155
156 typedef struct tagFORMATHDR {
157     BYTE   len;
158     BYTE   hex3;
159     BYTE   hex6;
160     BYTE   reserved[8];
161 } FORMATHDR;
162
163 FORMATTOKEN formatTokens[] = {           /* FIXME: Only date formats so far */
164     {":"     ,   1,  TOK_COLON  , 0},
165     {"/"     ,   1,  TOK_SLASH  , 0},
166     {"c"     ,   1,  TOK_c      , VT_DATE},
167     {"dddddd",   6,  TOK_dddddd , VT_DATE},
168     {"ddddd" ,   5,  TOK_ddddd  , VT_DATE},
169     {"dddd"  ,   4,  TOK_dddd   , VT_DATE},
170     {"ddd"   ,   3,  TOK_ddd    , VT_DATE},
171     {"dd"    ,   2,  TOK_dd     , VT_DATE},
172     {"d"     ,   1,  TOK_d      , VT_DATE},
173     {"ww"    ,   2,  TOK_ww     , VT_DATE},
174     {"w"     ,   1,  TOK_w      , VT_DATE},
175     {"mmmm"  ,   4,  TOK_mmmm   , VT_DATE},
176     {"mmm"   ,   3,  TOK_mmm    , VT_DATE},
177     {"mm"    ,   2,  TOK_mm     , VT_DATE},
178     {"m"     ,   1,  TOK_m      , VT_DATE},
179     {"q"     ,   1,  TOK_q      , VT_DATE},
180     {"yyyy"  ,   4,  TOK_yyyy   , VT_DATE},
181     {"yy"    ,   2,  TOK_yy     , VT_DATE},
182     {"y"     ,   1,  TOK_y      , VT_DATE},
183     {"h"     ,   1,  TOK_h      , VT_DATE},
184     {"Hh"    ,   2,  TOK_Hh     , VT_DATE},
185     {"Nn"    ,   2,  TOK_Nn     , VT_DATE},
186     {"N"     ,   1,  TOK_N      , VT_DATE},
187     {"S"     ,   1,  TOK_S      , VT_DATE},
188     {"Ss"    ,   2,  TOK_Ss     , VT_DATE},
189     {"ttttt" ,   5,  TOK_ttttt  , VT_DATE},
190     {"AM/PM" ,   5,  TOK_AMsPM  , VT_DATE},
191     {"am/pm" ,   5,  TOK_amspm  , VT_DATE},
192     {"A/P"   ,   3,  TOK_AsP    , VT_DATE},
193     {"a/p"   ,   3,  TOK_asp    , VT_DATE},
194     {"AMPM"  ,   4,  TOK_AMPM   , VT_DATE},
195     {0x00    ,   0,  0          , VT_NULL}
196 };
197
198 /******************************************************************************
199  *         DateTimeStringToTm   [INTERNAL]
200  *
201  * Converts a string representation of a date and/or time to a tm structure.
202  *
203  * Note this function uses the postgresql date parsing functions found
204  * in the parsedt.c file.
205  *
206  * Returns TRUE if successful.
207  *
208  * Note: This function does not parse the day of the week,
209  * daylight savings time. It will only fill the followin fields in
210  * the tm struct, tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
211  *
212  ******************************************************************************/
213 static BOOL DateTimeStringToTm( OLECHAR* strIn, DWORD dwFlags, struct tm* pTm )
214 {
215         BOOL res = FALSE;
216         double          fsec;
217         int             tzp;
218         int             dtype;
219         int             nf;
220         char       *field[MAXDATEFIELDS];
221         int             ftype[MAXDATEFIELDS];
222         char            lowstr[MAXDATELEN + 1];
223         char* strDateTime = NULL;
224
225         /* Convert the string to ASCII since this is the only format
226          * postgesql can handle.
227          */
228         strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
229
230         if( strDateTime != NULL )
231         {
232                 /* Make sure we don't go over the maximum length
233                  * accepted by postgesql.
234                  */
235                 if( strlen( strDateTime ) <= MAXDATELEN )
236                 {
237                         if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
238                         {
239                                 if( dwFlags & VAR_DATEVALUEONLY )
240                                 {
241                                         /* Get the date information.
242                                          * It returns 0 if date information was
243                                          * present and 1 if only time information was present.
244                                          * -1 if an error occures.
245                                          */
246                                         if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
247                                         {
248                                                 /* Eliminate the time information since we
249                                                  * were asked to get date information only.
250                                                  */
251                                                 pTm->tm_sec = 0;
252                                                 pTm->tm_min = 0;
253                                                 pTm->tm_hour = 0;
254                                                 res = TRUE;
255                                         }
256                                 }
257                                 if( dwFlags & VAR_TIMEVALUEONLY )
258                                 {
259                                         /* Get time information only.
260                                          */
261                                         if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
262                                         {
263                                                 res = TRUE;
264                                         }
265                                 }
266                                 else
267                                 {
268                                         /* Get both date and time information.
269                                          * It returns 0 if date information was
270                                          * present and 1 if only time information was present.
271                                          * -1 if an error occures.
272                                          */
273                                         if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
274                                         {
275                                                 res = TRUE;
276                                         }
277                                 }
278                         }
279                 }
280                 HeapFree( GetProcessHeap(), 0, strDateTime );
281         }
282
283         return res;
284 }
285
286
287
288
289
290
291 /******************************************************************************
292  *         TmToDATE     [INTERNAL]
293  *
294  * The date is implemented using an 8 byte floating-point number.
295  * Days are represented by whole numbers increments starting with 0.00 has
296  * being December 30 1899, midnight.
297  * The hours are expressed as the fractional part of the number.
298  * December 30 1899 at midnight = 0.00
299  * January 1 1900 at midnight = 2.00
300  * January 4 1900 at 6 AM = 5.25
301  * January 4 1900 at noon = 5.50
302  * December 29 1899 at midnight = -1.00
303  * December 18 1899 at midnight = -12.00
304  * December 18 1899 at 6AM = -12.25
305  * December 18 1899 at 6PM = -12.75
306  * December 19 1899 at midnight = -11.00
307  * The tm structure is as follows:
308  * struct tm {
309  *                int tm_sec;      seconds after the minute - [0,59]
310  *                int tm_min;      minutes after the hour - [0,59]
311  *                int tm_hour;     hours since midnight - [0,23]
312  *                int tm_mday;     day of the month - [1,31]
313  *                int tm_mon;      months since January - [0,11]
314  *                int tm_year;     years
315  *                int tm_wday;     days since Sunday - [0,6]
316  *                int tm_yday;     days since January 1 - [0,365]
317  *                int tm_isdst;    daylight savings time flag
318  *                };
319  *
320  * Note: This function does not use the tm_wday, tm_yday, tm_wday,
321  * and tm_isdst fields of the tm structure. And only converts years
322  * after 1900.
323  *
324  * Returns TRUE if successful.
325  */
326 static BOOL TmToDATE( struct tm* pTm, DATE *pDateOut )
327 {
328     int leapYear = 0;
329
330     /* Hmmm... An uninitialized Date in VB is December 30 1899 so
331        Start at 0. This is the way DATE is defined. */
332
333     /* Start at 1. This is the way DATE is defined.
334      * January 1, 1900 at Midnight is 1.00.
335      * January 1, 1900 at 6AM is 1.25.
336      * and so on.
337      */
338     *pDateOut = 1;
339
340     if( (pTm->tm_year - 1900) >= 0 ) {
341
342         /* Add the number of days corresponding to
343          * tm_year.
344          */
345         *pDateOut += (pTm->tm_year - 1900) * 365;
346
347         /* Add the leap days in the previous years between now and 1900.
348          * Note a leap year is one that is a multiple of 4
349          * but not of a 100.  Except if it is a multiple of
350          * 400 then it is a leap year.
351          * Copied + reversed functionality into TmToDate
352          */
353         *pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
354         *pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
355         *pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
356
357         /* Set the leap year flag if the
358          * current year specified by tm_year is a
359          * leap year. This will be used to add a day
360          * to the day count.
361          */
362         if( isleap( pTm->tm_year ) )
363             leapYear = 1;
364
365         /* Add the number of days corresponding to
366          * the month. (remember tm_mon is 0..11)
367          */
368         switch( pTm->tm_mon )
369         {
370         case 1:
371             *pDateOut += 31;
372             break;
373         case 2:
374             *pDateOut += ( 59 + leapYear );
375             break;
376         case 3:
377             *pDateOut += ( 90 + leapYear );
378             break;
379         case 4:
380             *pDateOut += ( 120 + leapYear );
381             break;
382         case 5:
383             *pDateOut += ( 151 + leapYear );
384             break;
385         case 6:
386             *pDateOut += ( 181 + leapYear );
387             break;
388         case 7:
389             *pDateOut += ( 212 + leapYear );
390             break;
391         case 8:
392             *pDateOut += ( 243 + leapYear );
393             break;
394         case 9:
395             *pDateOut += ( 273 + leapYear );
396             break;
397         case 10:
398             *pDateOut += ( 304 + leapYear );
399             break;
400         case 11:
401             *pDateOut += ( 334 + leapYear );
402             break;
403         }
404         /* Add the number of days in this month.
405          */
406         *pDateOut += pTm->tm_mday;
407
408         /* Add the number of seconds, minutes, and hours
409          * to the DATE. Note these are the fractional part
410          * of the DATE so seconds / number of seconds in a day.
411          */
412     } else {
413         *pDateOut = 0;
414     }
415
416     *pDateOut += pTm->tm_hour / 24.0;
417     *pDateOut += pTm->tm_min / 1440.0;
418     *pDateOut += pTm->tm_sec / 86400.0;
419     return TRUE;
420 }
421
422 /******************************************************************************
423  *         DateToTm     [INTERNAL]
424  *
425  * This function converts a windows DATE to a tm structure.
426  *
427  * It does not fill all the fields of the tm structure.
428  * Here is a list of the fields that are filled:
429  * tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
430  *
431  * Note this function does not support dates before the January 1, 1900
432  * or ( dateIn < 2.0 ).
433  *
434  * Returns TRUE if successful.
435  */
436 BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )
437 {
438     double decimalPart = 0.0;
439     double wholePart = 0.0;
440
441     memset(pTm,0,sizeof(*pTm));
442
443     /* Because of the nature of DATE format which
444      * associates 2.0 to January 1, 1900. We will
445      * remove 1.0 from the whole part of the DATE
446      * so that in the following code 1.0
447      * will correspond to January 1, 1900.
448      * This simplifies the processing of the DATE value.
449      */
450     decimalPart = fmod( dateIn, 1.0 ); /* Do this before the -1, otherwise 0.xx goes negative */
451     dateIn -= 1.0;
452     wholePart = (double) floor( dateIn );
453
454     if( !(dwFlags & VAR_TIMEVALUEONLY) )
455     {
456         unsigned int nDay = 0;
457         int leapYear = 0;
458         double yearsSince1900 = 0;
459
460         /* Hard code dates smaller than January 1, 1900. */
461         if( dateIn < 2.0 ) {
462             pTm->tm_year = 1899;
463             pTm->tm_mon  = 11; /* December as tm_mon is 0..11 */
464             if( dateIn < 1.0 ) {
465                 pTm->tm_mday  = 30;
466                 dateIn = dateIn * -1.0; /* Ensure +ve for time calculation */
467                 decimalPart = decimalPart * -1.0; /* Ensure +ve for time calculation */
468             } else {
469                 pTm->tm_mday  = 31;
470             }
471
472         } else {
473
474             /* Start at 1900, this is where the DATE time 0.0 starts.
475              */
476             pTm->tm_year = 1900;
477             /* find in what year the day in the "wholePart" falls into.
478              * add the value to the year field.
479              */
480             yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 );
481             pTm->tm_year += yearsSince1900;
482             /* determine if this is a leap year.
483              */
484             if( isleap( pTm->tm_year ) )
485             {
486                 leapYear = 1;
487                 wholePart++;
488             }
489
490             /* find what day of that year the "wholePart" corresponds to.
491              * Note: nDay is in [1-366] format
492              */
493             nDay = (((unsigned int) wholePart) - ((pTm->tm_year-1900) * DAYS_IN_ONE_YEAR ));
494
495             /* Remove the leap days in the previous years between now and 1900.
496              * Note a leap year is one that is a multiple of 4
497              * but not of a 100.  Except if it is a multiple of
498              * 400 then it is a leap year.
499              * Copied + reversed functionality from TmToDate
500              */
501             nDay -= ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
502             nDay += ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
503             nDay -= ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
504
505             /* Set the tm_yday value.
506              * Note: The day must be converted from [1-366] to [0-365]
507              */
508             /*pTm->tm_yday = nDay - 1;*/
509             /* find which month this day corresponds to.
510              */
511             if( nDay <= 31 )
512             {
513                 pTm->tm_mday = nDay;
514                 pTm->tm_mon = 0;
515             }
516             else if( nDay <= ( 59 + leapYear ) )
517             {
518                 pTm->tm_mday = nDay - 31;
519                 pTm->tm_mon = 1;
520             }
521             else if( nDay <= ( 90 + leapYear ) )
522             {
523                 pTm->tm_mday = nDay - ( 59 + leapYear );
524                 pTm->tm_mon = 2;
525             }
526             else if( nDay <= ( 120 + leapYear ) )
527             {
528                 pTm->tm_mday = nDay - ( 90 + leapYear );
529                 pTm->tm_mon = 3;
530             }
531             else if( nDay <= ( 151 + leapYear ) )
532             {
533                 pTm->tm_mday = nDay - ( 120 + leapYear );
534                 pTm->tm_mon = 4;
535             }
536             else if( nDay <= ( 181 + leapYear ) )
537             {
538                 pTm->tm_mday = nDay - ( 151 + leapYear );
539                 pTm->tm_mon = 5;
540             }
541             else if( nDay <= ( 212 + leapYear ) )
542             {
543                 pTm->tm_mday = nDay - ( 181 + leapYear );
544                 pTm->tm_mon = 6;
545             }
546             else if( nDay <= ( 243 + leapYear ) )
547             {
548                 pTm->tm_mday = nDay - ( 212 + leapYear );
549                 pTm->tm_mon = 7;
550             }
551             else if( nDay <= ( 273 + leapYear ) )
552             {
553                 pTm->tm_mday = nDay - ( 243 + leapYear );
554                 pTm->tm_mon = 8;
555             }
556             else if( nDay <= ( 304 + leapYear ) )
557             {
558                 pTm->tm_mday = nDay - ( 273 + leapYear );
559                 pTm->tm_mon = 9;
560             }
561             else if( nDay <= ( 334 + leapYear ) )
562             {
563                 pTm->tm_mday = nDay - ( 304 + leapYear );
564                 pTm->tm_mon = 10;
565             }
566             else if( nDay <= ( 365 + leapYear ) )
567             {
568                 pTm->tm_mday = nDay - ( 334 + leapYear );
569                 pTm->tm_mon = 11;
570             }
571         }
572     }
573     if( !(dwFlags & VAR_DATEVALUEONLY) )
574     {
575         /* find the number of seconds in this day.
576          * fractional part times, hours, minutes, seconds.
577          * Note: 0.1 is hack to ensure figures come out in whole numbers
578          *   due to floating point inaccuracies
579          */
580         pTm->tm_hour = (int) ( decimalPart * 24 );
581         pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
582         /* Note: 0.1 is hack to ensure seconds come out in whole numbers
583              due to floating point inaccuracies */
584         pTm->tm_sec = (int) (( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 ) + 0.1);
585     }
586     return TRUE;
587 }
588
589
590
591 /******************************************************************************
592  *         SizeOfVariantData    [INTERNAL]
593  *
594  * This function finds the size of the data referenced by a Variant based
595  * the type "vt" of the Variant.
596  */
597 static int SizeOfVariantData( VARIANT* parg )
598 {
599     int size = 0;
600     switch( V_VT(parg) & VT_TYPEMASK )
601     {
602     case( VT_I2 ):
603         size = sizeof(short);
604         break;
605     case( VT_INT ):
606         size = sizeof(int);
607         break;
608     case( VT_I4 ):
609         size = sizeof(long);
610         break;
611     case( VT_UI1 ):
612         size = sizeof(BYTE);
613         break;
614     case( VT_UI2 ):
615         size = sizeof(unsigned short);
616         break;
617     case( VT_UINT ):
618         size = sizeof(unsigned int);
619         break;
620     case( VT_UI4 ):
621         size = sizeof(unsigned long);
622         break;
623     case( VT_R4 ):
624         size = sizeof(float);
625         break;
626     case( VT_R8 ):
627         size = sizeof(double);
628         break;
629     case( VT_DATE ):
630         size = sizeof(DATE);
631         break;
632     case( VT_BOOL ):
633         size = sizeof(VARIANT_BOOL);
634         break;
635     case( VT_BSTR ):
636     case( VT_DISPATCH ):
637     case( VT_UNKNOWN ):
638         size = sizeof(void*);
639         break;
640     case( VT_CY ):
641         size = sizeof(CY);
642         break;
643     case( VT_DECIMAL ):         /* hmm, tricky, DECIMAL is only VT_BYREF */
644     default:
645         FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK );
646         break;
647     }
648
649     return size;
650 }
651 /******************************************************************************
652  *         StringDupAtoBstr             [INTERNAL]
653  *
654  */
655 static BSTR StringDupAtoBstr( char* strIn )
656 {
657         BSTR bstr = NULL;
658         OLECHAR* pNewString = NULL;
659         UNICODE_STRING usBuffer;
660         
661         RtlCreateUnicodeStringFromAsciiz( &usBuffer, strIn );
662         pNewString = usBuffer.Buffer;
663
664         bstr = SysAllocString( pNewString );
665         RtlFreeUnicodeString( &usBuffer );
666         return bstr;
667 }
668
669 /******************************************************************************
670  *              round           [INTERNAL]
671  *
672  * Round the double value to the nearest integer value.
673  */
674 static double round( double d )
675 {
676    double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
677     BOOL bEvenNumber = FALSE;
678     int nSign = 0;
679
680     /* Save the sign of the number
681      */
682    nSign = (d >= 0.0) ? 1 : -1;
683     d = fabs( d );
684
685         /* Remove the decimals.
686          */
687    integerValue = floor( d );
688
689     /* Set the Even flag.  This is used to round the number when
690      * the decimals are exactly 1/2.  If the integer part is
691      * odd the number is rounded up. If the integer part
692      * is even the number is rounded down.  Using this method
693      * numbers are rounded up|down half the time.
694      */
695    bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
696
697     /* Remove the integral part of the number.
698      */
699     decimals = d - integerValue;
700
701         /* Note: Ceil returns the smallest integer that is greater that x.
702          * and floor returns the largest integer that is less than or equal to x.
703          */
704     if( decimals > 0.5 )
705     {
706         /* If the decimal part is greater than 1/2
707          */
708         roundedValue = ceil( d );
709     }
710     else if( decimals < 0.5 )
711     {
712         /* If the decimal part is smaller than 1/2
713          */
714         roundedValue = floor( d );
715     }
716     else
717     {
718         /* the decimals are exactly 1/2 so round according to
719          * the bEvenNumber flag.
720          */
721         if( bEvenNumber )
722         {
723             roundedValue = floor( d );
724         }
725         else
726         {
727             roundedValue = ceil( d );
728         }
729     }
730
731         return roundedValue * nSign;
732 }
733
734 /******************************************************************************
735  *              Coerce  [INTERNAL]
736  *
737  * This function dispatches execution to the proper conversion API
738  * to do the necessary coercion.
739  *
740  * FIXME: Passing down dwFlags to the conversion functions is wrong, this
741  *        is a different flagmask. Check MSDN.
742  */
743 static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
744 {
745         HRESULT res = S_OK;
746         unsigned short vtFrom = 0;
747         vtFrom = V_VT(ps) & VT_TYPEMASK;
748
749
750         /* Note: Since "long" and "int" values both have 4 bytes and are
751          * both signed integers "int" will be treated as "long" in the
752          * following code.
753          * The same goes for their unsigned versions.
754          */
755
756         /* Trivial Case: If the coercion is from two types that are
757          * identical then we can blindly copy from one argument to another.*/
758         if ((vt==vtFrom))
759            return VariantCopy(pd,ps);
760
761         /* Cases requiring thought*/
762         switch( vt )
763         {
764
765     case( VT_EMPTY ):
766         res = VariantClear( pd );
767         break;
768     case( VT_NULL ):
769         res = VariantClear( pd );
770         if( res == S_OK )
771         {
772             V_VT(pd) = VT_NULL;
773         }
774         break;
775         case( VT_I1 ):
776                 switch( vtFrom )
777         {
778                 case( VT_I2 ):
779                         res = VarI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,cVal) );
780                         break;
781                 case( VT_INT ):
782                 case( VT_I4 ):
783                         res = VarI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,cVal) );
784                         break;
785                 case( VT_UI1 ):
786                         res = VarI1FromUI1( V_UNION(ps,bVal), &V_UNION(pd,cVal) );
787                         break;
788                 case( VT_UI2 ):
789                         res = VarI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cVal) );
790                         break;
791                 case( VT_UINT ):
792                 case( VT_UI4 ):
793                         res = VarI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cVal) );
794                         break;
795                 case( VT_R4 ):
796                         res = VarI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,cVal) );
797                         break;
798                 case( VT_R8 ):
799                         res = VarI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,cVal) );
800                         break;
801                 case( VT_DATE ):
802                         res = VarI1FromDate( V_UNION(ps,date), &V_UNION(pd,cVal) );
803                         break;
804                 case( VT_BOOL ):
805                         res = VarI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,cVal) );
806                         break;
807                 case( VT_BSTR ):
808                         res = VarI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cVal) );
809                         break;
810                 case( VT_CY ):
811                         res = VarI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,cVal) );
812                         break;
813                 case( VT_DISPATCH ):
814                         /*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
815                 case( VT_DECIMAL ):
816                         /*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
817                 case( VT_UNKNOWN ):
818                 default:
819                         res = DISP_E_TYPEMISMATCH;
820                         FIXME("Coercion from %d to VT_I1\n", vtFrom );
821                         break;
822                 }
823                 break;
824
825         case( VT_I2 ):
826                 switch( vtFrom )
827                 {
828                 case( VT_I1 ):
829                         res = VarI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,iVal) );
830                         break;
831                 case( VT_INT ):
832                 case( VT_I4 ):
833                         res = VarI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,iVal) );
834                         break;
835                 case( VT_UI1 ):
836                         res = VarI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,iVal) );
837                         break;
838                 case( VT_UI2 ):
839                         res = VarI2FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,iVal) );
840                         break;
841                 case( VT_UINT ):
842                 case( VT_UI4 ):
843                         res = VarI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,iVal) );
844                         break;
845                 case( VT_R4 ):
846                         res = VarI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,iVal) );
847                         break;
848                 case( VT_R8 ):
849                         res = VarI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,iVal) );
850                         break;
851                 case( VT_DATE ):
852                         res = VarI2FromDate( V_UNION(ps,date), &V_UNION(pd,iVal) );
853                         break;
854                 case( VT_BOOL ):
855                         res = VarI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,iVal) );
856                         break;
857                 case( VT_BSTR ):
858                         res = VarI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,iVal) );
859                         break;
860                 case( VT_CY ):
861                         res = VarI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,iVal) );
862                         break;
863                 case( VT_DISPATCH ):
864                         /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
865                 case( VT_DECIMAL ):
866                         /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
867                 case( VT_UNKNOWN ):
868                 default:
869                         res = DISP_E_TYPEMISMATCH;
870                         FIXME("Coercion from %d to VT_I2\n", vtFrom);
871                         break;
872                 }
873                 break;
874
875         case( VT_INT ):
876         case( VT_I4 ):
877                 switch( vtFrom )
878                 {
879                 case( VT_EMPTY ):
880                         V_UNION(pd,lVal) = 0;
881                         res = S_OK;
882                         break;
883                 case( VT_I1 ):
884                         res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
885                         break;
886                 case( VT_I2 ):
887                         res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
888
889                         break;
890                 case( VT_ERROR ):
891                         V_UNION(pd,lVal) = V_UNION(pd,scode);
892                         res = S_OK;
893                         break;
894         case( VT_INT ):
895         case( VT_I4 ):
896             res = VariantCopy( pd, ps );
897             break;
898                 case( VT_UI1 ):
899                         res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
900                         break;
901                 case( VT_UI2 ):
902                         res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
903                         break;
904                 case( VT_UINT ):
905                 case( VT_UI4 ):
906                         res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
907                         break;
908                 case( VT_R4 ):
909                         res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
910                         break;
911                 case( VT_R8 ):
912                         res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
913                         break;
914                 case( VT_DATE ):
915                         res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
916                         break;
917                 case( VT_BOOL ):
918                         res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
919                         break;
920                 case( VT_BSTR ):
921                         res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
922                         break;
923                 case( VT_CY ):
924                         res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
925                         break;
926                 case( VT_DISPATCH ):
927                         /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
928                 case( VT_DECIMAL ):
929                         /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
930                 case( VT_UNKNOWN ):
931                 default:
932                         res = DISP_E_TYPEMISMATCH;
933                         FIXME("Coercion from %d to VT_INT/VT_I4\n", vtFrom);
934                         break;
935                 }
936                 break;
937
938         case( VT_UI1 ):
939                 switch( vtFrom )
940                 {
941                 case( VT_I1 ):
942                         res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
943                         break;
944                 case( VT_I2 ):
945                         res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
946                         break;
947                 case( VT_INT ):
948                 case( VT_I4 ):
949                         res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
950                         break;
951         case( VT_UI1 ):
952             res = VariantCopy( pd, ps );
953             break;
954                 case( VT_UI2 ):
955                         res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
956                         break;
957                 case( VT_UINT ):
958                 case( VT_UI4 ):
959                         res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
960                         break;
961                 case( VT_R4 ):
962                         res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
963                         break;
964                 case( VT_R8 ):
965                         res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
966                         break;
967                 case( VT_DATE ):
968                         res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
969                         break;
970                 case( VT_BOOL ):
971                         res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
972                         break;
973                 case( VT_BSTR ):
974                         res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
975                         break;
976                 case( VT_CY ):
977                         res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
978                         break;
979                 case( VT_DISPATCH ):
980                         /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
981                 case( VT_DECIMAL ):
982                         /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
983                 case( VT_UNKNOWN ):
984                 default:
985                         res = DISP_E_TYPEMISMATCH;
986                         FIXME("Coercion from %d to VT_UI1\n", vtFrom);
987                         break;
988                 }
989                 break;
990
991         case( VT_UI2 ):
992                 switch( vtFrom )
993                 {
994                 case( VT_I1 ):
995                         res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
996                         break;
997                 case( VT_I2 ):
998                         res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
999                         break;
1000                 case( VT_INT ):
1001                 case( VT_I4 ):
1002                         res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
1003                         break;
1004                 case( VT_UI1 ):
1005                         res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
1006                         break;
1007         case( VT_UI2 ):
1008             res = VariantCopy( pd, ps );
1009             break;
1010                 case( VT_UINT ):
1011                 case( VT_UI4 ):
1012                         res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
1013                         break;
1014                 case( VT_R4 ):
1015                         res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
1016                         break;
1017                 case( VT_R8 ):
1018                         res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
1019                         break;
1020                 case( VT_DATE ):
1021                         res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
1022                         break;
1023                 case( VT_BOOL ):
1024                         res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
1025                         break;
1026                 case( VT_BSTR ):
1027                         res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
1028                         break;
1029                 case( VT_CY ):
1030                         res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
1031                         break;
1032                 case( VT_DISPATCH ):
1033                         /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1034                 case( VT_DECIMAL ):
1035                         /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1036                 case( VT_UNKNOWN ):
1037                 default:
1038                         res = DISP_E_TYPEMISMATCH;
1039                         FIXME("Coercion from %d to VT_UI2\n", vtFrom);
1040                         break;
1041                 }
1042                 break;
1043
1044         case( VT_UINT ):
1045         case( VT_UI4 ):
1046                 switch( vtFrom )
1047                 {
1048                 case( VT_I1 ):
1049                         res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
1050                         break;
1051                 case( VT_I2 ):
1052                         res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
1053                         break;
1054                 case( VT_INT ):
1055                 case( VT_I4 ):
1056                         res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
1057                         break;
1058                 case( VT_UI1 ):
1059                         res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
1060                         break;
1061                 case( VT_UI2 ):
1062                         res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
1063                         break;
1064         case( VT_UI4 ):
1065             res = VariantCopy( pd, ps );
1066             break;
1067                 case( VT_R4 ):
1068                         res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
1069                         break;
1070                 case( VT_R8 ):
1071                         res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
1072                         break;
1073                 case( VT_DATE ):
1074                         res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
1075                         break;
1076                 case( VT_BOOL ):
1077                         res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
1078                         break;
1079                 case( VT_BSTR ):
1080                         res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
1081                         break;
1082                 case( VT_CY ):
1083                         res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
1084                         break;
1085                 case( VT_DISPATCH ):
1086                         /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1087                 case( VT_DECIMAL ):
1088                         /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1089                 case( VT_UNKNOWN ):
1090                 default:
1091                         res = DISP_E_TYPEMISMATCH;
1092                         FIXME("Coercion from %d to VT_UINT/VT_UI4\n", vtFrom);
1093                         break;
1094                 }
1095                 break;
1096
1097         case( VT_R4 ):
1098                 switch( vtFrom )
1099                 {
1100                 case( VT_I1 ):
1101                         res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
1102                         break;
1103                 case( VT_I2 ):
1104                         res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
1105                         break;
1106                 case( VT_INT ):
1107                 case( VT_I4 ):
1108                         res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
1109                         break;
1110                 case( VT_UI1 ):
1111                         res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
1112                         break;
1113                 case( VT_UI2 ):
1114                         res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
1115                         break;
1116                 case( VT_UINT ):
1117                 case( VT_UI4 ):
1118                         res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
1119                         break;
1120                 case( VT_R4 ):
1121                     res = VariantCopy( pd, ps );
1122                     break;
1123                 case( VT_R8 ):
1124                         res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
1125                         break;
1126                 case( VT_DATE ):
1127                         res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
1128                         break;
1129                 case( VT_BOOL ):
1130                         res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
1131                         break;
1132                 case( VT_BSTR ):
1133                         res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
1134                         break;
1135                 case( VT_CY ):
1136                         res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
1137                         break;
1138                 case( VT_ERROR ):
1139                         V_UNION(pd,fltVal) = V_UNION(ps,scode);
1140                         res = S_OK;
1141                         break;
1142                 case( VT_DISPATCH ):
1143                         /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1144                 case( VT_DECIMAL ):
1145                         /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1146                 case( VT_UNKNOWN ):
1147                 default:
1148                         res = DISP_E_TYPEMISMATCH;
1149                         FIXME("Coercion from %d to VT_R4\n", vtFrom);
1150                         break;
1151                 }
1152                 break;
1153
1154         case( VT_R8 ):
1155                 switch( vtFrom )
1156                 {
1157                 case( VT_I1 ):
1158                         res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
1159                         break;
1160                 case( VT_I2 ):
1161                         res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
1162                         break;
1163                 case( VT_INT ):
1164                 case( VT_I4 ):
1165                         res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
1166                         break;
1167                 case( VT_UI1 ):
1168                         res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
1169                         break;
1170                 case( VT_UI2 ):
1171                         res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
1172                         break;
1173                 case( VT_UINT ):
1174                 case( VT_UI4 ):
1175                         res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
1176                         break;
1177                 case( VT_R4 ):
1178                         res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
1179                         break;
1180         case( VT_R8 ):
1181             res = VariantCopy( pd, ps );
1182             break;
1183                 case( VT_DATE ):
1184                         res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
1185                         break;
1186                 case( VT_BOOL ):
1187                         res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
1188                         break;
1189                 case( VT_BSTR ):
1190                         res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
1191                         break;
1192                 case( VT_CY ):
1193                         res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
1194                         break;
1195                 case( VT_DISPATCH ):
1196                         /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1197                 case( VT_DECIMAL ):
1198                         /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1199                 case( VT_UNKNOWN ):
1200                 default:
1201                         res = DISP_E_TYPEMISMATCH;
1202                         FIXME("Coercion from %d to VT_R8\n", vtFrom);
1203                         break;
1204                 }
1205                 break;
1206
1207         case( VT_DATE ):
1208                 switch( vtFrom )
1209                 {
1210                 case( VT_I1 ):
1211                         res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
1212                         break;
1213                 case( VT_I2 ):
1214                         res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
1215                         break;
1216                 case( VT_INT ):
1217                         res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
1218                         break;
1219                 case( VT_I4 ):
1220                         res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
1221                         break;
1222                 case( VT_UI1 ):
1223                         res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
1224                         break;
1225                 case( VT_UI2 ):
1226                         res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
1227                         break;
1228                 case( VT_UINT ):
1229                         res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
1230                         break;
1231                 case( VT_UI4 ):
1232                         res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
1233                         break;
1234                 case( VT_R4 ):
1235                         res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
1236                         break;
1237                 case( VT_R8 ):
1238                         res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
1239                         break;
1240                 case( VT_BOOL ):
1241                         res = VarDateFromBool( V_UNION(ps,boolVal), &V_UNION(pd,date) );
1242                         break;
1243                 case( VT_BSTR ):
1244                         res = VarDateFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,date) );
1245                         break;
1246                 case( VT_CY ):
1247                         res = VarDateFromCy( V_UNION(ps,cyVal), &V_UNION(pd,date) );
1248                         break;
1249                 case( VT_DISPATCH ):
1250                         /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1251                 case( VT_DECIMAL ):
1252                         /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1253                 case( VT_UNKNOWN ):
1254                 default:
1255                         res = DISP_E_TYPEMISMATCH;
1256                         FIXME("Coercion from %d to VT_DATE\n", vtFrom);
1257                         break;
1258                 }
1259                 break;
1260
1261         case( VT_BOOL ):
1262                 switch( vtFrom )
1263                 {
1264                 case( VT_NULL ):
1265                 case( VT_EMPTY ):
1266                         res = S_OK;
1267                         V_UNION(pd,boolVal) = VARIANT_FALSE;
1268                         break;
1269                 case( VT_I1 ):
1270                         res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
1271                         break;
1272                 case( VT_I2 ):
1273                         res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
1274                         break;
1275                 case( VT_INT ):
1276                         res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
1277                         break;
1278                 case( VT_I4 ):
1279                         res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
1280                         break;
1281                 case( VT_UI1 ):
1282                         res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
1283                         break;
1284                 case( VT_UI2 ):
1285                         res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
1286                         break;
1287                 case( VT_UINT ):
1288                         res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
1289                         break;
1290                 case( VT_UI4 ):
1291                         res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
1292                         break;
1293                 case( VT_R4 ):
1294                         res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
1295                         break;
1296                 case( VT_R8 ):
1297                         res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
1298                         break;
1299                 case( VT_DATE ):
1300                         res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
1301                         break;
1302                 case( VT_BSTR ):
1303                         res = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
1304                         break;
1305                 case( VT_CY ):
1306                         res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
1307                         break;
1308                 case( VT_DISPATCH ):
1309                         /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1310                 case( VT_DECIMAL ):
1311                         /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1312                 case( VT_UNKNOWN ):
1313                 default:
1314                         res = DISP_E_TYPEMISMATCH;
1315                         FIXME("Coercion from %d to VT_BOOL\n", vtFrom);
1316                         break;
1317                 }
1318                 break;
1319
1320         case( VT_BSTR ):
1321                 switch( vtFrom )
1322                 {
1323                 case( VT_EMPTY ):
1324                         if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
1325                                 res = S_OK;
1326                         else
1327                                 res = E_OUTOFMEMORY;
1328                         break;
1329                 case( VT_I1 ):
1330                         res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
1331                         break;
1332                 case( VT_I2 ):
1333                         res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
1334                         break;
1335                 case( VT_INT ):
1336                         res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
1337                         break;
1338                 case( VT_I4 ):
1339                         res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
1340                         break;
1341                 case( VT_UI1 ):
1342                         res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
1343                         break;
1344                 case( VT_UI2 ):
1345                         res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
1346                         break;
1347                 case( VT_UINT ):
1348                         res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
1349                         break;
1350                 case( VT_UI4 ):
1351                         res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
1352                         break;
1353                 case( VT_R4 ):
1354                         res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
1355                         break;
1356                 case( VT_R8 ):
1357                         res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
1358                         break;
1359                 case( VT_DATE ):
1360                         res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
1361                         break;
1362                 case( VT_BOOL ):
1363                         res = VarBstrFromBool( V_UNION(ps,boolVal), lcid, 0, &V_UNION(pd,bstrVal) );
1364                         break;
1365                 case( VT_BSTR ):
1366                         res = VariantCopy( pd, ps );
1367                         break;
1368                 case( VT_CY ):
1369                         res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
1370                         break;
1371                 case( VT_DISPATCH ):
1372                         /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1373                 case( VT_DECIMAL ):
1374                         /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1375                 case( VT_UNKNOWN ):
1376                 default:
1377                         res = DISP_E_TYPEMISMATCH;
1378                         FIXME("Coercion from %d to VT_BSTR\n", vtFrom);
1379                         break;
1380                 }
1381                 break;
1382
1383      case( VT_CY ):
1384         switch( vtFrom )
1385           {
1386           case( VT_I1 ):
1387              res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
1388              break;
1389           case( VT_I2 ):
1390              res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
1391              break;
1392           case( VT_INT ):
1393              res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
1394              break;
1395           case( VT_I4 ):
1396              res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
1397              break;
1398           case( VT_UI1 ):
1399              res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
1400              break;
1401           case( VT_UI2 ):
1402              res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
1403              break;
1404           case( VT_UINT ):
1405              res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
1406              break;
1407           case( VT_UI4 ):
1408              res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
1409              break;
1410           case( VT_R4 ):
1411              res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
1412              break;
1413           case( VT_R8 ):
1414              res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
1415              break;
1416           case( VT_DATE ):
1417              res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1418              break;
1419           case( VT_BOOL ):
1420              res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1421              break;
1422           case( VT_CY ):
1423              res = VariantCopy( pd, ps );
1424              break;
1425           case( VT_BSTR ):
1426              res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
1427              break;
1428           case( VT_DISPATCH ):
1429              /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1430           case( VT_DECIMAL ):
1431              /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1432              break;
1433           case( VT_UNKNOWN ):
1434           default:
1435              res = DISP_E_TYPEMISMATCH;
1436              FIXME("Coercion from %d to VT_CY\n", vtFrom);
1437              break;
1438           }
1439         break;
1440
1441         case( VT_UNKNOWN ):
1442             switch (vtFrom) {
1443             case VT_DISPATCH:
1444                 if (V_DISPATCH(ps) == NULL) {
1445                         V_UNKNOWN(pd) = NULL;
1446                 } else {
1447                         res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1448                 }
1449                 break;
1450             case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4:
1451             case VT_R4: case VT_R8: case VT_CY: case VT_DATE:
1452             case VT_BSTR: case VT_ERROR: case VT_BOOL:
1453             case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1:
1454             case VT_UI2: case VT_UI4: case VT_I8: case VT_UI8: case VT_INT:
1455             case VT_UINT: case VT_VOID: case VT_HRESULT: case VT_PTR:
1456             case VT_SAFEARRAY: case VT_CARRAY: case VT_USERDEFINED:
1457             case VT_LPSTR: case VT_LPWSTR: case VT_RECORD: case VT_FILETIME:
1458             case VT_BLOB: case VT_STREAM: case VT_STORAGE:
1459             case VT_STREAMED_OBJECT: case VT_STORED_OBJECT: case VT_BLOB_OBJECT:
1460             case VT_CF: case VT_CLSID:
1461                 res = DISP_E_TYPEMISMATCH;
1462                 break;
1463             default:
1464                 FIXME("Coercion from %d to VT_UNKNOWN unhandled.\n", vtFrom);
1465                 res = DISP_E_BADVARTYPE;
1466                 break;
1467             }
1468             break;
1469
1470         case( VT_DISPATCH ):
1471             switch (vtFrom) {
1472             case VT_UNKNOWN:
1473                 if (V_UNION(ps,punkVal) == NULL) {
1474                         V_UNION(pd,pdispVal) = NULL;
1475                 } else {
1476                         res = IUnknown_QueryInterface(V_UNION(ps,punkVal), &IID_IDispatch, (LPVOID*)&V_UNION(pd,pdispVal));
1477                 }
1478                 break;
1479             case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4:
1480             case VT_R4: case VT_R8: case VT_CY: case VT_DATE:
1481             case VT_BSTR: case VT_ERROR: case VT_BOOL:
1482             case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1:
1483             case VT_UI2: case VT_UI4: case VT_I8: case VT_UI8: case VT_INT:
1484            case VT_UINT: case VT_VOID: case VT_HRESULT:
1485             case VT_SAFEARRAY: case VT_CARRAY: case VT_USERDEFINED:
1486             case VT_LPSTR: case VT_LPWSTR: case VT_RECORD: case VT_FILETIME:
1487             case VT_BLOB: case VT_STREAM: case VT_STORAGE:
1488             case VT_STREAMED_OBJECT: case VT_STORED_OBJECT: case VT_BLOB_OBJECT:
1489             case VT_CF: case VT_CLSID:
1490                 res = DISP_E_TYPEMISMATCH;
1491                 break;
1492            case VT_PTR:
1493                V_UNION(pd,pdispVal) = V_UNION(ps,pdispVal);
1494                break;
1495             default:
1496                 FIXME("Coercion from %d to VT_DISPATCH unhandled.\n", vtFrom);
1497                 res = DISP_E_BADVARTYPE;
1498                 break;
1499             }
1500             break;
1501
1502         default:
1503                 res = DISP_E_TYPEMISMATCH;
1504                 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1505                 break;
1506         }
1507
1508         return res;
1509 }
1510
1511 /******************************************************************************
1512  *              ValidateVtRange [INTERNAL]
1513  *
1514  * Used internally by the hi-level Variant API to determine
1515  * if the vartypes are valid.
1516  */
1517 static HRESULT ValidateVtRange( VARTYPE vt )
1518 {
1519     /* if by value we must make sure it is in the
1520      * range of the valid types.
1521      */
1522     if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1523     {
1524         return DISP_E_BADVARTYPE;
1525     }
1526     return S_OK;
1527 }
1528
1529 /* Copy data from one variant to another. */
1530 static void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
1531 {
1532   switch(vt)
1533   {
1534   case VT_I1:
1535   case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
1536   case VT_BOOL:
1537   case VT_I2:
1538   case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
1539   case VT_R4:
1540   case VT_I4:
1541   case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
1542   case VT_R8:
1543   case VT_DATE:
1544   case VT_CY:
1545   case VT_I8:
1546   case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break;
1547   case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
1548   default:
1549     FIXME("VT_ type %d unhandled, please report!\n", vt);
1550   }
1551 }
1552
1553 /* Coerce VT_DISPATCH to another type */
1554 HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, VARTYPE vt)
1555 {
1556   VARIANTARG srcVar, dstVar;
1557   HRESULT hRet;
1558
1559   V_VT(&srcVar) = VT_DISPATCH;
1560   V_DISPATCH(&srcVar) = pdispIn;
1561
1562   hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, 0, vt);
1563
1564   if (SUCCEEDED(hRet))
1565     VARIANT_CopyData(&dstVar, vt, pOut);
1566   return hRet;
1567 }
1568
1569 /* Coerce VT_BSTR to a numeric type */
1570 HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
1571                                void* pOut, VARTYPE vt)
1572 {
1573   VARIANTARG dstVar;
1574   HRESULT hRet;
1575   NUMPARSE np;
1576   BYTE rgb[1024];
1577
1578   /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
1579   np.cDig = sizeof(rgb) / sizeof(BYTE);
1580   np.dwInFlags = NUMPRS_STD;
1581
1582   hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
1583
1584   if (SUCCEEDED(hRet))
1585   {
1586     /* 1 << vt gives us the VTBIT constant for the destination number type */
1587     hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
1588     if (SUCCEEDED(hRet))
1589       VARIANT_CopyData(&dstVar, vt, pOut);
1590   }
1591   return hRet;
1592 }
1593
1594 /******************************************************************************
1595  *              ValidateVartype [INTERNAL]
1596  *
1597  * Used internally by the hi-level Variant API to determine
1598  * if the vartypes are valid.
1599  */
1600 static HRESULT ValidateVariantType( VARTYPE vt )
1601 {
1602         HRESULT res = S_OK;
1603
1604         /* check if we have a valid argument.
1605          */
1606         if( vt & VT_BYREF )
1607     {
1608         /* if by reference check that the type is in
1609          * the valid range and that it is not of empty or null type
1610          */
1611         if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1612             ( vt & VT_TYPEMASK ) == VT_NULL ||
1613                         ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1614                 {
1615                         res = DISP_E_BADVARTYPE;
1616                 }
1617
1618     }
1619     else
1620     {
1621         res = ValidateVtRange( vt );
1622     }
1623
1624         return res;
1625 }
1626
1627 /******************************************************************************
1628  *              ValidateVt      [INTERNAL]
1629  *
1630  * Used internally by the hi-level Variant API to determine
1631  * if the vartypes are valid.
1632  */
1633 static HRESULT ValidateVt( VARTYPE vt )
1634 {
1635         HRESULT res = S_OK;
1636
1637         /* check if we have a valid argument.
1638          */
1639         if( vt & VT_BYREF )
1640     {
1641         /* if by reference check that the type is in
1642          * the valid range and that it is not of empty or null type
1643          */
1644         if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1645             ( vt & VT_TYPEMASK ) == VT_NULL ||
1646                         ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1647                 {
1648                         res = DISP_E_BADVARTYPE;
1649                 }
1650
1651     }
1652     else
1653     {
1654         res = ValidateVtRange( vt );
1655     }
1656
1657         return res;
1658 }
1659
1660 /******************************************************************************
1661  * Check if a variants type is valid.
1662  */
1663 static inline HRESULT VARIANT_ValidateType(VARTYPE vt)
1664 {
1665   VARTYPE vtExtra = vt & VT_EXTRA_TYPE;
1666
1667   vt &= VT_TYPEMASK;
1668
1669   if (!(vtExtra & (VT_VECTOR|VT_RESERVED)))
1670   {
1671     if (vt < VT_VOID || vt == VT_RECORD || vt == VT_CLSID)
1672     {
1673       if ((vtExtra & (VT_BYREF|VT_ARRAY)) && vt <= VT_NULL)
1674         return DISP_E_BADVARTYPE;
1675       if (vt != (VARTYPE)15)
1676         return S_OK;
1677     }
1678   }
1679   return DISP_E_BADVARTYPE;
1680 }
1681
1682 /******************************************************************************
1683  *              VariantInit     [OLEAUT32.8]
1684  *
1685  * Initialise a variant.
1686  *
1687  * PARAMS
1688  *  pVarg [O] Variant to initialise
1689  *
1690  * RETURNS
1691  *  Nothing.
1692  *
1693  * NOTES
1694  *  This function simply sets the type of the variant to VT_EMPTY. It does not
1695  *  free any existing value, use VariantClear() for that.
1696  */
1697 void WINAPI VariantInit(VARIANTARG* pVarg)
1698 {
1699   TRACE("(%p)\n", pVarg);
1700
1701   V_VT(pVarg) = VT_EMPTY; /* Native doesn't set any other fields */
1702 }
1703
1704 /******************************************************************************
1705  *              VariantClear    [OLEAUT32.9]
1706  *
1707  * Clear a variant.
1708  *
1709  * PARAMS
1710  *  pVarg [I/O] Variant to clear
1711  *
1712  * RETURNS
1713  *  Success: S_OK. Any previous value in pVarg is freed and its type is set to VT_EMPTY.
1714  *  Failure: DISP_E_BADVARTYPE, if the variant is a not a valid variant type.
1715  */
1716 HRESULT WINAPI VariantClear(VARIANTARG* pVarg)
1717 {
1718   HRESULT hres = S_OK;
1719
1720   TRACE("(%p)\n", pVarg);
1721
1722   hres = VARIANT_ValidateType(V_VT(pVarg));
1723
1724   if (SUCCEEDED(hres))
1725   {
1726     if (!V_ISBYREF(pVarg))
1727     {
1728       if (V_ISARRAY(pVarg) || V_VT(pVarg) == VT_SAFEARRAY)
1729       {
1730         if (V_ARRAY(pVarg))
1731           hres = SafeArrayDestroy(V_ARRAY(pVarg));
1732       }
1733       else if (V_VT(pVarg) == VT_BSTR)
1734       {
1735         if (V_BSTR(pVarg))
1736           SysFreeString(V_BSTR(pVarg));
1737       }
1738       else if (V_VT(pVarg) == VT_RECORD)
1739       {
1740         struct __tagBRECORD* pBr = &V_UNION(pVarg,brecVal);
1741         if (pBr->pRecInfo)
1742         {
1743           IRecordInfo_RecordClear(pBr->pRecInfo, pBr->pvRecord);
1744           IRecordInfo_Release(pBr->pRecInfo);
1745         }
1746       }
1747       else if (V_VT(pVarg) == VT_DISPATCH ||
1748                V_VT(pVarg) == VT_UNKNOWN)
1749       {
1750         if (V_UNKNOWN(pVarg))
1751           IUnknown_Release(V_UNKNOWN(pVarg));
1752       }
1753       else if (V_VT(pVarg) == VT_VARIANT)
1754       {
1755         if (V_VARIANTREF(pVarg))
1756           VariantClear(V_VARIANTREF(pVarg));
1757       }
1758     }
1759     V_VT(pVarg) = VT_EMPTY;
1760   }
1761   return hres;
1762 }
1763
1764 /******************************************************************************
1765  *              VariantCopy     [OLEAUT32.10]
1766  *
1767  * Copy a variant.
1768  *
1769  * PARAMS
1770  *  pvargDest [O] Destination for copy
1771  *  pvargSrc  [I] Source variant to copy
1772  *
1773  * RETURNS
1774  *  Success: S_OK. pvargDest contains a copy of pvargSrc.
1775  *  Failure: An HRESULT error code indicating the error.
1776  *
1777  * NOTES
1778  *  pvargDest is always freed, and may be equal to pvargSrc.
1779  *  If pvargSrc is by-reference, pvargDest is by-reference also.
1780  */
1781 HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
1782 {
1783   HRESULT res = S_OK;
1784
1785   TRACE("(%p, %p), vt=%d\n", pvargDest, pvargSrc, V_VT(pvargSrc));
1786
1787   res = ValidateVariantType( V_VT(pvargSrc) );
1788
1789   /* If the pointer are to the same variant we don't need
1790    * to do anything.
1791    */
1792   if( pvargDest != pvargSrc && res == S_OK )
1793   {
1794     VariantClear( pvargDest ); /* result is not checked */
1795
1796     if( V_VT(pvargSrc) & VT_BYREF )
1797     {
1798       /* In the case of byreference we only need
1799        * to copy the pointer.
1800        */
1801       pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1802       V_VT(pvargDest) = V_VT(pvargSrc);
1803     }
1804     else
1805     {
1806       /*
1807        * The VT_ARRAY flag is another way to designate a safe array.
1808        */
1809       if (V_VT(pvargSrc) & VT_ARRAY)
1810       {
1811         SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1812       }
1813       else
1814       {
1815         /* In the case of by value we need to
1816          * copy the actual value. In the case of
1817          * VT_BSTR a copy of the string is made,
1818          * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1819          * called to increment the object's reference count.
1820          */
1821         switch( V_VT(pvargSrc) & VT_TYPEMASK )
1822         {
1823           case( VT_BSTR ):
1824             V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
1825             break;
1826           case( VT_DISPATCH ):
1827             V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
1828             if (V_UNION(pvargDest,pdispVal)!=NULL)
1829               IDispatch_AddRef(V_UNION(pvargDest,pdispVal));
1830             break;
1831           case( VT_VARIANT ):
1832             VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
1833             break;
1834           case( VT_UNKNOWN ):
1835             V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
1836             if (V_UNION(pvargDest,pdispVal)!=NULL)
1837               IUnknown_AddRef(V_UNION(pvargDest,punkVal));
1838             break;
1839           case( VT_SAFEARRAY ):
1840             SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1841             break;
1842           default:
1843             pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1844             break;
1845         }
1846       }
1847       V_VT(pvargDest) = V_VT(pvargSrc);
1848       dump_Variant(pvargDest);
1849     }
1850   }
1851
1852   return res;
1853 }
1854
1855
1856 /******************************************************************************
1857  *              VariantCopyInd  [OLEAUT32.11]
1858  *
1859  *
1860  * Copy a variant, dereferencing if it is by-reference.
1861  *
1862  * PARAMS
1863  *  pvargDest [O] Destination for copy
1864  *  pvargSrc  [I] Source variant to copy
1865  *
1866  * RETURNS
1867  *  Success: S_OK. pvargDest contains a copy of pvargSrc.
1868  *  Failure: An HRESULT error code indicating the error.
1869  *  
1870  * NOTES
1871  *  pvargDest is always freed, and may be equal to pvargSrc.
1872  *  If pvargSrc is not by-reference, this function acts as VariantCopy().
1873  */
1874 HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
1875 {
1876   HRESULT res = S_OK;
1877
1878   TRACE("(%p, %p)\n", pvargDest, pvargSrc);
1879
1880   res = ValidateVariantType( V_VT(pvargSrc) );
1881
1882   if( res != S_OK )
1883     return res;
1884
1885   if( V_VT(pvargSrc) & VT_BYREF )
1886   {
1887     VARIANTARG varg;
1888     VariantInit( &varg );
1889
1890     /* handle the in place copy.
1891      */
1892     if( pvargDest == pvargSrc )
1893     {
1894       /* we will use a copy of the source instead.
1895        */
1896       res = VariantCopy( &varg, pvargSrc );
1897       pvargSrc = &varg;
1898     }
1899
1900     if( res == S_OK )
1901     {
1902       res = VariantClear( pvargDest );
1903
1904       if( res == S_OK )
1905       {
1906         /*
1907          * The VT_ARRAY flag is another way to designate a safearray variant.
1908          */
1909         if ( V_VT(pvargSrc) & VT_ARRAY)
1910         {
1911           SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
1912         }
1913         else
1914         {
1915           /* In the case of by reference we need
1916            * to copy the date pointed to by the variant.
1917            */
1918
1919           /* Get the variant type.
1920            */
1921           switch( V_VT(pvargSrc) & VT_TYPEMASK )
1922           {
1923             case( VT_BSTR ):
1924               V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
1925               break;
1926             case( VT_DISPATCH ):
1927               V_UNION(pvargDest,pdispVal) = *V_UNION(pvargSrc,ppdispVal);
1928               if (V_UNION(pvargDest,pdispVal)!=NULL)
1929                 IDispatch_AddRef(V_UNION(pvargDest,pdispVal));
1930               break;
1931             case( VT_VARIANT ):
1932               {
1933                 /* Prevent from cycling.  According to tests on
1934                  * VariantCopyInd in Windows and the documentation
1935                  * this API dereferences the inner Variants to only one depth.
1936                  * If the inner Variant itself contains an
1937                  * other inner variant the E_INVALIDARG error is
1938                  * returned.
1939                  */
1940                 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
1941                 {
1942                   /* If we get here we are attempting to deference
1943                    * an inner variant that that is itself contained
1944                    * in an inner variant so report E_INVALIDARG error.
1945                    */
1946                   res = E_INVALIDARG;
1947                 }
1948                 else
1949                 {
1950                   /* Set the processing inner variant flag.
1951                    * We will set this flag in the inner variant
1952                    * that will be passed to the VariantCopyInd function.
1953                    */
1954                   (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
1955
1956                   /* Dereference the inner variant.
1957                    */
1958                   res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
1959                   /* We must also copy its type, I think.
1960                    */
1961                   V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
1962                 }
1963               }
1964               break;
1965             case( VT_UNKNOWN ):
1966               V_UNION(pvargDest,punkVal) = *V_UNION(pvargSrc,ppunkVal);
1967               if (V_UNION(pvargDest,pdispVal)!=NULL)
1968                 IUnknown_AddRef(V_UNION(pvargDest,punkVal));
1969               break;
1970             case( VT_SAFEARRAY ):
1971               SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
1972               break;
1973             default:
1974               /* This is a by reference Variant which means that the union
1975                * part of the Variant contains a pointer to some data of
1976                * type "V_VT(pvargSrc) & VT_TYPEMASK".
1977                * We will deference this data in a generic fashion using
1978                * the void pointer "Variant.u.byref".
1979                * We will copy this data into the union of the destination
1980                * Variant.
1981                */
1982               memcpy( &pvargDest->n1.n2.n3, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
1983               break;
1984           }
1985         }
1986
1987         if (res == S_OK) V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
1988       }
1989     }
1990
1991     /* this should not fail.
1992      */
1993     VariantClear( &varg );
1994   }
1995   else
1996   {
1997     res = VariantCopy( pvargDest, pvargSrc );
1998   }
1999
2000   return res;
2001 }
2002
2003 /******************************************************************************
2004  * Coerces a full safearray. Not optimal code.
2005  */
2006 static HRESULT
2007 coerce_array(
2008         VARIANTARG* src, VARIANTARG *dst, LCID lcid, USHORT wFlags, VARTYPE vt
2009 ) {
2010         SAFEARRAY       *sarr = V_ARRAY(src);
2011         HRESULT         hres;
2012         LPVOID          data;
2013         VARTYPE         vartype;
2014
2015         SafeArrayGetVartype(sarr,&vartype);
2016         switch (vt) {
2017         case VT_BSTR:
2018                 if (sarr->cDims != 1) {
2019                         FIXME("Can not coerce array with dim %d into BSTR\n", sarr->cDims);
2020                         return E_FAIL;
2021                 }
2022                 switch (V_VT(src) & VT_TYPEMASK) {
2023                 case VT_UI1:
2024                         hres = SafeArrayAccessData(sarr, &data);
2025                         if (FAILED(hres)) return hres;
2026
2027                         /* Yes, just memcpied apparently. */
2028                         V_BSTR(dst) = SysAllocStringByteLen(data, sarr->rgsabound[0].cElements);
2029                         hres = SafeArrayUnaccessData(sarr);
2030                         if (FAILED(hres)) return hres;
2031                         break;
2032                 default:
2033                         FIXME("Cannot coerce array of %d into BSTR yet. Please report!\n", V_VT(src) & VT_TYPEMASK);
2034                         return E_FAIL;
2035                 }
2036                 break;
2037         case VT_SAFEARRAY:
2038                 V_VT(dst) = VT_SAFEARRAY;
2039                 return SafeArrayCopy(sarr, &V_ARRAY(dst));
2040         default:
2041                 FIXME("Cannot coerce array of vt 0x%x/0x%x into vt 0x%x yet. Please report/implement!\n", vartype, V_VT(src), vt);
2042                 return E_FAIL;
2043         }
2044         return S_OK;
2045 }
2046
2047 /******************************************************************************
2048  *              VariantChangeType       [OLEAUT32.12]
2049  *
2050  * Change the type of a variant.
2051  *  
2052  * PARAMS
2053  *  pvargDest [O] Destination for the converted variant
2054  *  pvargSrc  [O] Source variant to change the type of
2055  *  wFlags    [I] VARIANT_ flags from "oleauto.h"
2056  *  vt        [I] Variant type to change pvargSrc into
2057  *    
2058  * RETURNS
2059  *  Success: S_OK. pvargDest contains the converted value.
2060  *  Failure: An HRESULT error code describing the failure.
2061  *    
2062  * NOTES
2063  *  The LCID used for the conversion is LOCALE_USER_DEFAULT.
2064  *  See VariantChangeTypeEx.
2065  */
2066 HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2067                                                         USHORT wFlags, VARTYPE vt)
2068 {
2069         return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
2070 }
2071
2072 /******************************************************************************
2073  *              VariantChangeTypeEx     [OLEAUT32.147]
2074  *
2075  * Change the type of a variant.
2076  *  
2077  * PARAMS
2078  *  pvargDest [O] Destination for the converted variant
2079  *  pvargSrc  [O] Source variant to change the type of
2080  *  lcid      [I] LCID for the conversion
2081  *  wFlags    [I] VARIANT_ flags from "oleauto.h"
2082  *  vt        [I] Variant type to change pvargSrc into
2083  *  
2084  * RETURNS
2085  *  Success: S_OK. pvargDest contains the converted value.
2086  *  Failure: An HRESULT error code describing the failure.
2087  *
2088  * NOTES
2089  *  pvargDest and pvargSrc can point to the same variant to perform an in-place
2090  *  conversion. If the conversion is successful, pvargSrc will be freed.
2091  */
2092 HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2093                                                           LCID lcid, USHORT wFlags, VARTYPE vt)
2094 {
2095         HRESULT res = S_OK;
2096         VARIANTARG varg;
2097         VariantInit( &varg );
2098
2099         TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
2100     TRACE("Src Var:\n");
2101     dump_Variant(pvargSrc);
2102
2103         /* validate our source argument.
2104          */
2105         res = ValidateVariantType( V_VT(pvargSrc) );
2106
2107         /* validate the vartype.
2108          */
2109         if( res == S_OK )
2110         {
2111                 res = ValidateVt( vt );
2112         }
2113
2114         /* if we are doing an in-place conversion make a copy of the source.
2115          */
2116         if( res == S_OK && pvargDest == pvargSrc )
2117         {
2118                 res = VariantCopy( &varg, pvargSrc );
2119                 pvargSrc = &varg;
2120         }
2121
2122         if( res == S_OK )
2123         {
2124                 /* free up the destination variant.
2125                  */
2126                 res = VariantClear( pvargDest );
2127         }
2128
2129         if( res == S_OK )
2130         {
2131                 if( V_VT(pvargSrc) & VT_BYREF )
2132                 {
2133                         /* Convert the source variant to a "byvalue" variant.
2134                          */
2135                         VARIANTARG Variant;
2136
2137                         if ((V_VT(pvargSrc) & 0xf000) != VT_BYREF) {
2138                                 FIXME("VT_TYPEMASK %x is unhandled.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2139                                 return E_FAIL;
2140                         }
2141
2142                         VariantInit( &Variant );
2143                         res = VariantCopyInd( &Variant, pvargSrc );
2144                         if( res == S_OK )
2145                         {
2146                                 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2147                                 /* this should not fail.
2148                                  */
2149                                 VariantClear( &Variant );
2150                         }
2151                 } else {
2152                         if (V_VT(pvargSrc) & VT_ARRAY) {
2153                                 if ((V_VT(pvargSrc) & 0xf000) != VT_ARRAY) {
2154                                         FIXME("VT_TYPEMASK %x is unhandled in VT_ARRAY.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2155                                         return E_FAIL;
2156                                 }
2157                                 V_VT(pvargDest) = VT_ARRAY | vt;
2158                                 res = coerce_array(pvargSrc, pvargDest, lcid, wFlags, vt);
2159                         } else {
2160                                 if ((V_VT(pvargSrc) & 0xf000)) {
2161                                         FIXME("VT_TYPEMASK %x is unhandled in normal case.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2162                                         return E_FAIL;
2163                                 }
2164                                 /* Use the current "byvalue" source variant.
2165                                  */
2166                                 res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2167                         }
2168                 }
2169         }
2170         /* this should not fail.
2171          */
2172         VariantClear( &varg );
2173
2174         /* set the type of the destination
2175          */
2176         if ( res == S_OK )
2177                 V_VT(pvargDest) = vt;
2178
2179     TRACE("Dest Var:\n");
2180     dump_Variant(pvargDest);
2181
2182         return res;
2183 }
2184
2185
2186
2187
2188 /******************************************************************************
2189  *              VarUI1FromI2            [OLEAUT32.130]
2190  */
2191 HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2192 {
2193         TRACE("( %d, %p ), stub\n", sIn, pbOut );
2194
2195         /* Check range of value.
2196          */
2197         if( sIn < UI1_MIN || sIn > UI1_MAX )
2198         {
2199                 return DISP_E_OVERFLOW;
2200         }
2201
2202         *pbOut = (BYTE) sIn;
2203
2204         return S_OK;
2205 }
2206
2207 /******************************************************************************
2208  *              VarUI1FromI4            [OLEAUT32.131]
2209  */
2210 HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2211 {
2212         TRACE("( %ld, %p ), stub\n", lIn, pbOut );
2213
2214         /* Check range of value.
2215          */
2216         if( lIn < UI1_MIN || lIn > UI1_MAX )
2217         {
2218                 return DISP_E_OVERFLOW;
2219         }
2220
2221         *pbOut = (BYTE) lIn;
2222
2223         return S_OK;
2224 }
2225
2226
2227 /******************************************************************************
2228  *              VarUI1FromR4            [OLEAUT32.132]
2229  */
2230 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2231 {
2232         TRACE("( %f, %p ), stub\n", fltIn, pbOut );
2233
2234         /* Check range of value.
2235      */
2236     fltIn = round( fltIn );
2237         if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2238         {
2239                 return DISP_E_OVERFLOW;
2240         }
2241
2242         *pbOut = (BYTE) fltIn;
2243
2244         return S_OK;
2245 }
2246
2247 /******************************************************************************
2248  *              VarUI1FromR8            [OLEAUT32.133]
2249  */
2250 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2251 {
2252         TRACE("( %f, %p ), stub\n", dblIn, pbOut );
2253
2254         /* Check range of value.
2255      */
2256     dblIn = round( dblIn );
2257         if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2258         {
2259                 return DISP_E_OVERFLOW;
2260         }
2261
2262         *pbOut = (BYTE) dblIn;
2263
2264         return S_OK;
2265 }
2266
2267 /******************************************************************************
2268  *              VarUI1FromDate          [OLEAUT32.135]
2269  */
2270 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2271 {
2272         TRACE("( %f, %p ), stub\n", dateIn, pbOut );
2273
2274         /* Check range of value.
2275      */
2276     dateIn = round( dateIn );
2277         if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2278         {
2279                 return DISP_E_OVERFLOW;
2280         }
2281
2282         *pbOut = (BYTE) dateIn;
2283
2284         return S_OK;
2285 }
2286
2287 /******************************************************************************
2288  *              VarUI1FromBool          [OLEAUT32.138]
2289  */
2290 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2291 {
2292         TRACE("( %d, %p ), stub\n", boolIn, pbOut );
2293
2294         *pbOut = (BYTE) boolIn;
2295
2296         return S_OK;
2297 }
2298
2299 /******************************************************************************
2300  *              VarUI1FromI1            [OLEAUT32.237]
2301  */
2302 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
2303 {
2304         TRACE("( %c, %p ), stub\n", cIn, pbOut );
2305
2306         *pbOut = cIn;
2307
2308         return S_OK;
2309 }
2310
2311 /******************************************************************************
2312  *              VarUI1FromUI2           [OLEAUT32.238]
2313  */
2314 HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2315 {
2316         TRACE("( %d, %p ), stub\n", uiIn, pbOut );
2317
2318         /* Check range of value.
2319          */
2320         if( uiIn > UI1_MAX )
2321         {
2322                 return DISP_E_OVERFLOW;
2323         }
2324
2325         *pbOut = (BYTE) uiIn;
2326
2327         return S_OK;
2328 }
2329
2330 /******************************************************************************
2331  *              VarUI1FromUI4           [OLEAUT32.239]
2332  */
2333 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2334 {
2335         TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
2336
2337         /* Check range of value.
2338          */
2339         if( ulIn > UI1_MAX )
2340         {
2341                 return DISP_E_OVERFLOW;
2342         }
2343
2344         *pbOut = (BYTE) ulIn;
2345
2346         return S_OK;
2347 }
2348
2349
2350 /******************************************************************************
2351  *              VarUI1FromStr           [OLEAUT32.136]
2352  */
2353 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2354 {
2355   TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pbOut);
2356   return _VarUI1FromStr(strIn, lcid, dwFlags, pbOut);
2357 }
2358
2359 /**********************************************************************
2360  *              VarUI1FromCy [OLEAUT32.134]
2361  * Convert currency to unsigned char
2362  */
2363 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
2364    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2365
2366    if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
2367
2368    *pbOut = (BYTE)t;
2369    return S_OK;
2370 }
2371
2372 /******************************************************************************
2373  *              VarI2FromUI1            [OLEAUT32.48]
2374  */
2375 HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2376 {
2377         TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
2378
2379         *psOut = (short) bIn;
2380
2381         return S_OK;
2382 }
2383
2384 /******************************************************************************
2385  *              VarI2FromI4             [OLEAUT32.49]
2386  */
2387 HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2388 {
2389         TRACE("( %lx, %p ), stub\n", lIn, psOut );
2390
2391         /* Check range of value.
2392          */
2393         if( lIn < I2_MIN || lIn > I2_MAX )
2394         {
2395                 return DISP_E_OVERFLOW;
2396         }
2397
2398         *psOut = (short) lIn;
2399
2400         return S_OK;
2401 }
2402
2403 /******************************************************************************
2404  *              VarI2FromR4             [OLEAUT32.50]
2405  */
2406 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2407 {
2408         TRACE("( %f, %p ), stub\n", fltIn, psOut );
2409
2410         /* Check range of value.
2411      */
2412     fltIn = round( fltIn );
2413         if( fltIn < I2_MIN || fltIn > I2_MAX )
2414         {
2415                 return DISP_E_OVERFLOW;
2416         }
2417
2418         *psOut = (short) fltIn;
2419
2420         return S_OK;
2421 }
2422
2423 /******************************************************************************
2424  *              VarI2FromR8             [OLEAUT32.51]
2425  */
2426 HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2427 {
2428         TRACE("( %f, %p ), stub\n", dblIn, psOut );
2429
2430         /* Check range of value.
2431      */
2432     dblIn = round( dblIn );
2433         if( dblIn < I2_MIN || dblIn > I2_MAX )
2434         {
2435                 return DISP_E_OVERFLOW;
2436         }
2437
2438         *psOut = (short) dblIn;
2439
2440         return S_OK;
2441 }
2442
2443 /******************************************************************************
2444  *              VarI2FromDate           [OLEAUT32.53]
2445  */
2446 HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2447 {
2448         TRACE("( %f, %p ), stub\n", dateIn, psOut );
2449
2450         /* Check range of value.
2451      */
2452     dateIn = round( dateIn );
2453         if( dateIn < I2_MIN || dateIn > I2_MAX )
2454         {
2455                 return DISP_E_OVERFLOW;
2456         }
2457
2458         *psOut = (short) dateIn;
2459
2460         return S_OK;
2461 }
2462
2463 /******************************************************************************
2464  *              VarI2FromBool           [OLEAUT32.56]
2465  */
2466 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2467 {
2468         TRACE("( %d, %p ), stub\n", boolIn, psOut );
2469
2470         *psOut = (short) boolIn;
2471
2472         return S_OK;
2473 }
2474
2475 /******************************************************************************
2476  *              VarI2FromI1             [OLEAUT32.205]
2477  */
2478 HRESULT WINAPI VarI2FromI1(signed char cIn, short* psOut)
2479 {
2480         TRACE("( %c, %p ), stub\n", cIn, psOut );
2481
2482         *psOut = (short) cIn;
2483
2484         return S_OK;
2485 }
2486
2487 /******************************************************************************
2488  *              VarI2FromUI2            [OLEAUT32.206]
2489  */
2490 HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2491 {
2492         TRACE("( %d, %p ), stub\n", uiIn, psOut );
2493
2494         /* Check range of value.
2495          */
2496         if( uiIn > I2_MAX )
2497         {
2498                 return DISP_E_OVERFLOW;
2499         }
2500
2501         *psOut = (short) uiIn;
2502
2503         return S_OK;
2504 }
2505
2506 /******************************************************************************
2507  *              VarI2FromUI4            [OLEAUT32.207]
2508  */
2509 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2510 {
2511         TRACE("( %lx, %p ), stub\n", ulIn, psOut );
2512
2513         /* Check range of value.
2514          */
2515         if( ulIn < I2_MIN || ulIn > I2_MAX )
2516         {
2517                 return DISP_E_OVERFLOW;
2518         }
2519
2520         *psOut = (short) ulIn;
2521
2522         return S_OK;
2523 }
2524
2525 /******************************************************************************
2526  *              VarI2FromStr            [OLEAUT32.54]
2527  */
2528 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2529 {
2530   TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, psOut);
2531   return _VarI2FromStr(strIn, lcid, dwFlags, psOut);
2532 }
2533
2534 /**********************************************************************
2535  *              VarI2FromCy [OLEAUT32.52]
2536  * Convert currency to signed short
2537  */
2538 HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
2539    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2540
2541    if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
2542
2543    *psOut = (SHORT)t;
2544    return S_OK;
2545 }
2546
2547 /******************************************************************************
2548  *              VarI4FromUI1            [OLEAUT32.58]
2549  */
2550 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2551 {
2552         TRACE("( %X, %p ), stub\n", bIn, plOut );
2553
2554         *plOut = (LONG) bIn;
2555
2556         return S_OK;
2557 }
2558
2559
2560 /******************************************************************************
2561  *              VarI4FromR4             [OLEAUT32.60]
2562  */
2563 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2564 {
2565         TRACE("( %f, %p ), stub\n", fltIn, plOut );
2566
2567         /* Check range of value.
2568      */
2569     fltIn = round( fltIn );
2570         if( fltIn < I4_MIN || fltIn > I4_MAX )
2571         {
2572                 return DISP_E_OVERFLOW;
2573         }
2574
2575         *plOut = (LONG) fltIn;
2576
2577         return S_OK;
2578 }
2579
2580 /******************************************************************************
2581  *              VarI4FromR8             [OLEAUT32.61]
2582  */
2583 HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2584 {
2585         TRACE("( %f, %p ), stub\n", dblIn, plOut );
2586
2587         /* Check range of value.
2588      */
2589     dblIn = round( dblIn );
2590         if( dblIn < I4_MIN || dblIn > I4_MAX )
2591         {
2592                 return DISP_E_OVERFLOW;
2593         }
2594
2595         *plOut = (LONG) dblIn;
2596
2597         return S_OK;
2598 }
2599
2600 /******************************************************************************
2601  *              VarI4FromDate           [OLEAUT32.63]
2602  */
2603 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2604 {
2605         TRACE("( %f, %p ), stub\n", dateIn, plOut );
2606
2607         /* Check range of value.
2608      */
2609     dateIn = round( dateIn );
2610         if( dateIn < I4_MIN || dateIn > I4_MAX )
2611         {
2612                 return DISP_E_OVERFLOW;
2613         }
2614
2615         *plOut = (LONG) dateIn;
2616
2617         return S_OK;
2618 }
2619
2620 /******************************************************************************
2621  *              VarI4FromBool           [OLEAUT32.66]
2622  */
2623 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2624 {
2625         TRACE("( %d, %p ), stub\n", boolIn, plOut );
2626
2627         *plOut = (LONG) boolIn;
2628
2629         return S_OK;
2630 }
2631
2632 /******************************************************************************
2633  *              VarI4FromI1             [OLEAUT32.209]
2634  */
2635 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG* plOut)
2636 {
2637         TRACE("( %c, %p ), stub\n", cIn, plOut );
2638
2639         *plOut = (LONG) cIn;
2640
2641         return S_OK;
2642 }
2643
2644 /******************************************************************************
2645  *              VarI4FromUI2            [OLEAUT32.210]
2646  */
2647 HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2648 {
2649         TRACE("( %d, %p ), stub\n", uiIn, plOut );
2650
2651         *plOut = (LONG) uiIn;
2652
2653         return S_OK;
2654 }
2655
2656 /******************************************************************************
2657  *              VarI4FromUI4            [OLEAUT32.211]
2658  */
2659 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2660 {
2661         TRACE("( %lx, %p ), stub\n", ulIn, plOut );
2662
2663         /* Check range of value.
2664          */
2665         if( ulIn < I4_MIN || ulIn > I4_MAX )
2666         {
2667                 return DISP_E_OVERFLOW;
2668         }
2669
2670         *plOut = (LONG) ulIn;
2671
2672         return S_OK;
2673 }
2674
2675 /******************************************************************************
2676  *              VarI4FromI2             [OLEAUT32.59]
2677  */
2678 HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2679 {
2680         TRACE("( %d, %p ), stub\n", sIn, plOut );
2681
2682         *plOut = (LONG) sIn;
2683
2684         return S_OK;
2685 }
2686
2687 /******************************************************************************
2688  *              VarI4FromStr            [OLEAUT32.64]
2689  */
2690 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2691 {
2692   TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, plOut);
2693   return _VarI4FromStr(strIn, lcid, dwFlags, plOut);
2694 }
2695
2696 /**********************************************************************
2697  *              VarI4FromCy [OLEAUT32.62]
2698  * Convert currency to signed long
2699  */
2700 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
2701    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2702
2703    if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
2704
2705    *plOut = (LONG)t;
2706    return S_OK;
2707 }
2708
2709 /******************************************************************************
2710  *              VarR4FromUI1            [OLEAUT32.68]
2711  */
2712 HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
2713 {
2714         TRACE("( %X, %p ), stub\n", bIn, pfltOut );
2715
2716         *pfltOut = (FLOAT) bIn;
2717
2718         return S_OK;
2719 }
2720
2721 /******************************************************************************
2722  *              VarR4FromI2             [OLEAUT32.69]
2723  */
2724 HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
2725 {
2726         TRACE("( %d, %p ), stub\n", sIn, pfltOut );
2727
2728         *pfltOut = (FLOAT) sIn;
2729
2730         return S_OK;
2731 }
2732
2733 /******************************************************************************
2734  *              VarR4FromI4             [OLEAUT32.70]
2735  */
2736 HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
2737 {
2738         TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
2739
2740         *pfltOut = (FLOAT) lIn;
2741
2742         return S_OK;
2743 }
2744
2745 /******************************************************************************
2746  *              VarR4FromR8             [OLEAUT32.71]
2747  */
2748 HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
2749 {
2750         TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
2751
2752         /* Check range of value.
2753          */
2754         if( dblIn < -(R4_MAX) || dblIn > R4_MAX )
2755         {
2756                 return DISP_E_OVERFLOW;
2757         }
2758
2759         *pfltOut = (FLOAT) dblIn;
2760
2761         return S_OK;
2762 }
2763
2764 /******************************************************************************
2765  *              VarR4FromDate           [OLEAUT32.73]
2766  */
2767 HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
2768 {
2769         TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
2770
2771         /* Check range of value.
2772          */
2773         if( dateIn < -(R4_MAX) || dateIn > R4_MAX )
2774         {
2775                 return DISP_E_OVERFLOW;
2776         }
2777
2778         *pfltOut = (FLOAT) dateIn;
2779
2780         return S_OK;
2781 }
2782
2783 /******************************************************************************
2784  *              VarR4FromBool           [OLEAUT32.76]
2785  */
2786 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
2787 {
2788         TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
2789
2790         *pfltOut = (FLOAT) boolIn;
2791
2792         return S_OK;
2793 }
2794
2795 /******************************************************************************
2796  *              VarR4FromI1             [OLEAUT32.213]
2797  */
2798 HRESULT WINAPI VarR4FromI1(signed char cIn, FLOAT* pfltOut)
2799 {
2800         TRACE("( %c, %p ), stub\n", cIn, pfltOut );
2801
2802         *pfltOut = (FLOAT) cIn;
2803
2804         return S_OK;
2805 }
2806
2807 /******************************************************************************
2808  *              VarR4FromUI2            [OLEAUT32.214]
2809  */
2810 HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
2811 {
2812         TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
2813
2814         *pfltOut = (FLOAT) uiIn;
2815
2816         return S_OK;
2817 }
2818
2819 /******************************************************************************
2820  *              VarR4FromUI4            [OLEAUT32.215]
2821  */
2822 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
2823 {
2824         TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
2825
2826         *pfltOut = (FLOAT) ulIn;
2827
2828         return S_OK;
2829 }
2830
2831 /******************************************************************************
2832  *              VarR4FromStr            [OLEAUT32.74]
2833  */
2834 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
2835 {
2836   TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pfltOut);
2837   return _VarR4FromStr(strIn, lcid, dwFlags, pfltOut);
2838 }
2839
2840 /**********************************************************************
2841  *              VarR4FromCy [OLEAUT32.72]
2842  * Convert currency to float
2843  */
2844 HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
2845    *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2846
2847    return S_OK;
2848 }
2849
2850 /******************************************************************************
2851  *              VarR8FromUI1            [OLEAUT32.78]
2852  */
2853 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
2854 {
2855         TRACE("( %d, %p ), stub\n", bIn, pdblOut );
2856
2857         *pdblOut = (double) bIn;
2858
2859         return S_OK;
2860 }
2861
2862 /******************************************************************************
2863  *              VarR8FromI2             [OLEAUT32.79]
2864  */
2865 HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
2866 {
2867         TRACE("( %d, %p ), stub\n", sIn, pdblOut );
2868
2869         *pdblOut = (double) sIn;
2870
2871         return S_OK;
2872 }
2873
2874 /******************************************************************************
2875  *              VarR8FromI4             [OLEAUT32.80]
2876  */
2877 HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
2878 {
2879         TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
2880
2881         *pdblOut = (double) lIn;
2882
2883         return S_OK;
2884 }
2885
2886 /******************************************************************************
2887  *              VarR8FromR4             [OLEAUT32.81]
2888  */
2889 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
2890 {
2891         TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
2892
2893         *pdblOut = (double) fltIn;
2894
2895         return S_OK;
2896 }
2897
2898 /******************************************************************************
2899  *              VarR8FromDate           [OLEAUT32.83]
2900  */
2901 HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
2902 {
2903         TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
2904
2905         *pdblOut = (double) dateIn;
2906
2907         return S_OK;
2908 }
2909
2910 /******************************************************************************
2911  *              VarR8FromBool           [OLEAUT32.86]
2912  */
2913 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
2914 {
2915         TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
2916
2917         *pdblOut = (double) boolIn;
2918
2919         return S_OK;
2920 }
2921
2922 /******************************************************************************
2923  *              VarR8FromI1             [OLEAUT32.217]
2924  */
2925 HRESULT WINAPI VarR8FromI1(signed char cIn, double* pdblOut)
2926 {
2927         TRACE("( %c, %p ), stub\n", cIn, pdblOut );
2928
2929         *pdblOut = (double) cIn;
2930
2931         return S_OK;
2932 }
2933
2934 /******************************************************************************
2935  *              VarR8FromUI2            [OLEAUT32.218]
2936  */
2937 HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
2938 {
2939         TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
2940
2941         *pdblOut = (double) uiIn;
2942
2943         return S_OK;
2944 }
2945
2946 /******************************************************************************
2947  *              VarR8FromUI4            [OLEAUT32.219]
2948  */
2949 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
2950 {
2951         TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
2952
2953         *pdblOut = (double) ulIn;
2954
2955         return S_OK;
2956 }
2957
2958 /******************************************************************************
2959  *              VarR8FromStr            [OLEAUT32.84]
2960  */
2961 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
2962 {
2963   TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pdblOut);
2964   return _VarR8FromStr(strIn, lcid, dwFlags, pdblOut);
2965 }
2966
2967 /**********************************************************************
2968  *              VarR8FromCy [OLEAUT32.82]
2969  * Convert currency to double
2970  */
2971 HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
2972    *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2973    TRACE("%lu %ld -> %f\n", cyIn.s.Hi, cyIn.s.Lo, *pdblOut);
2974    return S_OK;
2975 }
2976
2977 /******************************************************************************
2978  *              VarDateFromUI1          [OLEAUT32.88]
2979  */
2980 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
2981 {
2982         TRACE("( %d, %p ), stub\n", bIn, pdateOut );
2983
2984         *pdateOut = (DATE) bIn;
2985
2986         return S_OK;
2987 }
2988
2989 /******************************************************************************
2990  *              VarDateFromI2           [OLEAUT32.89]
2991  */
2992 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
2993 {
2994         TRACE("( %d, %p ), stub\n", sIn, pdateOut );
2995
2996         *pdateOut = (DATE) sIn;
2997
2998         return S_OK;
2999 }
3000
3001 /******************************************************************************
3002  *              VarDateFromI4           [OLEAUT32.90]
3003  */
3004 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3005 {
3006         TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
3007
3008         if( lIn < DATE_MIN || lIn > DATE_MAX )
3009         {
3010                 return DISP_E_OVERFLOW;
3011         }
3012
3013         *pdateOut = (DATE) lIn;
3014
3015         return S_OK;
3016 }
3017
3018 /******************************************************************************
3019  *              VarDateFromR4           [OLEAUT32.91]
3020  */
3021 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3022 {
3023     TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3024
3025     if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
3026         {
3027                 return DISP_E_OVERFLOW;
3028         }
3029
3030         *pdateOut = (DATE) fltIn;
3031
3032         return S_OK;
3033 }
3034
3035 /******************************************************************************
3036  *              VarDateFromR8           [OLEAUT32.92]
3037  */
3038 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3039 {
3040     TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3041
3042         if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3043         {
3044                 return DISP_E_OVERFLOW;
3045         }
3046
3047         *pdateOut = (DATE) dblIn;
3048
3049         return S_OK;
3050 }
3051
3052 /******************************************************************************
3053  *              VarDateFromStr          [OLEAUT32.94]
3054  * The string representing the date is composed of two parts, a date and time.
3055  *
3056  * The format of the time is has follows:
3057  * hh[:mm][:ss][AM|PM]
3058  * Whitespace can be inserted anywhere between these tokens.  A whitespace consists
3059  * of space and/or tab characters, which are ignored.
3060  *
3061  * The formats for the date part are has follows:
3062  * mm/[dd/][yy]yy
3063  * [dd/]mm/[yy]yy
3064  * [yy]yy/mm/dd
3065  * January dd[,] [yy]yy
3066  * dd January [yy]yy
3067  * [yy]yy January dd
3068  * Whitespace can be inserted anywhere between these tokens.
3069  *
3070  * The formats for the date and time string are has follows.
3071  * date[whitespace][time]
3072  * [time][whitespace]date
3073  *
3074  * These are the only characters allowed in a string representing a date and time:
3075  * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3076  */
3077 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3078 {
3079     HRESULT ret = S_OK;
3080     struct tm TM;
3081
3082     memset( &TM, 0, sizeof(TM) );
3083
3084     TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3085
3086     if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
3087     {
3088         if( TmToDATE( &TM, pdateOut ) == FALSE )
3089         {
3090             ret = E_INVALIDARG;
3091         }
3092     }
3093     else
3094     {
3095         ret = DISP_E_TYPEMISMATCH;
3096     }
3097     TRACE("Return value %f\n", *pdateOut);
3098         return ret;
3099 }
3100
3101 /******************************************************************************
3102  *              VarDateFromI1           [OLEAUT32.221]
3103  */
3104 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
3105 {
3106         TRACE("( %c, %p ), stub\n", cIn, pdateOut );
3107
3108         *pdateOut = (DATE) cIn;
3109
3110         return S_OK;
3111 }
3112
3113 /******************************************************************************
3114  *              VarDateFromUI2          [OLEAUT32.222]
3115  */
3116 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3117 {
3118         TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
3119
3120         *pdateOut = (DATE) uiIn;
3121
3122         return S_OK;
3123 }
3124
3125 /******************************************************************************
3126  *              VarDateFromUI4          [OLEAUT32.223]
3127  */
3128 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3129 {
3130         TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
3131
3132         if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3133         {
3134                 return DISP_E_OVERFLOW;
3135         }
3136
3137         *pdateOut = (DATE) ulIn;
3138
3139         return S_OK;
3140 }
3141
3142 /******************************************************************************
3143  *              VarDateFromBool         [OLEAUT32.96]
3144  */
3145 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3146 {
3147         TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
3148
3149         *pdateOut = (DATE) boolIn;
3150
3151         return S_OK;
3152 }
3153
3154 /**********************************************************************
3155  *              VarDateFromCy [OLEAUT32.93]
3156  * Convert currency to date
3157  */
3158 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
3159    *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3160
3161    if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3162    return S_OK;
3163 }
3164
3165 /******************************************************************************
3166  *              VarBstrFromUI1          [OLEAUT32.108]
3167  */
3168 HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3169 {
3170         TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3171         sprintf( pBuffer, "%d", bVal );
3172
3173         *pbstrOut =  StringDupAtoBstr( pBuffer );
3174
3175         return S_OK;
3176 }
3177
3178 /******************************************************************************
3179  *              VarBstrFromI2           [OLEAUT32.109]
3180  */
3181 HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3182 {
3183         TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3184         sprintf( pBuffer, "%d", iVal );
3185         *pbstrOut = StringDupAtoBstr( pBuffer );
3186
3187         return S_OK;
3188 }
3189
3190 /******************************************************************************
3191  *              VarBstrFromI4           [OLEAUT32.110]
3192  */
3193 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3194 {
3195         TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
3196
3197         sprintf( pBuffer, "%ld", lIn );
3198         *pbstrOut = StringDupAtoBstr( pBuffer );
3199
3200         return S_OK;
3201 }
3202
3203 /******************************************************************************
3204  *              VarBstrFromR4           [OLEAUT32.111]
3205  */
3206 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3207 {
3208         TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
3209
3210         sprintf( pBuffer, "%.7G", fltIn );
3211         *pbstrOut = StringDupAtoBstr( pBuffer );
3212
3213         return S_OK;
3214 }
3215
3216 /******************************************************************************
3217  *              VarBstrFromR8           [OLEAUT32.112]
3218  */
3219 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3220 {
3221         TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
3222
3223         sprintf( pBuffer, "%.15G", dblIn );
3224         *pbstrOut = StringDupAtoBstr( pBuffer );
3225
3226         return S_OK;
3227 }
3228
3229 /******************************************************************************
3230  *    VarBstrFromCy   [OLEAUT32.113]
3231  */
3232 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
3233     HRESULT rc = S_OK;
3234     double curVal = 0.0;
3235
3236         TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid, dwFlags, pbstrOut);
3237
3238     /* Firstly get the currency in a double, then put it in a buffer */
3239     rc = VarR8FromCy(cyIn, &curVal);
3240     if (rc == S_OK) {
3241         sprintf(pBuffer, "%G", curVal);
3242         *pbstrOut = StringDupAtoBstr( pBuffer );
3243     }
3244         return rc;
3245 }
3246
3247
3248 /******************************************************************************
3249  *              VarBstrFromDate         [OLEAUT32.114]
3250  *
3251  * The date is implemented using an 8 byte floating-point number.
3252  * Days are represented by whole numbers increments starting with 0.00 as
3253  * being December 30 1899, midnight.
3254  * The hours are expressed as the fractional part of the number.
3255  * December 30 1899 at midnight = 0.00
3256  * January 1 1900 at midnight = 2.00
3257  * January 4 1900 at 6 AM = 5.25
3258  * January 4 1900 at noon = 5.50
3259  * December 29 1899 at midnight = -1.00
3260  * December 18 1899 at midnight = -12.00
3261  * December 18 1899 at 6AM = -12.25
3262  * December 18 1899 at 6PM = -12.75
3263  * December 19 1899 at midnight = -11.00
3264  * The tm structure is as follows:
3265  * struct tm {
3266  *                int tm_sec;      seconds after the minute - [0,59]
3267  *                int tm_min;      minutes after the hour - [0,59]
3268  *                int tm_hour;     hours since midnight - [0,23]
3269  *                int tm_mday;     day of the month - [1,31]
3270  *                int tm_mon;      months since January - [0,11]
3271  *                int tm_year;     years
3272  *                int tm_wday;     days since Sunday - [0,6]
3273  *                int tm_yday;     days since January 1 - [0,365]
3274  *                int tm_isdst;    daylight savings time flag
3275  *                };
3276  */
3277 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3278 {
3279     struct tm TM;
3280     memset( &TM, 0, sizeof(TM) );
3281
3282     TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
3283
3284     if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
3285                         {
3286         return E_INVALIDARG;
3287                 }
3288
3289     if( dwFlags & VAR_DATEVALUEONLY )
3290                         strftime( pBuffer, BUFFER_MAX, "%x", &TM );
3291     else if( dwFlags & VAR_TIMEVALUEONLY )
3292                         strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3293                 else
3294         strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3295
3296         TRACE("result: %s\n", pBuffer);
3297                 *pbstrOut = StringDupAtoBstr( pBuffer );
3298         return S_OK;
3299 }
3300
3301 /******************************************************************************
3302  *              VarBstrFromBool         [OLEAUT32.116]
3303  */
3304 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3305 {
3306         TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
3307
3308         sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
3309
3310         *pbstrOut = StringDupAtoBstr( pBuffer );
3311
3312         return S_OK;
3313 }
3314
3315 /******************************************************************************
3316  *              VarBstrFromI1           [OLEAUT32.229]
3317  */
3318 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3319 {
3320         TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3321         sprintf( pBuffer, "%d", cIn );
3322         *pbstrOut = StringDupAtoBstr( pBuffer );
3323
3324         return S_OK;
3325 }
3326
3327 /******************************************************************************
3328  *              VarBstrFromUI2          [OLEAUT32.230]
3329  */
3330 HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3331 {
3332         TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3333         sprintf( pBuffer, "%d", uiIn );
3334         *pbstrOut = StringDupAtoBstr( pBuffer );
3335
3336         return S_OK;
3337 }
3338
3339 /******************************************************************************
3340  *              VarBstrFromUI4          [OLEAUT32.231]
3341  */
3342 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3343 {
3344         TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3345         sprintf( pBuffer, "%ld", ulIn );
3346         *pbstrOut = StringDupAtoBstr( pBuffer );
3347
3348         return S_OK;
3349 }
3350
3351 /******************************************************************************
3352  *              VarBstrFromDec          [OLEAUT32.@]
3353  */
3354 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3355 {
3356         if(!pDecIn->u.s.sign && !pDecIn->u.s.scale &&
3357            !pDecIn->Hi32 && !pDecIn->u1.s1.Mid32)
3358             return VarBstrFromUI4(pDecIn->u1.s1.Lo32, lcid, dwFlags, pbstrOut);
3359         FIXME("%c%08lx%08lx%08lx E%02x stub\n",
3360         (pDecIn->u.s.sign == DECIMAL_NEG) ? '-' :
3361         (pDecIn->u.s.sign == 0) ? '+' : '?',
3362         pDecIn->Hi32, pDecIn->u1.s1.Mid32, pDecIn->u1.s1.Lo32,
3363         pDecIn->u.s.scale);
3364         return E_INVALIDARG;
3365 }
3366
3367 /******************************************************************************
3368  *              VarBoolFromUI1          [OLEAUT32.118]
3369  */
3370 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3371 {
3372         TRACE("( %d, %p ), stub\n", bIn, pboolOut );
3373
3374         if( bIn == 0 )
3375         {
3376                 *pboolOut = VARIANT_FALSE;
3377         }
3378         else
3379         {
3380                 *pboolOut = VARIANT_TRUE;
3381         }
3382
3383         return S_OK;
3384 }
3385
3386 /******************************************************************************
3387  *              VarBoolFromI2           [OLEAUT32.119]
3388  */
3389 HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3390 {
3391         TRACE("( %d, %p ), stub\n", sIn, pboolOut );
3392
3393         *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
3394
3395         return S_OK;
3396 }
3397
3398 /******************************************************************************
3399  *              VarBoolFromI4           [OLEAUT32.120]
3400  */
3401 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3402 {
3403         TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
3404
3405         *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
3406
3407         return S_OK;
3408 }
3409
3410 /******************************************************************************
3411  *              VarBoolFromR4           [OLEAUT32.121]
3412  */
3413 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3414 {
3415         TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
3416
3417         *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3418
3419         return S_OK;
3420 }
3421
3422 /******************************************************************************
3423  *              VarBoolFromR8           [OLEAUT32.122]
3424  */
3425 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3426 {
3427         TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
3428
3429         *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3430
3431         return S_OK;
3432 }
3433
3434 /******************************************************************************
3435  *              VarBoolFromDate         [OLEAUT32.123]
3436  */
3437 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3438 {
3439         TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
3440
3441         *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3442
3443         return S_OK;
3444 }
3445
3446 /******************************************************************************
3447  *              VarBoolFromStr          [OLEAUT32.125]
3448  */
3449 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3450 {
3451         static const WCHAR szTrue[] = { 'T','r','u','e','\0' };
3452         static const WCHAR szFalse[] = { 'F','a','l','s','e','\0' };
3453         HRESULT ret = S_OK;
3454
3455         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
3456
3457         if( strIn == NULL || strlenW( strIn ) == 0 )
3458         {
3459                 ret = DISP_E_TYPEMISMATCH;
3460         }
3461
3462         if( ret == S_OK )
3463         {
3464                 if( strcmpiW( (LPCWSTR)strIn, szTrue ) == 0 )
3465                 {
3466                         *pboolOut = VARIANT_TRUE;
3467                 }
3468                 else if( strcmpiW( (LPCWSTR)strIn, szFalse ) == 0 )
3469                 {
3470                         *pboolOut = VARIANT_FALSE;
3471                 }
3472                 else
3473                 {
3474                         /* Try converting the string to a floating point number.
3475                          */
3476                         double dValue = 0.0;
3477                         HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3478                         if( res != S_OK )
3479                         {
3480                                 ret = DISP_E_TYPEMISMATCH;
3481                         }
3482                         else
3483                                 *pboolOut = (dValue == 0.0) ?
3484                                                 VARIANT_FALSE : VARIANT_TRUE;
3485                 }
3486         }
3487
3488         return ret;
3489 }
3490
3491 /******************************************************************************
3492  *              VarBoolFromI1           [OLEAUT32.233]
3493  */
3494 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL* pboolOut)
3495 {
3496         TRACE("( %c, %p ), stub\n", cIn, pboolOut );
3497
3498         *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3499
3500         return S_OK;
3501 }
3502
3503 /******************************************************************************
3504  *              VarBoolFromUI2          [OLEAUT32.234]
3505  */
3506 HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3507 {
3508         TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
3509
3510         *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3511
3512         return S_OK;
3513 }
3514
3515 /******************************************************************************
3516  *              VarBoolFromUI4          [OLEAUT32.235]
3517  */
3518 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3519 {
3520         TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
3521
3522         *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3523
3524         return S_OK;
3525 }
3526
3527 /**********************************************************************
3528  *              VarBoolFromCy [OLEAUT32.124]
3529  * Convert currency to boolean
3530  */
3531 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
3532       if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
3533       else *pboolOut = 0;
3534
3535       return S_OK;
3536 }
3537
3538 /******************************************************************************
3539  *              VarI1FromUI1            [OLEAUT32.244]
3540  */
3541 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char *pcOut)
3542 {
3543         TRACE("( %d, %p ), stub\n", bIn, pcOut );
3544
3545         /* Check range of value.
3546          */
3547         if( bIn > I1_MAX )
3548         {
3549                 return DISP_E_OVERFLOW;
3550         }
3551
3552         *pcOut = (CHAR) bIn;
3553
3554         return S_OK;
3555 }
3556
3557 /******************************************************************************
3558  *              VarI1FromI2             [OLEAUT32.245]
3559  */
3560 HRESULT WINAPI VarI1FromI2(short uiIn, signed char *pcOut)
3561 {
3562         TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3563
3564         if( uiIn > I1_MAX )
3565         {
3566                 return DISP_E_OVERFLOW;
3567         }
3568
3569         *pcOut = (CHAR) uiIn;
3570
3571         return S_OK;
3572 }
3573
3574 /******************************************************************************
3575  *              VarI1FromI4             [OLEAUT32.246]
3576  */
3577 HRESULT WINAPI VarI1FromI4(LONG lIn, signed char *pcOut)
3578 {
3579         TRACE("( %ld, %p ), stub\n", lIn, pcOut );
3580
3581         if( lIn < I1_MIN || lIn > I1_MAX )
3582         {
3583                 return DISP_E_OVERFLOW;
3584         }
3585
3586         *pcOut = (CHAR) lIn;
3587
3588         return S_OK;
3589 }
3590
3591 /******************************************************************************
3592  *              VarI1FromR4             [OLEAUT32.247]
3593  */
3594 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char *pcOut)
3595 {
3596         TRACE("( %f, %p ), stub\n", fltIn, pcOut );
3597
3598     fltIn = round( fltIn );
3599         if( fltIn < I1_MIN || fltIn > I1_MAX )
3600         {
3601                 return DISP_E_OVERFLOW;
3602         }
3603
3604         *pcOut = (CHAR) fltIn;
3605
3606         return S_OK;
3607 }
3608
3609 /******************************************************************************
3610  *              VarI1FromR8             [OLEAUT32.248]
3611  */
3612 HRESULT WINAPI VarI1FromR8(double dblIn, signed char *pcOut)
3613 {
3614         TRACE("( %f, %p ), stub\n", dblIn, pcOut );
3615
3616     dblIn = round( dblIn );
3617     if( dblIn < I1_MIN || dblIn > I1_MAX )
3618         {
3619                 return DISP_E_OVERFLOW;
3620         }
3621
3622         *pcOut = (CHAR) dblIn;
3623
3624         return S_OK;
3625 }
3626
3627 /******************************************************************************
3628  *              VarI1FromDate           [OLEAUT32.249]
3629  */
3630 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char *pcOut)
3631 {
3632         TRACE("( %f, %p ), stub\n", dateIn, pcOut );
3633
3634     dateIn = round( dateIn );
3635         if( dateIn < I1_MIN || dateIn > I1_MAX )
3636         {
3637                 return DISP_E_OVERFLOW;
3638         }
3639
3640         *pcOut = (CHAR) dateIn;
3641
3642         return S_OK;
3643 }
3644
3645 /******************************************************************************
3646  *              VarI1FromStr            [OLEAUT32.251]
3647  */
3648 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char *pcOut)
3649 {
3650   TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pcOut);
3651   return _VarI1FromStr(strIn, lcid, dwFlags, pcOut);
3652 }
3653
3654 /******************************************************************************
3655  *              VarI1FromBool           [OLEAUT32.253]
3656  */
3657 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char *pcOut)
3658 {
3659         TRACE("( %d, %p ), stub\n", boolIn, pcOut );
3660
3661         *pcOut = (CHAR) boolIn;
3662
3663         return S_OK;
3664 }
3665
3666 /******************************************************************************
3667  *              VarI1FromUI2            [OLEAUT32.254]
3668  */
3669 HRESULT WINAPI VarI1FromUI2(USHORT uiIn, signed char *pcOut)
3670 {
3671         TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3672
3673         if( uiIn > I1_MAX )
3674         {
3675                 return DISP_E_OVERFLOW;
3676         }
3677
3678         *pcOut = (CHAR) uiIn;
3679
3680         return S_OK;
3681 }
3682
3683 /******************************************************************************
3684  *              VarI1FromUI4            [OLEAUT32.255]
3685  */
3686 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char *pcOut)
3687 {
3688         TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
3689
3690         if( ulIn > I1_MAX )
3691         {
3692                 return DISP_E_OVERFLOW;
3693         }
3694
3695         *pcOut = (CHAR) ulIn;
3696
3697         return S_OK;
3698 }
3699
3700 /**********************************************************************
3701  *              VarI1FromCy [OLEAUT32.250]
3702  * Convert currency to signed char
3703  */
3704 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char *pcOut) {
3705    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3706
3707    if (t > I1_MAX || t < I1_MIN) return DISP_E_OVERFLOW;
3708
3709    *pcOut = (CHAR)t;
3710    return S_OK;
3711 }
3712
3713 /******************************************************************************
3714  *              VarUI2FromUI1           [OLEAUT32.257]
3715  */
3716 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
3717 {
3718         TRACE("( %d, %p ), stub\n", bIn, puiOut );
3719
3720         *puiOut = (USHORT) bIn;
3721
3722         return S_OK;
3723 }
3724
3725 /******************************************************************************
3726  *              VarUI2FromI2            [OLEAUT32.258]
3727  */
3728 HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
3729 {
3730         TRACE("( %d, %p ), stub\n", uiIn, puiOut );
3731
3732         if( uiIn < UI2_MIN )
3733         {
3734                 return DISP_E_OVERFLOW;
3735         }
3736
3737         *puiOut = (USHORT) uiIn;
3738
3739         return S_OK;
3740 }
3741
3742 /******************************************************************************
3743  *              VarUI2FromI4            [OLEAUT32.259]
3744  */
3745 HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
3746 {
3747         TRACE("( %ld, %p ), stub\n", lIn, puiOut );
3748
3749         if( lIn < UI2_MIN || lIn > UI2_MAX )
3750         {
3751                 return DISP_E_OVERFLOW;
3752         }
3753
3754         *puiOut = (USHORT) lIn;
3755
3756         return S_OK;
3757 }
3758
3759 /******************************************************************************
3760  *              VarUI2FromR4            [OLEAUT32.260]
3761  */
3762 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
3763 {
3764         TRACE("( %f, %p ), stub\n", fltIn, puiOut );
3765
3766     fltIn = round( fltIn );
3767         if( fltIn < UI2_MIN || fltIn > UI2_MAX )
3768         {
3769                 return DISP_E_OVERFLOW;
3770         }
3771
3772         *puiOut = (USHORT) fltIn;
3773
3774         return S_OK;
3775 }
3776
3777 /******************************************************************************
3778  *              VarUI2FromR8            [OLEAUT32.261]
3779  */
3780 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
3781 {
3782         TRACE("( %f, %p ), stub\n", dblIn, puiOut );
3783
3784     dblIn = round( dblIn );
3785     if( dblIn < UI2_MIN || dblIn > UI2_MAX )
3786         {
3787                 return DISP_E_OVERFLOW;
3788         }
3789
3790         *puiOut = (USHORT) dblIn;
3791
3792         return S_OK;
3793 }
3794
3795 /******************************************************************************
3796  *              VarUI2FromDate          [OLEAUT32.262]
3797  */
3798 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
3799 {
3800         TRACE("( %f, %p ), stub\n", dateIn, puiOut );
3801
3802     dateIn = round( dateIn );
3803         if( dateIn < UI2_MIN || dateIn > UI2_MAX )
3804         {
3805                 return DISP_E_OVERFLOW;
3806         }
3807
3808         *puiOut = (USHORT) dateIn;
3809
3810         return S_OK;
3811 }
3812
3813 /******************************************************************************
3814  *              VarUI2FromStr           [OLEAUT32.264]
3815  */
3816 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
3817 {
3818   TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, puiOut);
3819   return _VarUI2FromStr(strIn, lcid, dwFlags, puiOut);
3820 }
3821
3822 /******************************************************************************
3823  *              VarUI2FromBool          [OLEAUT32.266]
3824  */
3825 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
3826 {
3827         TRACE("( %d, %p ), stub\n", boolIn, puiOut );
3828
3829         *puiOut = (USHORT) boolIn;
3830
3831         return S_OK;
3832 }
3833
3834 /******************************************************************************
3835  *              VarUI2FromI1            [OLEAUT32.267]
3836  */
3837 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* puiOut)
3838 {
3839         TRACE("( %c, %p ), stub\n", cIn, puiOut );
3840
3841         *puiOut = (USHORT) cIn;
3842
3843         return S_OK;
3844 }
3845
3846 /******************************************************************************
3847  *              VarUI2FromUI4           [OLEAUT32.268]
3848  */
3849 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
3850 {
3851         TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
3852
3853         if( ulIn > UI2_MAX )
3854         {
3855                 return DISP_E_OVERFLOW;
3856         }
3857
3858         *puiOut = (USHORT) ulIn;
3859
3860         return S_OK;
3861 }
3862
3863 /******************************************************************************
3864  *              VarUI4FromStr           [OLEAUT32.277]
3865  */
3866 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
3867 {
3868   TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pulOut);
3869   return _VarUI4FromStr(strIn, lcid, dwFlags, pulOut);
3870 }
3871
3872 /**********************************************************************
3873  *              VarUI2FromCy [OLEAUT32.263]
3874  * Convert currency to unsigned short
3875  */
3876 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
3877    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3878
3879    if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
3880
3881    *pusOut = (USHORT)t;
3882
3883    return S_OK;
3884 }
3885
3886 /******************************************************************************
3887  *              VarUI4FromUI1           [OLEAUT32.270]
3888  */
3889 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
3890 {
3891         TRACE("( %d, %p ), stub\n", bIn, pulOut );
3892
3893         *pulOut = (USHORT) bIn;
3894
3895         return S_OK;
3896 }
3897
3898 /******************************************************************************
3899  *              VarUI4FromI2            [OLEAUT32.271]
3900  */
3901 HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
3902 {
3903         TRACE("( %d, %p ), stub\n", uiIn, pulOut );
3904
3905         if( uiIn < UI4_MIN )
3906         {
3907                 return DISP_E_OVERFLOW;
3908         }
3909
3910         *pulOut = (ULONG) uiIn;
3911
3912         return S_OK;
3913 }
3914
3915 /******************************************************************************
3916  *              VarUI4FromI4            [OLEAUT32.272]
3917  */
3918 HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
3919 {
3920         TRACE("( %ld, %p ), stub\n", lIn, pulOut );
3921
3922         if( lIn < 0 )
3923         {
3924                 return DISP_E_OVERFLOW;
3925         }
3926
3927         *pulOut = (ULONG) lIn;
3928
3929         return S_OK;
3930 }
3931
3932 /******************************************************************************
3933  *              VarUI4FromR4            [OLEAUT32.273]
3934  */
3935 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
3936 {
3937     fltIn = round( fltIn );
3938     if( fltIn < UI4_MIN || fltIn > UI4_MAX )
3939         {
3940                 return DISP_E_OVERFLOW;
3941         }
3942
3943         *pulOut = (ULONG) fltIn;
3944
3945         return S_OK;
3946 }
3947
3948 /******************************************************************************
3949  *              VarUI4FromR8            [OLEAUT32.274]
3950  */
3951 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
3952 {
3953         TRACE("( %f, %p ), stub\n", dblIn, pulOut );
3954
3955         dblIn = round( dblIn );
3956         if( dblIn < UI4_MIN || dblIn > UI4_MAX )
3957         {
3958                 return DISP_E_OVERFLOW;
3959         }
3960
3961         *pulOut = (ULONG) dblIn;
3962
3963         return S_OK;
3964 }
3965
3966 /******************************************************************************
3967  *              VarUI4FromDate          [OLEAUT32.275]
3968  */
3969 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
3970 {
3971         TRACE("( %f, %p ), stub\n", dateIn, pulOut );
3972
3973         dateIn = round( dateIn );
3974         if( dateIn < UI4_MIN || dateIn > UI4_MAX )
3975         {
3976                 return DISP_E_OVERFLOW;
3977         }
3978
3979         *pulOut = (ULONG) dateIn;
3980
3981         return S_OK;
3982 }
3983
3984 /******************************************************************************
3985  *              VarUI4FromBool          [OLEAUT32.279]
3986  */
3987 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
3988 {
3989         TRACE("( %d, %p ), stub\n", boolIn, pulOut );
3990
3991         *pulOut = (ULONG) boolIn;
3992
3993         return S_OK;
3994 }
3995
3996 /******************************************************************************
3997  *              VarUI4FromI1            [OLEAUT32.280]
3998  */
3999 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG* pulOut)
4000 {
4001         TRACE("( %c, %p ), stub\n", cIn, pulOut );
4002
4003         *pulOut = (ULONG) cIn;
4004
4005         return S_OK;
4006 }
4007
4008 /******************************************************************************
4009  *              VarUI4FromUI2           [OLEAUT32.281]
4010  */
4011 HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4012 {
4013         TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4014
4015         *pulOut = (ULONG) uiIn;
4016
4017         return S_OK;
4018 }
4019
4020 /**********************************************************************
4021  *              VarUI4FromCy [OLEAUT32.276]
4022  * Convert currency to unsigned long
4023  */
4024 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
4025    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4026
4027    if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4028
4029    *pulOut = (ULONG)t;
4030
4031    return S_OK;
4032 }
4033
4034 /**********************************************************************
4035  *              VarCyFromUI1 [OLEAUT32.98]
4036  * Convert unsigned char to currency
4037  */
4038 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
4039     pcyOut->s.Hi = 0;
4040     pcyOut->s.Lo = ((ULONG)bIn) * 10000;
4041
4042     return S_OK;
4043 }
4044
4045 /**********************************************************************
4046  *              VarCyFromI2 [OLEAUT32.99]
4047  * Convert signed short to currency
4048  */
4049 HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
4050     if (sIn < 0) pcyOut->s.Hi = -1;
4051     else pcyOut->s.Hi = 0;
4052     pcyOut->s.Lo = ((ULONG)sIn) * 10000;
4053
4054     return S_OK;
4055 }
4056
4057 /**********************************************************************
4058  *              VarCyFromI4 [OLEAUT32.100]
4059  * Convert signed long to currency
4060  */
4061 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4062       double t = (double)lIn * (double)10000;
4063       pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4064       pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4065       if (lIn < 0) pcyOut->s.Hi--;
4066
4067       return S_OK;
4068 }
4069
4070 /**********************************************************************
4071  *              VarCyFromR4 [OLEAUT32.101]
4072  * Convert float to currency
4073  */
4074 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
4075    double t = round((double)fltIn * (double)10000);
4076    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4077    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4078    if (fltIn < 0) pcyOut->s.Hi--;
4079
4080    return S_OK;
4081 }
4082
4083 /**********************************************************************
4084  *              VarCyFromR8 [OLEAUT32.102]
4085  * Convert double to currency
4086  */
4087 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
4088    double t = round(dblIn * (double)10000);
4089    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4090    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4091    if (dblIn < 0) pcyOut->s.Hi--;
4092
4093    return S_OK;
4094 }
4095
4096 /**********************************************************************
4097  *              VarCyFromDate [OLEAUT32.103]
4098  * Convert date to currency
4099  */
4100 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
4101    double t = round((double)dateIn * (double)10000);
4102    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4103    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4104    if (dateIn < 0) pcyOut->s.Hi--;
4105
4106    return S_OK;
4107 }
4108
4109 /**********************************************************************
4110  *              VarCyFromStr [OLEAUT32.104]
4111  * FIXME: Never tested with decimal separator other than '.'
4112  */
4113 HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut)
4114 {
4115   TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pcyOut);
4116   return _VarCyFromStr(strIn, lcid, dwFlags, pcyOut);
4117 }
4118
4119
4120 /**********************************************************************
4121  *              VarCyFromBool [OLEAUT32.106]
4122  * Convert boolean to currency
4123  */
4124 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
4125    if (boolIn < 0) pcyOut->s.Hi = -1;
4126    else pcyOut->s.Hi = 0;
4127    pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
4128
4129    return S_OK;
4130 }
4131
4132 /**********************************************************************
4133  *              VarCyFromI1 [OLEAUT32.225]
4134  * Convert signed char to currency
4135  */
4136 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
4137    if (cIn < 0) pcyOut->s.Hi = -1;
4138    else pcyOut->s.Hi = 0;
4139    pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
4140
4141    return S_OK;
4142 }
4143
4144 /**********************************************************************
4145  *              VarCyFromUI2 [OLEAUT32.226]
4146  * Convert unsigned short to currency
4147  */
4148 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
4149    pcyOut->s.Hi = 0;
4150    pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
4151
4152    return S_OK;
4153 }
4154
4155 /**********************************************************************
4156  *              VarCyFromUI4 [OLEAUT32.227]
4157  * Convert unsigned long to currency
4158  */
4159 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4160    double t = (double)ulIn * (double)10000;
4161    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4162    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4163
4164    return S_OK;
4165 }
4166
4167 /**********************************************************************
4168  *              VarDecFromStr [OLEAUT32.@]
4169  */
4170 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags,
4171                              DECIMAL* pdecOut)
4172 {   WCHAR *p=strIn;
4173     ULONGLONG t;
4174     ULONG  cy;
4175
4176     DECIMAL_SETZERO(pdecOut);
4177
4178     if(*p == (WCHAR)'-')pdecOut->u.s.sign= DECIMAL_NEG;
4179     if((*p == (WCHAR)'-') || (*p == (WCHAR)'+')) p++;
4180     for(;*p != (WCHAR)0; p++) {
4181         if((*p < (WCHAR)'0')||(*p > (WCHAR)'9')) goto error ;
4182         t = (ULONGLONG)pdecOut->u1.s1.Lo32 *(ULONGLONG)10
4183           + (ULONGLONG)(*p -(WCHAR)'0');
4184         cy = (ULONG)(t >> 32);
4185         pdecOut->u1.s1.Lo32 = (ULONG)(t & (ULONGLONG)UI4_MAX);
4186         t = (ULONGLONG)pdecOut->u1.s1.Mid32 * (ULONGLONG)10
4187           + (ULONGLONG)cy;
4188         cy = (ULONG)(t >> 32);
4189         pdecOut->u1.s1.Mid32 = (ULONG)(t & (ULONGLONG)UI4_MAX);
4190         t = (ULONGLONG)pdecOut->Hi32 * (ULONGLONG)10
4191           + (ULONGLONG)cy;
4192         cy = (ULONG)(t >> 32);
4193         pdecOut->Hi32 = (ULONG)(t & (ULONGLONG)UI4_MAX);
4194         if(cy) goto overflow ;
4195     }
4196     TRACE("%s -> sign %02x,hi %08lx,mid %08lx, lo%08lx, scale %08x\n",
4197           debugstr_w(strIn),
4198           pdecOut->u.s.sign, pdecOut->Hi32, pdecOut->u1.s1.Mid32,
4199           pdecOut->u1.s1.Lo32, pdecOut->u.s.scale);
4200     return S_OK;
4201
4202 overflow:
4203     /* like NT4 SP5 */
4204     pdecOut->Hi32 = pdecOut->u1.s1.Mid32 = pdecOut->u1.s1.Lo32 = 0xffffffff;
4205     return DISP_E_OVERFLOW;
4206
4207 error:
4208     ERR("%s: unknown char at pos %d\n",
4209               debugstr_w(strIn),  p - strIn + 1);
4210     return DISP_E_TYPEMISMATCH;
4211 }
4212
4213 /* Date Conversions */
4214
4215 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
4216
4217 /* Convert a VT_DATE value to a Julian Date */
4218 static inline int VARIANT_JulianFromDate(int dateIn)
4219 {
4220   int julianDays = dateIn;
4221
4222   julianDays -= DATE_MIN; /* Convert to + days from 1 Jan 100 AD */
4223   julianDays += 1757585;  /* Convert to + days from 23 Nov 4713 BC (Julian) */
4224   return julianDays;
4225 }
4226
4227 /* Convert a Julian Date to a VT_DATE value */
4228 static inline int VARIANT_DateFromJulian(int dateIn)
4229 {
4230   int julianDays = dateIn;
4231
4232   julianDays -= 1757585;  /* Convert to + days from 1 Jan 100 AD */
4233   julianDays += DATE_MIN; /* Convert to +/- days from 1 Jan 1899 AD */
4234   return julianDays;
4235 }
4236
4237 /* Convert a Julian date to Day/Month/Year - from PostgreSQL */
4238 static inline void VARIANT_DMYFromJulian(int jd, USHORT *year, USHORT *month, USHORT *day)
4239 {
4240   int j, i, l, n;
4241
4242   l = jd + 68569;
4243   n = l * 4 / 146097;
4244   l -= (n * 146097 + 3) / 4;
4245   i = (4000 * (l + 1)) / 1461001;
4246   l += 31 - (i * 1461) / 4;
4247   j = (l * 80) / 2447;
4248   *day = l - (j * 2447) / 80;
4249   l = j / 11;
4250   *month = (j + 2) - (12 * l);
4251   *year = 100 * (n - 49) + i + l;
4252 }
4253
4254 /* Convert Day/Month/Year to a Julian date - from PostgreSQL */
4255 static inline double VARIANT_JulianFromDMY(USHORT year, USHORT month, USHORT day)
4256 {
4257   int m12 = (month - 14) / 12;
4258
4259   return ((1461 * (year + 4800 + m12)) / 4 + (367 * (month - 2 - 12 * m12)) / 12 -
4260            (3 * ((year + 4900 + m12) / 100)) / 4 + day - 32075);
4261 }
4262
4263 /* Macros for accessing DOS format date/time fields */
4264 #define DOS_YEAR(x)   (1980 + (x >> 9))
4265 #define DOS_MONTH(x)  ((x >> 5) & 0xf)
4266 #define DOS_DAY(x)    (x & 0x1f)
4267 #define DOS_HOUR(x)   (x >> 11)
4268 #define DOS_MINUTE(x) ((x >> 5) & 0x3f)
4269 #define DOS_SECOND(x) ((x & 0x1f) << 1)
4270 /* Create a DOS format date/time */
4271 #define DOS_DATE(d,m,y) (d | (m << 5) | ((y-1980) << 9))
4272 #define DOS_TIME(h,m,s) ((s >> 1) | (m << 5) | (h << 11))
4273
4274 /* Roll a date forwards or backwards to correct it */
4275 static HRESULT VARIANT_RollUdate(UDATE *lpUd)
4276 {
4277   static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
4278
4279   TRACE("Raw date: %d/%d/%d %d:%d:%d\n", lpUd->st.wDay, lpUd->st.wMonth,
4280         lpUd->st.wYear, lpUd->st.wHour, lpUd->st.wMinute, lpUd->st.wSecond);
4281
4282   /* Years < 100 are treated as 1900 + year */
4283   if (lpUd->st.wYear < 100)
4284     lpUd->st.wYear += 1900;
4285
4286   if (!lpUd->st.wMonth)
4287   {
4288     /* Roll back to December of the previous year */
4289     lpUd->st.wMonth = 12;
4290     lpUd->st.wYear--;
4291   }
4292   else while (lpUd->st.wMonth > 12)
4293   {
4294     /* Roll forward the correct number of months */
4295     lpUd->st.wYear++;
4296     lpUd->st.wMonth -= 12;
4297   }
4298
4299   if (lpUd->st.wYear > 9999 || lpUd->st.wHour > 23 ||
4300       lpUd->st.wMinute > 59 || lpUd->st.wSecond > 59)
4301     return E_INVALIDARG; /* Invalid values */
4302
4303   if (!lpUd->st.wDay)
4304   {
4305     /* Roll back the date one day */
4306     if (lpUd->st.wMonth == 1)
4307     {
4308       /* Roll back to December 31 of the previous year */
4309       lpUd->st.wDay   = 31;
4310       lpUd->st.wMonth = 12;
4311       lpUd->st.wYear--;
4312     }
4313     else
4314     {
4315       lpUd->st.wMonth--; /* Previous month */
4316       if (lpUd->st.wMonth == 2 && IsLeapYear(lpUd->st.wYear))
4317         lpUd->st.wDay = 29; /* Februaury has 29 days on leap years */
4318       else
4319         lpUd->st.wDay = days[lpUd->st.wMonth]; /* Last day of the month */
4320     }
4321   }
4322   else if (lpUd->st.wDay > 28)
4323   {
4324     int rollForward = 0;
4325
4326     /* Possibly need to roll the date forward */
4327     if (lpUd->st.wMonth == 2 && IsLeapYear(lpUd->st.wYear))
4328       rollForward = lpUd->st.wDay - 29; /* Februaury has 29 days on leap years */
4329     else
4330       rollForward = lpUd->st.wDay - days[lpUd->st.wMonth];
4331
4332     if (rollForward > 0)
4333     {
4334       lpUd->st.wDay = rollForward;
4335       lpUd->st.wMonth++;
4336       if (lpUd->st.wMonth > 12)
4337       {
4338         lpUd->st.wMonth = 1; /* Roll forward into January of the next year */
4339         lpUd->st.wYear++;
4340       }
4341     }
4342   }
4343   TRACE("Rolled date: %d/%d/%d %d:%d:%d\n", lpUd->st.wDay, lpUd->st.wMonth,
4344         lpUd->st.wYear, lpUd->st.wHour, lpUd->st.wMinute, lpUd->st.wSecond);
4345   return S_OK;
4346 }
4347
4348 /**********************************************************************
4349  *              DosDateTimeToVariantTime [OLEAUT32.14]
4350  *
4351  * Convert a Dos format date and time into variant VT_DATE format.
4352  *
4353  * PARAMS
4354  *  wDosDate [I] Dos format date
4355  *  wDosTime [I] Dos format time
4356  *  pDateOut [O] Destination for VT_DATE format
4357  *
4358  * RETURNS
4359  *  Success: TRUE. pDateOut contains the converted time.
4360  *  Failure: FALSE, if wDosDate or wDosTime are invalid (see notes).
4361  *
4362  * NOTES
4363  * - Dos format dates can only hold dates from 1-Jan-1980 to 31-Dec-2099.
4364  * - Dos format times are accurate to only 2 second precision.
4365  * - The format of a Dos Date is:
4366  *| Bits   Values  Meaning
4367  *| ----   ------  -------
4368  *| 0-4    1-31    Day of the week. 0 rolls back one day. A value greater than
4369  *|                the days in the month rolls forward the extra days.
4370  *| 5-8    1-12    Month of the year. 0 rolls back to December of the previous
4371  *|                year. 13-15 are invalid.
4372  *| 9-15   0-119   Year based from 1980 (Max 2099). 120-127 are invalid.
4373  * - The format of a Dos Time is:
4374  *| Bits   Values  Meaning
4375  *| ----   ------  -------
4376  *| 0-4    0-29    Seconds/2. 30 and 31 are invalid.
4377  *| 5-10   0-59    Minutes. 60-63 are invalid.
4378  *| 11-15  0-23    Hours (24 hour clock). 24-32 are invalid.
4379  */
4380 INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4381                                     double *pDateOut)
4382 {
4383   UDATE ud;
4384
4385   TRACE("(0x%x(%d/%d/%d),0x%x(%d:%d:%d),%p)\n",
4386         wDosDate, DOS_YEAR(wDosDate), DOS_MONTH(wDosDate), DOS_DAY(wDosDate),
4387         wDosTime, DOS_HOUR(wDosTime), DOS_MINUTE(wDosTime), DOS_SECOND(wDosTime),
4388         pDateOut);
4389
4390   ud.st.wYear = DOS_YEAR(wDosDate);
4391   ud.st.wMonth = DOS_MONTH(wDosDate);
4392   if (ud.st.wYear > 2099 || ud.st.wMonth > 12)
4393     return FALSE;
4394   ud.st.wDay = DOS_DAY(wDosDate);
4395   ud.st.wHour = DOS_HOUR(wDosTime);
4396   ud.st.wMinute = DOS_MINUTE(wDosTime);
4397   ud.st.wSecond = DOS_SECOND(wDosTime);
4398   ud.st.wDayOfWeek = ud.st.wMilliseconds = 0;
4399
4400   return !VarDateFromUdate(&ud, 0, pDateOut);
4401 }
4402
4403 /**********************************************************************
4404  *              VariantTimeToDosDateTime [OLEAUT32.13]
4405  *
4406  * Convert a variant format date into a Dos format date and time.
4407  *
4408  *  dateIn    [I] VT_DATE time format
4409  *  pwDosDate [O] Destination for Dos format date
4410  *  pwDosTime [O] Destination for Dos format time
4411  *
4412  * RETURNS
4413  *  Success: TRUE. pwDosDate and pwDosTime contains the converted values.
4414  *  Failure: FALSE, if dateIn cannot be represented in Dos format.
4415  *
4416  * NOTES
4417  *   See DosDateTimeToVariantTime() for Dos format details and bugs.
4418  */
4419 INT WINAPI VariantTimeToDosDateTime(double dateIn, USHORT *pwDosDate, USHORT *pwDosTime)
4420 {
4421   UDATE ud;
4422
4423   TRACE("(%g,%p,%p)\n", dateIn, pwDosDate, pwDosTime);
4424
4425   if (FAILED(VarUdateFromDate(dateIn, 0, &ud)))
4426     return FALSE;
4427
4428   if (ud.st.wYear < 1980 || ud.st.wYear > 2099)
4429     return FALSE;
4430
4431   *pwDosDate = DOS_DATE(ud.st.wDay, ud.st.wMonth, ud.st.wYear);
4432   *pwDosTime = DOS_TIME(ud.st.wHour, ud.st.wMinute, ud.st.wSecond);
4433
4434   TRACE("Returning 0x%x(%d/%d/%d), 0x%x(%d:%d:%d)\n",
4435         *pwDosDate, DOS_YEAR(*pwDosDate), DOS_MONTH(*pwDosDate), DOS_DAY(*pwDosDate),
4436         *pwDosTime, DOS_HOUR(*pwDosTime), DOS_MINUTE(*pwDosTime), DOS_SECOND(*pwDosTime));
4437   return TRUE;
4438 }
4439
4440 /***********************************************************************
4441  *              SystemTimeToVariantTime [OLEAUT32.184]
4442  *
4443  * Convert a System format date and time into variant VT_DATE format.
4444  *
4445  * PARAMS
4446  *  lpSt     [I] System format date and time
4447  *  pDateOut [O] Destination for VT_DATE format date
4448  *
4449  * RETURNS
4450  *  Success: TRUE. *pDateOut contains the converted value.
4451  *  Failure: FALSE, if lpSt cannot be represented in VT_DATE format.
4452  */
4453 INT WINAPI SystemTimeToVariantTime(LPSYSTEMTIME lpSt, double *pDateOut)
4454 {
4455   UDATE ud;
4456
4457   TRACE("(%p->%d/%d/%d %d:%d:%d,%p)\n", lpSt, lpSt->wDay, lpSt->wMonth,
4458         lpSt->wYear, lpSt->wHour, lpSt->wMinute, lpSt->wSecond, pDateOut);
4459
4460   if (lpSt->wMonth > 12)
4461     return FALSE;
4462
4463   memcpy(&ud.st, lpSt, sizeof(ud.st));
4464   return !VarDateFromUdate(&ud, 0, pDateOut);
4465 }
4466
4467 /***********************************************************************
4468  *              VariantTimeToSystemTime [OLEAUT32.185]
4469  *
4470  * Convert a variant VT_DATE into a System format date and time.
4471  *
4472  * PARAMS
4473  *  datein [I] Variant VT_DATE format date
4474  *  lpSt   [O] Destination for System format date and time
4475  *
4476  * RETURNS
4477  *  Success: TRUE. *lpSt contains the converted value.
4478  *  Failure: FALSE, if dateIn is too large or small.
4479  */
4480 INT WINAPI VariantTimeToSystemTime(double dateIn, LPSYSTEMTIME lpSt)
4481 {
4482   UDATE ud;
4483
4484   TRACE("(%g,%p)\n", dateIn, lpSt);
4485
4486   if (FAILED(VarUdateFromDate(dateIn, 0, &ud)))
4487     return FALSE;
4488
4489   memcpy(lpSt, &ud.st, sizeof(ud.st));
4490   return TRUE;
4491 }
4492
4493 /***********************************************************************
4494  *              VarDateFromUdate [OLEAUT32.330]
4495  *
4496  * Convert an unpacked format date and time to a variant VT_DATE.
4497  *
4498  * PARAMS
4499  *  pUdateIn [I] Unpacked format date and time to convert
4500  *  dwFlags  [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4501  *  pDateOut [O] Destination for variant VT_DATE.
4502  *
4503  * RETURNS
4504  *  Success: S_OK. *pDateOut contains the converted value.
4505  *  Failure: E_INVALIDARG, if pUdateIn cannot be represented in VT_DATE format.
4506  */
4507 HRESULT WINAPI VarDateFromUdate(UDATE *pUdateIn, ULONG dwFlags, DATE *pDateOut)
4508 {
4509   UDATE ud;
4510   double dateVal;
4511
4512   TRACE("(%p->%d/%d/%d %d:%d:%d:%d %d %d,0x%08lx,%p)\n", pUdateIn,
4513         pUdateIn->st.wMonth, pUdateIn->st.wDay, pUdateIn->st.wYear,
4514         pUdateIn->st.wHour, pUdateIn->st.wMinute, pUdateIn->st.wSecond,
4515         pUdateIn->st.wMilliseconds, pUdateIn->st.wDayOfWeek,
4516         pUdateIn->wDayOfYear, dwFlags, pDateOut);
4517
4518   memcpy(&ud, pUdateIn, sizeof(ud));
4519
4520   if (dwFlags & VAR_VALIDDATE)
4521     WARN("Ignoring VAR_VALIDDATE\n");
4522
4523   if (FAILED(VARIANT_RollUdate(&ud)))
4524     return E_INVALIDARG;
4525
4526   /* Date */
4527   dateVal = VARIANT_DateFromJulian(VARIANT_JulianFromDMY(ud.st.wYear, ud.st.wMonth, ud.st.wDay));
4528
4529   /* Time */
4530   dateVal += ud.st.wHour / 24.0;
4531   dateVal += ud.st.wMinute / 1440.0;
4532   dateVal += ud.st.wSecond / 86400.0;
4533   dateVal += ud.st.wMilliseconds / 86400000.0;
4534
4535   TRACE("Returning %g\n", dateVal);
4536   *pDateOut = dateVal;
4537   return S_OK;
4538 }
4539
4540 /***********************************************************************
4541  *              VarUdateFromDate [OLEAUT32.331]
4542  *
4543  * Convert a variant VT_DATE into an unpacked format date and time.
4544  *
4545  * PARAMS
4546  *  datein    [I] Variant VT_DATE format date
4547  *  dwFlags   [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4548  *  lpUdate [O] Destination for unpacked format date and time
4549  *
4550  * RETURNS
4551  *  Success: S_OK. *lpUdate contains the converted value.
4552  *  Failure: E_INVALIDARG, if dateIn is too large or small.
4553  */
4554 HRESULT WINAPI VarUdateFromDate(DATE dateIn, ULONG dwFlags, UDATE *lpUdate)
4555 {
4556   /* Cumulative totals of days per month */
4557   static const USHORT cumulativeDays[] =
4558   {
4559     0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
4560   };
4561   double datePart, timePart;
4562   int julianDays;
4563
4564   TRACE("(%g,0x%08lx,%p)\n", dateIn, dwFlags, lpUdate);
4565
4566   if (dateIn <= (DATE_MIN - 1.0) || dateIn >= (DATE_MAX + 1.0))
4567     return E_INVALIDARG;
4568
4569   datePart = dateIn < 0.0 ? ceil(dateIn) : floor(dateIn);
4570   /* Compensate for int truncation (always downwards) */
4571   timePart = dateIn - datePart + 0.00000000001;
4572   if (timePart >= 1.0)
4573     timePart -= 0.00000000001;
4574
4575   /* Date */
4576   julianDays = VARIANT_JulianFromDate(dateIn);
4577   VARIANT_DMYFromJulian(julianDays, &lpUdate->st.wYear, &lpUdate->st.wMonth,
4578                         &lpUdate->st.wDay);
4579
4580   datePart = (datePart + 1.5) / 7.0;
4581   lpUdate->st.wDayOfWeek = (datePart - floor(datePart)) * 7;
4582   if (lpUdate->st.wDayOfWeek == 0)
4583     lpUdate->st.wDayOfWeek = 5;
4584   else if (lpUdate->st.wDayOfWeek == 1)
4585     lpUdate->st.wDayOfWeek = 6;
4586   else
4587     lpUdate->st.wDayOfWeek -= 2;
4588
4589   if (lpUdate->st.wMonth > 2 && IsLeapYear(lpUdate->st.wYear))
4590     lpUdate->wDayOfYear = 1; /* After February, in a leap year */
4591   else
4592     lpUdate->wDayOfYear = 0;
4593
4594   lpUdate->wDayOfYear += cumulativeDays[lpUdate->st.wMonth];
4595   lpUdate->wDayOfYear += lpUdate->st.wDay;
4596
4597   /* Time */
4598   timePart *= 24.0;
4599   lpUdate->st.wHour = timePart;
4600   timePart -= lpUdate->st.wHour;
4601   timePart *= 60.0;
4602   lpUdate->st.wMinute = timePart;
4603   timePart -= lpUdate->st.wMinute;
4604   timePart *= 60.0;
4605   lpUdate->st.wSecond = timePart;
4606   timePart -= lpUdate->st.wSecond;
4607   lpUdate->st.wMilliseconds = 0;
4608   if (timePart > 0.0005)
4609   {
4610     /* Round the milliseconds, adjusting the time/date forward if needed */
4611     if (lpUdate->st.wSecond < 59)
4612       lpUdate->st.wSecond++;
4613     else
4614     {
4615       lpUdate->st.wSecond = 0;
4616       if (lpUdate->st.wMinute < 59)
4617         lpUdate->st.wMinute++;
4618       else
4619       {
4620         lpUdate->st.wMinute = 0;
4621         if (lpUdate->st.wHour < 23)
4622           lpUdate->st.wHour++;
4623         else
4624         {
4625           lpUdate->st.wHour = 0;
4626           /* Roll over a whole day */
4627           if (++lpUdate->st.wDay > 28)
4628             VARIANT_RollUdate(lpUdate);
4629         }
4630       }
4631     }
4632   }
4633   return S_OK;
4634 }
4635
4636 #define GET_NUMBER_TEXT(fld,name) \
4637   buff[0] = 0; \
4638   if (!GetLocaleInfoW(lcid, lctype|fld, buff, sizeof(WCHAR) * 2)) \
4639     WARN("buffer too small for " #fld "\n"); \
4640   else \
4641     if (buff[0]) lpChars->name = buff[0]; \
4642   TRACE("lcid 0x%lx, " #name "=%d '%c'\n", lcid, lpChars->name, lpChars->name)
4643
4644 /* Get the valid number characters for an lcid */
4645 void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS *lpChars, LCID lcid, DWORD dwFlags)
4646 {
4647   static const VARIANT_NUMBER_CHARS defaultChars = { '-','+','.',',','$',0,'.',',' };
4648   LCTYPE lctype = 0;
4649   WCHAR buff[4];
4650
4651   if (dwFlags & VARIANT_NOUSEROVERRIDE)
4652     lctype |= LOCALE_NOUSEROVERRIDE;
4653
4654   memcpy(lpChars, &defaultChars, sizeof(defaultChars));
4655   GET_NUMBER_TEXT(LOCALE_SNEGATIVESIGN, cNegativeSymbol);
4656   GET_NUMBER_TEXT(LOCALE_SPOSITIVESIGN, cPositiveSymbol);
4657   GET_NUMBER_TEXT(LOCALE_SDECIMAL, cDecimalPoint);
4658   GET_NUMBER_TEXT(LOCALE_STHOUSAND, cDigitSeperator);
4659   GET_NUMBER_TEXT(LOCALE_SMONDECIMALSEP, cCurrencyDecimalPoint);
4660   GET_NUMBER_TEXT(LOCALE_SMONTHOUSANDSEP, cCurrencyDigitSeperator);
4661
4662   /* Local currency symbols are often 2 characters */
4663   lpChars->cCurrencyLocal2 = '\0';
4664   switch(GetLocaleInfoW(lcid, lctype|LOCALE_SCURRENCY, buff, sizeof(WCHAR) * 4))
4665   {
4666     case 3: lpChars->cCurrencyLocal2 = buff[1]; /* Fall through */
4667     case 2: lpChars->cCurrencyLocal  = buff[0];
4668             break;
4669     default: WARN("buffer too small for LOCALE_SCURRENCY\n");
4670   }
4671   TRACE("lcid 0x%lx, cCurrencyLocal =%d,%d '%c','%c'\n", lcid, lpChars->cCurrencyLocal,
4672         lpChars->cCurrencyLocal2, lpChars->cCurrencyLocal, lpChars->cCurrencyLocal2);
4673 }
4674
4675 /* Number Parsing States */
4676 #define B_PROCESSING_EXPONENT 0x1
4677 #define B_NEGATIVE_EXPONENT   0x2
4678 #define B_EXPONENT_START      0x4
4679 #define B_INEXACT_ZEROS       0x8
4680 #define B_LEADING_ZERO        0x10
4681
4682 /**********************************************************************
4683  *              VarParseNumFromStr [OLEAUT32.46]
4684  *
4685  * Parse a string containing a number into a NUMPARSE structure.
4686  *
4687  * PARAMS
4688  *  lpszStr [I]   String to parse number from
4689  *  lcid    [I]   Locale Id for the conversion
4690  *  dwFlags [I]   Apparently not used
4691  *  pNumprs [I/O] Destination for parsed number
4692  *  rgbDig  [O]   Destination for digits read in
4693  *
4694  * RETURNS
4695  *  Success: S_OK. pNumprs and rgbDig contain the parsed representation of
4696  *           the number.
4697  *  Failure: E_INVALIDARG, if any parameter is invalid.
4698  *           DISP_E_TYPEMISMATCH, if the string is not a number or is formatted
4699  *           incorrectly.
4700  *           DISP_E_OVERFLOW, if rgbDig is too small to hold the number.
4701  *
4702  * NOTES
4703  *  pNumprs must have the following fields set:
4704  *   cDig: Set to the size of rgbDig.
4705  *   dwInFlags: Set to the allowable syntax of the number using NUMPRS_ flags
4706  *            from "oleauto.h".
4707  *
4708  * FIXME
4709  *  - I am unsure if this function should parse non-arabic (e.g. Thai)
4710  *   numerals, so this has not been implemented.
4711  */
4712 HRESULT WINAPI VarParseNumFromStr(OLECHAR *lpszStr, LCID lcid, ULONG dwFlags,
4713                                   NUMPARSE *pNumprs, BYTE *rgbDig)
4714 {
4715   VARIANT_NUMBER_CHARS chars;
4716   BYTE rgbTmp[1024];
4717   DWORD dwState = B_EXPONENT_START|B_INEXACT_ZEROS;
4718   int iMaxDigits = sizeof(rgbTmp) / sizeof(BYTE);
4719   int cchUsed = 0;
4720
4721   TRACE("(%s,%ld,%ld,%p,%p)\n", debugstr_w(lpszStr), lcid, dwFlags, pNumprs, rgbDig);
4722
4723   if (pNumprs->dwInFlags & NUMPRS_HEX_OCT)
4724     FIXME("dwInFlags & NUMPRS_HEX_OCT not yet implemented!\n");
4725
4726   if (!pNumprs || !rgbDig)
4727     return E_INVALIDARG;
4728
4729   if (pNumprs->cDig < iMaxDigits)
4730     iMaxDigits = pNumprs->cDig;
4731
4732   pNumprs->cDig = 0;
4733   pNumprs->dwOutFlags = 0;
4734   pNumprs->cchUsed = 0;
4735   pNumprs->nBaseShift = 0;
4736   pNumprs->nPwr10 = 0;
4737
4738   if (!lpszStr)
4739     return DISP_E_TYPEMISMATCH;
4740
4741   VARIANT_GetLocalisedNumberChars(&chars, lcid, dwFlags);
4742
4743   /* First consume all the leading symbols and space from the string */
4744   while (1)
4745   {
4746     if (pNumprs->dwInFlags & NUMPRS_LEADING_WHITE && isspaceW(*lpszStr))
4747     {
4748       pNumprs->dwOutFlags |= NUMPRS_LEADING_WHITE;
4749       do
4750       {
4751         cchUsed++;
4752         lpszStr++;
4753       } while (isspaceW(*lpszStr));
4754     }
4755     else if (pNumprs->dwInFlags & NUMPRS_LEADING_PLUS &&
4756              *lpszStr == chars.cPositiveSymbol &&
4757              !(pNumprs->dwOutFlags & NUMPRS_LEADING_PLUS))
4758     {
4759       pNumprs->dwOutFlags |= NUMPRS_LEADING_PLUS;
4760       cchUsed++;
4761       lpszStr++;
4762     }
4763     else if (pNumprs->dwInFlags & NUMPRS_LEADING_MINUS &&
4764              *lpszStr == chars.cNegativeSymbol &&
4765              !(pNumprs->dwOutFlags & NUMPRS_LEADING_MINUS))
4766     {
4767       pNumprs->dwOutFlags |= (NUMPRS_LEADING_MINUS|NUMPRS_NEG);
4768       cchUsed++;
4769       lpszStr++;
4770     }
4771     else if (pNumprs->dwInFlags & NUMPRS_CURRENCY &&
4772              !(pNumprs->dwOutFlags & NUMPRS_CURRENCY) &&
4773              *lpszStr == chars.cCurrencyLocal &&
4774              (!chars.cCurrencyLocal2 || lpszStr[1] == chars.cCurrencyLocal2))
4775     {
4776       pNumprs->dwOutFlags |= NUMPRS_CURRENCY;
4777       cchUsed++;
4778       lpszStr++;
4779       /* Only accept currency characters */
4780       chars.cDecimalPoint = chars.cCurrencyDecimalPoint;
4781       chars.cDigitSeperator = chars.cCurrencyDigitSeperator;
4782     }
4783     else if (pNumprs->dwInFlags & NUMPRS_PARENS && *lpszStr == '(' &&
4784              !(pNumprs->dwOutFlags & NUMPRS_PARENS))
4785     {
4786       pNumprs->dwOutFlags |= NUMPRS_PARENS;
4787       cchUsed++;
4788       lpszStr++;
4789     }
4790     else
4791       break;
4792   }
4793
4794   if (!(pNumprs->dwOutFlags & NUMPRS_CURRENCY))
4795   {
4796     /* Only accept non-currency characters */
4797     chars.cCurrencyDecimalPoint = chars.cDecimalPoint;
4798     chars.cCurrencyDigitSeperator = chars.cDigitSeperator;
4799   }
4800
4801   /* Strip Leading zeros */
4802   while (*lpszStr == '0')
4803   {
4804     dwState |= B_LEADING_ZERO;
4805     cchUsed++;
4806     lpszStr++;
4807   }
4808
4809   while (*lpszStr)
4810   {
4811     if (isdigitW(*lpszStr))
4812     {
4813       if (dwState & B_PROCESSING_EXPONENT)
4814       {
4815         int exponentSize = 0;
4816         if (dwState & B_EXPONENT_START)
4817         {
4818           while (*lpszStr == '0')
4819           {
4820             /* Skip leading zero's in the exponent */
4821             cchUsed++;
4822             lpszStr++;
4823           }
4824           if (!isdigitW(*lpszStr))
4825             break; /* No exponent digits - invalid */
4826         }
4827
4828         while (isdigitW(*lpszStr))
4829         {
4830           exponentSize *= 10;
4831           exponentSize += *lpszStr - '0';
4832           cchUsed++;
4833           lpszStr++;
4834         }
4835         if (dwState & B_NEGATIVE_EXPONENT)
4836           exponentSize = -exponentSize;
4837         /* Add the exponent into the powers of 10 */
4838         pNumprs->nPwr10 += exponentSize;
4839         dwState &= ~(B_PROCESSING_EXPONENT|B_EXPONENT_START);
4840         lpszStr--; /* back up to allow processing of next char */
4841       }
4842       else
4843       {
4844         if (pNumprs->cDig >= iMaxDigits)
4845         {
4846           pNumprs->dwOutFlags |= NUMPRS_INEXACT;
4847
4848           if (*lpszStr != '0')
4849             dwState &= ~B_INEXACT_ZEROS; /* Inexact number with non-trailing zeros */
4850
4851           /* This digit can't be represented, but count it in nPwr10 */
4852           if (pNumprs->dwOutFlags & NUMPRS_DECIMAL)
4853             pNumprs->nPwr10--;
4854           else
4855             pNumprs->nPwr10++;
4856         }
4857         else
4858         {
4859           if (pNumprs->dwOutFlags & NUMPRS_DECIMAL)
4860             pNumprs->nPwr10--; /* Count decimal points in nPwr10 */
4861           rgbTmp[pNumprs->cDig] = *lpszStr - '0';
4862         }
4863         pNumprs->cDig++;
4864         cchUsed++;
4865       }
4866     }
4867     else if (*lpszStr == chars.cDigitSeperator && pNumprs->dwInFlags & NUMPRS_THOUSANDS)
4868     {
4869       pNumprs->dwOutFlags |= NUMPRS_THOUSANDS;
4870       cchUsed++;
4871     }
4872     else if (*lpszStr == chars.cDecimalPoint &&
4873              pNumprs->dwInFlags & NUMPRS_DECIMAL &&
4874              !(pNumprs->dwOutFlags & (NUMPRS_DECIMAL|NUMPRS_EXPONENT)))
4875     {
4876       pNumprs->dwOutFlags |= NUMPRS_DECIMAL;
4877       cchUsed++;
4878
4879       /* Remove trailing zeros from the whole number part */
4880       while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1])
4881       {
4882         pNumprs->nPwr10++;
4883         pNumprs->cDig--;
4884       }
4885
4886       /* If we have no digits so far, skip leading zeros */
4887       if (!pNumprs->cDig)
4888       {
4889         while (lpszStr[1] == '0')
4890         {
4891           dwState |= B_LEADING_ZERO;
4892           cchUsed++;
4893           lpszStr++;
4894         }
4895       }
4896     }
4897     else if ((*lpszStr == 'e' || *lpszStr == 'E') &&
4898              pNumprs->dwInFlags & NUMPRS_EXPONENT &&
4899              !(pNumprs->dwOutFlags & NUMPRS_EXPONENT))
4900     {
4901       dwState |= B_PROCESSING_EXPONENT;
4902       pNumprs->dwOutFlags |= NUMPRS_EXPONENT;
4903       cchUsed++;
4904     }
4905     else if (dwState & B_PROCESSING_EXPONENT && *lpszStr == chars.cPositiveSymbol)
4906     {
4907       cchUsed++; /* Ignore positive exponent */
4908     }
4909     else if (dwState & B_PROCESSING_EXPONENT && *lpszStr == chars.cNegativeSymbol)
4910     {
4911       dwState |= B_NEGATIVE_EXPONENT;
4912       cchUsed++;
4913     }
4914     else
4915       break; /* Stop at an unrecognised character */
4916
4917     lpszStr++;
4918   }
4919
4920   if (!pNumprs->cDig && dwState & B_LEADING_ZERO)
4921   {
4922     /* Ensure a 0 on its own gets stored */
4923     pNumprs->cDig = 1;
4924     rgbTmp[0] = 0;
4925   }
4926
4927   if (pNumprs->dwOutFlags & NUMPRS_EXPONENT && dwState & B_PROCESSING_EXPONENT)
4928   {
4929     pNumprs->cchUsed = cchUsed;
4930     return DISP_E_TYPEMISMATCH; /* Failed to completely parse the exponent */
4931   }
4932
4933   if (pNumprs->dwOutFlags & NUMPRS_INEXACT)
4934   {
4935     if (dwState & B_INEXACT_ZEROS)
4936       pNumprs->dwOutFlags &= ~NUMPRS_INEXACT; /* All zeros doesn't set NUMPRS_INEXACT */
4937   }
4938   else
4939   {
4940     /* Remove trailing zeros from the last (whole number or decimal) part */
4941     while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1])
4942     {
4943       if (pNumprs->dwOutFlags & NUMPRS_DECIMAL)
4944         pNumprs->nPwr10--;
4945       else
4946         pNumprs->nPwr10++;
4947       pNumprs->cDig--;
4948     }
4949   }
4950
4951   if (pNumprs->cDig <= iMaxDigits)
4952     pNumprs->dwOutFlags &= ~NUMPRS_INEXACT; /* Ignore stripped zeros for NUMPRS_INEXACT */
4953   else
4954     pNumprs->cDig = iMaxDigits; /* Only return iMaxDigits worth of digits */
4955
4956   /* Copy the digits we processed into rgbDig */
4957   memcpy(rgbDig, rgbTmp, pNumprs->cDig * sizeof(BYTE));
4958
4959   /* Consume any trailing symbols and space */
4960   while (1)
4961   {
4962     if ((pNumprs->dwInFlags & NUMPRS_TRAILING_WHITE) && isspaceW(*lpszStr))
4963     {
4964       pNumprs->dwOutFlags |= NUMPRS_TRAILING_WHITE;
4965       do
4966       {
4967         cchUsed++;
4968         lpszStr++;
4969       } while (isspaceW(*lpszStr));
4970     }
4971     else if (pNumprs->dwInFlags & NUMPRS_TRAILING_PLUS &&
4972              !(pNumprs->dwOutFlags & NUMPRS_LEADING_PLUS) &&
4973              *lpszStr == chars.cPositiveSymbol)
4974     {
4975       pNumprs->dwOutFlags |= NUMPRS_TRAILING_PLUS;
4976       cchUsed++;
4977       lpszStr++;
4978     }
4979     else if (pNumprs->dwInFlags & NUMPRS_TRAILING_MINUS &&
4980              !(pNumprs->dwOutFlags & NUMPRS_LEADING_MINUS) &&
4981              *lpszStr == chars.cNegativeSymbol)
4982     {
4983       pNumprs->dwOutFlags |= (NUMPRS_TRAILING_MINUS|NUMPRS_NEG);
4984       cchUsed++;
4985       lpszStr++;
4986     }
4987     else if (pNumprs->dwInFlags & NUMPRS_PARENS && *lpszStr == ')' &&
4988              pNumprs->dwOutFlags & NUMPRS_PARENS)
4989     {
4990       cchUsed++;
4991       lpszStr++;
4992       pNumprs->dwOutFlags |= NUMPRS_NEG;
4993     }
4994     else
4995       break;
4996   }
4997
4998   if (pNumprs->dwOutFlags & NUMPRS_PARENS && !(pNumprs->dwOutFlags & NUMPRS_NEG))
4999   {
5000     pNumprs->cchUsed = cchUsed;
5001     return DISP_E_TYPEMISMATCH; /* Opening parenthesis not matched */
5002   }
5003
5004   if (pNumprs->dwInFlags & NUMPRS_USE_ALL && *lpszStr != '\0')
5005     return DISP_E_TYPEMISMATCH; /* Not all chars were consumed */
5006
5007   if (!pNumprs->cDig)
5008     return DISP_E_TYPEMISMATCH; /* No Number found */
5009
5010   pNumprs->cchUsed = cchUsed;
5011   return S_OK;
5012 }
5013
5014 /* VTBIT flags indicating an integer value */
5015 #define INTEGER_VTBITS (VTBIT_I1|VTBIT_UI1|VTBIT_I2|VTBIT_UI2|VTBIT_I4|VTBIT_UI4|VTBIT_I8|VTBIT_UI8)
5016 /* VTBIT flags indicating a real number value */
5017 #define REAL_VTBITS (VTBIT_R4|VTBIT_R8|VTBIT_CY|VTBIT_DECIMAL)
5018
5019 /**********************************************************************
5020  *              VarNumFromParseNum [OLEAUT32.47]
5021  *
5022  * Convert a NUMPARSE structure into a numeric Variant type.
5023  *
5024  * PARAMS
5025  *  pNumprs  [I] Source for parsed number. cDig must be set to the size of rgbDig
5026  *  rgbDig   [I] Source for the numbers digits
5027  *  dwVtBits [I] VTBIT_ flags from "oleauto.h" indicating the acceptable dest types
5028  *  pVarDst  [O] Destination for the converted Variant value.
5029  *
5030  * RETURNS
5031  *  Success: S_OK. pVarDst contains the converted value.
5032  *  Failure: E_INVALIDARG, if any parameter is invalid.
5033  *           DISP_E_OVERFLOW, if the number is too big for the types set in dwVtBits.
5034  *
5035  * NOTES
5036  *  - The smallest favoured type present in dwVtBits that can represent the
5037  *    number in pNumprs without losing precision is used.
5038  *  - Signed types are preferrred over unsigned types of the same size.
5039  *  - Preferred types in order are: integer, float, double, currency then decimal.
5040  *  - Rounding (dropping of decimal points) occurs without error. See VarI8FromR8()
5041  *    for details of the rounding method.
5042  *  - pVarDst is not cleared before the result is stored in it.
5043  */
5044 HRESULT WINAPI VarNumFromParseNum(NUMPARSE *pNumprs, BYTE *rgbDig,
5045                                   ULONG dwVtBits, VARIANT *pVarDst)
5046 {
5047   /* Scale factors and limits for double arithmetics */
5048   static const double dblMultipliers[11] = {
5049     1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0,
5050     1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10000000000.0
5051   };
5052   static const double dblMinimums[11] = {
5053     R8_MIN, R8_MIN*10.0, R8_MIN*100.0, R8_MIN*1000.0, R8_MIN*10000.0,
5054     R8_MIN*100000.0, R8_MIN*1000000.0, R8_MIN*10000000.0,
5055     R8_MIN*100000000.0, R8_MIN*1000000000.0, R8_MIN*10000000000.0
5056   };
5057   static const double dblMaximums[11] = {
5058     R8_MAX, R8_MAX/10.0, R8_MAX/100.0, R8_MAX/1000.0, R8_MAX/10000.0,
5059     R8_MAX/100000.0, R8_MAX/1000000.0, R8_MAX/10000000.0,
5060     R8_MAX/100000000.0, R8_MAX/1000000000.0, R8_MAX/10000000000.0
5061   };
5062
5063   int wholeNumberDigits, fractionalDigits, divisor10 = 0, multiplier10 = 0;
5064
5065   TRACE("(%p,%p,0x%lx,%p)\n", pNumprs, rgbDig, dwVtBits, pVarDst);
5066
5067   if (pNumprs->nBaseShift)
5068   {
5069     /* nBaseShift indicates a hex or octal number */
5070     FIXME("nBaseShift=%d not yet implemented, returning overflow\n", pNumprs->nBaseShift);
5071     return DISP_E_OVERFLOW;
5072   }
5073
5074   /* Count the number of relevant fractional and whole digits stored,
5075    * And compute the divisor/multiplier to scale the number by.
5076    */
5077   if (pNumprs->nPwr10 < 0)
5078   {
5079     if (-pNumprs->nPwr10 >= pNumprs->cDig)
5080     {
5081       /* A real number < +/- 1.0 e.g. 0.1024 or 0.01024 */
5082       wholeNumberDigits = 0;
5083       fractionalDigits = pNumprs->cDig;
5084       divisor10 = -pNumprs->nPwr10;
5085     }
5086     else
5087     {
5088       /* An exactly represented real number e.g. 1.024 */
5089       wholeNumberDigits = pNumprs->cDig + pNumprs->nPwr10;
5090       fractionalDigits = pNumprs->cDig - wholeNumberDigits;
5091       divisor10 = pNumprs->cDig - wholeNumberDigits;
5092     }
5093   }
5094   else if (pNumprs->nPwr10 == 0)
5095   {
5096     /* An exactly represented whole number e.g. 1024 */
5097     wholeNumberDigits = pNumprs->cDig;
5098     fractionalDigits = 0;
5099   }
5100   else /* pNumprs->nPwr10 > 0 */
5101   {
5102     /* A whole number followed by nPwr10 0's e.g. 102400 */
5103     wholeNumberDigits = pNumprs->cDig;
5104     fractionalDigits = 0;
5105     multiplier10 = pNumprs->nPwr10;
5106   }
5107
5108   TRACE("cDig %d; nPwr10 %d, whole %d, frac %d ", pNumprs->cDig,
5109         pNumprs->nPwr10, wholeNumberDigits, fractionalDigits);
5110   TRACE("mult %d; div %d\n", multiplier10, divisor10);
5111
5112   if (dwVtBits & INTEGER_VTBITS &&
5113       (!fractionalDigits || !(dwVtBits & (REAL_VTBITS|VTBIT_CY|VTBIT_DECIMAL))))
5114   {
5115     /* We have one or more integer output choices, and either:
5116      *  1) An integer input value, or
5117      *  2) A real number input value but no floating output choices.
5118      * So, place the integer value into pVarDst, using the smallest type
5119      * possible and preferring signed over unsigned types.
5120      */
5121     BOOL bOverflow = FALSE, bNegative;
5122     ULONG64 ul64 = 0;
5123     int i;
5124
5125     /* Convert the integer part of the number into a UI8 */
5126     for (i = 0; i < wholeNumberDigits; i++)
5127     {
5128       if (ul64 > (UI8_MAX / 10 - rgbDig[i]))
5129       {
5130         TRACE("Overflow multiplying digits\n");
5131         bOverflow = TRUE;
5132         break;
5133       }
5134       ul64 = ul64 * 10 + rgbDig[i];
5135     }
5136
5137     /* Account for the scale of the number */
5138     if (!bOverflow && multiplier10)
5139     {
5140       for (i = 0; i < multiplier10; i++)
5141       {
5142         if (ul64 > (UI8_MAX / 10))
5143         {
5144           TRACE("Overflow scaling number\n");
5145           bOverflow = TRUE;
5146           break;
5147         }
5148         ul64 = ul64 * 10;
5149       }
5150     }
5151
5152     /* If we have any fractional digits, round the value.
5153      * Note we dont have to do this if divisor10 is < 1,
5154      * because this means the fractional part must be < 0.5
5155      */
5156     if (!bOverflow && fractionalDigits && divisor10 > 0)
5157     {
5158       const BYTE* fracDig = rgbDig + wholeNumberDigits;
5159       BOOL bAdjust = FALSE;
5160
5161       TRACE("first decimal value is %d\n", *fracDig);
5162
5163       if (*fracDig > 5)
5164         bAdjust = TRUE; /* > 0.5 */
5165       else if (*fracDig == 5)
5166       {
5167         for (i = 1; i < fractionalDigits; i++)
5168         {
5169           if (fracDig[i])
5170           {
5171             bAdjust = TRUE; /* > 0.5 */
5172             break;
5173           }
5174         }
5175         /* If exactly 0.5, round only odd values */
5176         if (i == fractionalDigits && (ul64 & 1))
5177           bAdjust = TRUE;
5178       }
5179
5180       if (bAdjust)
5181       {
5182         if (ul64 == UI8_MAX)
5183         {
5184           TRACE("Overflow after rounding\n");
5185           bOverflow = TRUE;
5186         }
5187         ul64++;
5188       }
5189     }
5190
5191     /* Zero is not a negative number */
5192     bNegative = pNumprs->dwOutFlags & NUMPRS_NEG && ul64 ? TRUE : FALSE;
5193
5194     TRACE("Integer value is %lld, bNeg %d\n", ul64, bNegative);
5195
5196     /* For negative integers, try the signed types in size order */
5197     if (!bOverflow && bNegative)
5198     {
5199       if (dwVtBits & (VTBIT_I1|VTBIT_I2|VTBIT_I4|VTBIT_I8))
5200       {
5201         if (dwVtBits & VTBIT_I1 && ul64 <= -I1_MIN)
5202         {
5203           V_VT(pVarDst) = VT_I1;
5204           V_I1(pVarDst) = -ul64;
5205           return S_OK;
5206         }
5207         else if (dwVtBits & VTBIT_I2 && ul64 <= -I2_MIN)
5208         {
5209           V_VT(pVarDst) = VT_I2;
5210           V_I2(pVarDst) = -ul64;
5211           return S_OK;
5212         }
5213         else if (dwVtBits & VTBIT_I4 && ul64 <= -((LONGLONG)I4_MIN))
5214         {
5215           V_VT(pVarDst) = VT_I4;
5216           V_I4(pVarDst) = -ul64;
5217           return S_OK;
5218         }
5219         else if (dwVtBits & VTBIT_I8 && ul64 <= (ULONGLONG)I8_MAX + 1)
5220         {
5221           V_VT(pVarDst) = VT_I8;
5222           V_I8(pVarDst) = -ul64;
5223           return S_OK;
5224         }
5225       }
5226     }
5227     else if (!bOverflow)
5228     {
5229       /* For positive integers, try signed then unsigned types in size order */
5230       if (dwVtBits & VTBIT_I1 && ul64 <= I1_MAX)
5231       {
5232         V_VT(pVarDst) = VT_I1;
5233         V_I1(pVarDst) = ul64;
5234         return S_OK;
5235       }
5236       if (dwVtBits & VTBIT_UI1 && ul64 <= UI1_MAX)
5237       {
5238         V_VT(pVarDst) = VT_UI1;
5239         V_UI1(pVarDst) = ul64;
5240         return S_OK;
5241       }
5242       if (dwVtBits & VTBIT_I2 && ul64 <= I2_MAX)
5243       {
5244         V_VT(pVarDst) = VT_I2;
5245         V_I2(pVarDst) = ul64;
5246         return S_OK;
5247       }
5248       if (dwVtBits & VTBIT_UI2 && ul64 <= UI2_MAX)
5249       {
5250         V_VT(pVarDst) = VT_UI2;
5251         V_UI2(pVarDst) = ul64;
5252         return S_OK;
5253       }
5254       if (dwVtBits & VTBIT_I4 && ul64 <= I4_MAX)
5255       {
5256         V_VT(pVarDst) = VT_I4;
5257         V_I4(pVarDst) = ul64;
5258         return S_OK;
5259       }
5260       if (dwVtBits & VTBIT_UI4 && ul64 <= UI4_MAX)
5261       {
5262         V_VT(pVarDst) = VT_UI4;
5263         V_UI4(pVarDst) = ul64;
5264         return S_OK;
5265       }
5266       if (dwVtBits & VTBIT_I8 && ul64 <= I8_MAX)
5267       {
5268         V_VT(pVarDst) = VT_I8;
5269         V_I8(pVarDst) = ul64;
5270         return S_OK;
5271       }
5272       if (dwVtBits & VTBIT_UI8)
5273       {
5274         V_VT(pVarDst) = VT_UI8;
5275         V_UI8(pVarDst) = ul64;
5276         return S_OK;
5277       }
5278     }
5279   }
5280
5281   if (dwVtBits & REAL_VTBITS)
5282   {
5283     /* Try to put the number into a float or real */
5284     BOOL bOverflow = FALSE, bNegative = pNumprs->dwOutFlags & NUMPRS_NEG;
5285     double whole = 0.0;
5286     int i;
5287
5288     /* Convert the number into a double */
5289     for (i = 0; i < pNumprs->cDig; i++)
5290       whole = whole * 10.0 + rgbDig[i];
5291
5292     TRACE("Whole double value is %16.16g\n", whole);
5293
5294     /* Account for the scale */
5295     while (multiplier10 > 10)
5296     {
5297       if (whole > dblMaximums[10])
5298       {
5299         dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY);
5300         bOverflow = TRUE;
5301         break;
5302       }
5303       whole = whole * dblMultipliers[10];
5304       multiplier10 -= 10;
5305     }
5306     if (multiplier10)
5307     {
5308       if (whole > dblMaximums[multiplier10])
5309       {
5310         dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY);
5311         bOverflow = TRUE;
5312       }
5313       else
5314         whole = whole * dblMultipliers[multiplier10];
5315     }
5316
5317     TRACE("Scaled double value is %16.16g\n", whole);
5318
5319     while (divisor10 > 10)
5320     {
5321       if (whole < dblMinimums[10])
5322       {
5323         dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); /* Underflow */
5324         bOverflow = TRUE;
5325         break;
5326       }
5327       whole = whole / dblMultipliers[10];
5328       divisor10 -= 10;
5329     }
5330     if (divisor10)
5331     {
5332       if (whole < dblMinimums[divisor10])
5333       {
5334         dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); /* Underflow */
5335         bOverflow = TRUE;
5336       }
5337       else
5338         whole = whole / dblMultipliers[divisor10];
5339     }
5340     if (!bOverflow)
5341       TRACE("Final double value is %16.16g\n", whole);
5342
5343     if (dwVtBits & VTBIT_R4 &&
5344         ((whole <= R4_MAX && whole >= R4_MIN) || whole == 0.0))
5345     {
5346       TRACE("Set R4 to final value\n");
5347       V_VT(pVarDst) = VT_R4; /* Fits into a float */
5348       V_R4(pVarDst) = pNumprs->dwOutFlags & NUMPRS_NEG ? -whole : whole;
5349       return S_OK;
5350     }
5351
5352     if (dwVtBits & VTBIT_R8)
5353     {
5354       TRACE("Set R8 to final value\n");
5355       V_VT(pVarDst) = VT_R8; /* Fits into a double */
5356       V_R8(pVarDst) = pNumprs->dwOutFlags & NUMPRS_NEG ? -whole : whole;
5357       return S_OK;
5358     }
5359
5360     if (dwVtBits & VTBIT_CY)
5361     {
5362       if (SUCCEEDED(VarCyFromR8(bNegative ? -whole : whole, &V_CY(pVarDst))))
5363       {
5364         V_VT(pVarDst) = VT_CY; /* Fits into a currency */
5365         TRACE("Set CY to final value\n");
5366         return S_OK;
5367       }
5368       TRACE("Value Overflows CY\n");
5369     }
5370
5371     if (!bOverflow && dwVtBits & VTBIT_DECIMAL)
5372     {
5373       WARN("VTBIT_DECIMAL not yet implemented\n");
5374 #if 0
5375       if (SUCCEEDED(VarDecFromR8(bNegative ? -whole : whole, &V_DECIMAL(pVarDst))))
5376       {
5377         V_VT(pVarDst) = VT_DECIMAL; /* Fits into a decimal */
5378         TRACE("Set DECIMAL to final value\n");
5379         return S_OK;
5380       }
5381 #endif
5382     }
5383   }
5384
5385   if (dwVtBits & VTBIT_DECIMAL)
5386   {
5387     FIXME("VT_DECIMAL > R8 not yet supported, returning overflow\n");
5388   }
5389   return DISP_E_OVERFLOW; /* No more output choices */
5390 }
5391
5392 /**********************************************************************
5393  *              VarFormatDateTime [OLEAUT32.97]
5394  */
5395 HRESULT WINAPI VarFormatDateTime(LPVARIANT var, INT format, ULONG dwFlags, BSTR *out)
5396 {
5397     FIXME("%p %d %lx %p\n", var, format, dwFlags, out);
5398     return E_NOTIMPL;
5399 }
5400
5401 /**********************************************************************
5402  *              VarFormatCurrency [OLEAUT32.127]
5403  */
5404 HRESULT WINAPI VarFormatCurrency(LPVARIANT var, INT digits, INT lead, INT paren, INT group, ULONG dwFlags, BSTR *out)
5405 {
5406     FIXME("%p %d %d %d %d %lx %p\n", var, digits, lead, paren, group, dwFlags, out);
5407     return E_NOTIMPL;
5408 }
5409
5410 /**********************************************************************
5411  *              VarBstrCmp [OLEAUT32.314]
5412  *
5413  * flags can be:
5414  *   NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
5415  *   NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
5416  *
5417  */
5418 HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
5419 {
5420     INT r;
5421
5422     TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
5423
5424     /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
5425     if((!left) || (!right)) {
5426
5427         if (!left && (!right || *right==0)) return VARCMP_EQ;
5428         else if (!right && (!left || *left==0)) return VARCMP_EQ;
5429         else return VARCMP_NULL;
5430     }
5431
5432     if(flags&NORM_IGNORECASE)
5433         r = lstrcmpiW(left,right);
5434     else
5435         r = lstrcmpW(left,right);
5436
5437     if(r<0)
5438         return VARCMP_LT;
5439     if(r>0)
5440         return VARCMP_GT;
5441
5442     return VARCMP_EQ;
5443 }
5444
5445 /**********************************************************************
5446  *              VarBstrCat [OLEAUT32.313]
5447  */
5448 HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
5449 {
5450     BSTR result;
5451     int size = 0;
5452
5453     TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
5454
5455     /* On Windows, NULL parms are still handled (as empty strings) */
5456     if (left)  size=size + lstrlenW(left);
5457     if (right) size=size + lstrlenW(right);
5458
5459     if (out) {
5460         result = SysAllocStringLen(NULL, size);
5461         *out = result;
5462         if (left) lstrcatW(result,left);
5463         if (right) lstrcatW(result,right);
5464         TRACE("result = %s, [%p]\n", debugstr_w(result), result);
5465     }
5466     return S_OK;
5467 }
5468
5469 /**********************************************************************
5470  *              VarCat [OLEAUT32.318]
5471  */
5472 HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
5473 {
5474     /* Should we VariantClear out? */
5475     /* Can we handle array, vector, by ref etc. */
5476     if ((V_VT(left)&VT_TYPEMASK) == VT_NULL &&
5477         (V_VT(right)&VT_TYPEMASK) == VT_NULL)
5478     {
5479         V_VT(out) = VT_NULL;
5480         return S_OK;
5481     }
5482
5483     if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR)
5484     {
5485         V_VT(out) = VT_BSTR;
5486         VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out));
5487         return S_OK;
5488     }
5489     if (V_VT(left) == VT_BSTR) {
5490         VARIANT bstrvar;
5491         HRESULT hres;
5492
5493         V_VT(out) = VT_BSTR;
5494         hres = VariantChangeTypeEx(&bstrvar,right,0,0,VT_BSTR);
5495         if (hres) {
5496             FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right));
5497             return hres;
5498         }
5499         VarBstrCat (V_BSTR(left), V_BSTR(&bstrvar), &V_BSTR(out));
5500         return S_OK;
5501     }
5502     if (V_VT(right) == VT_BSTR) {
5503         VARIANT bstrvar;
5504         HRESULT hres;
5505
5506         V_VT(out) = VT_BSTR;
5507         hres = VariantChangeTypeEx(&bstrvar,left,0,0,VT_BSTR);
5508         if (hres) {
5509             FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right));
5510             return hres;
5511         }
5512         VarBstrCat (V_BSTR(&bstrvar), V_BSTR(right), &V_BSTR(out));
5513         return S_OK;
5514     }
5515     FIXME ("types %d / %d not supported\n",V_VT(left)&VT_TYPEMASK, V_VT(right)&VT_TYPEMASK);
5516     return S_OK;
5517 }
5518
5519 /**********************************************************************
5520  *              VarCmp [OLEAUT32.176]
5521  *
5522  * flags can be:
5523  *   NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
5524  *   NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
5525  *
5526  */
5527 HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
5528 {
5529
5530
5531     BOOL        lOk        = TRUE;
5532     BOOL        rOk        = TRUE;
5533     LONGLONG    lVal = -1;
5534     LONGLONG    rVal = -1;
5535     VARIANT     rv,lv;
5536     DWORD       xmask;
5537     HRESULT     rc;
5538
5539     VariantInit(&lv);VariantInit(&rv);
5540     V_VT(right) &= ~0x8000; /* hack since we sometime get this flag.  */
5541     V_VT(left) &= ~0x8000; /* hack since we sometime get this flag. */
5542
5543     TRACE("Left Var:\n");
5544     dump_Variant(left);
5545     TRACE("Right Var:\n");
5546     dump_Variant(right);
5547
5548     /* If either are null, then return VARCMP_NULL */
5549     if ((V_VT(left)&VT_TYPEMASK) == VT_NULL ||
5550         (V_VT(right)&VT_TYPEMASK) == VT_NULL)
5551         return VARCMP_NULL;
5552
5553     /* Strings - use VarBstrCmp */
5554     if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
5555         (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
5556         return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags);
5557     }
5558
5559     xmask = (1<<(V_VT(left)&VT_TYPEMASK))|(1<<(V_VT(right)&VT_TYPEMASK));
5560     if (xmask & (1<<VT_R8)) {
5561         rc = VariantChangeType(&lv,left,0,VT_R8);
5562         if (FAILED(rc)) return rc;
5563         rc = VariantChangeType(&rv,right,0,VT_R8);
5564         if (FAILED(rc)) return rc;
5565         
5566         if (V_R8(&lv) == V_R8(&rv)) return VARCMP_EQ;
5567         if (V_R8(&lv) < V_R8(&rv)) return VARCMP_LT;
5568         if (V_R8(&lv) > V_R8(&rv)) return VARCMP_GT;
5569         return E_FAIL; /* can't get here */
5570     }
5571     if (xmask & (1<<VT_R4)) {
5572         rc = VariantChangeType(&lv,left,0,VT_R4);
5573         if (FAILED(rc)) return rc;
5574         rc = VariantChangeType(&rv,right,0,VT_R4);
5575         if (FAILED(rc)) return rc;
5576         
5577         if (V_R4(&lv) == V_R4(&rv)) return VARCMP_EQ;
5578         if (V_R4(&lv) < V_R4(&rv)) return VARCMP_LT;
5579         if (V_R4(&lv) > V_R4(&rv)) return VARCMP_GT;
5580         return E_FAIL; /* can't get here */
5581     }
5582
5583     /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
5584            Use LONGLONG to maximize ranges                              */
5585     lOk = TRUE;
5586     switch (V_VT(left)&VT_TYPEMASK) {
5587     case VT_I1   : lVal = V_UNION(left,cVal); break;
5588     case VT_I2   : lVal = V_UNION(left,iVal); break;
5589     case VT_I4   : lVal = V_UNION(left,lVal); break;
5590     case VT_INT  : lVal = V_UNION(left,lVal); break;
5591     case VT_UI1  : lVal = V_UNION(left,bVal); break;
5592     case VT_UI2  : lVal = V_UNION(left,uiVal); break;
5593     case VT_UI4  : lVal = V_UNION(left,ulVal); break;
5594     case VT_UINT : lVal = V_UNION(left,ulVal); break;
5595     case VT_BOOL : lVal = V_UNION(left,boolVal); break;
5596     default: lOk = FALSE;
5597     }
5598
5599     rOk = TRUE;
5600     switch (V_VT(right)&VT_TYPEMASK) {
5601     case VT_I1   : rVal = V_UNION(right,cVal); break;
5602     case VT_I2   : rVal = V_UNION(right,iVal); break;
5603     case VT_I4   : rVal = V_UNION(right,lVal); break;
5604     case VT_INT  : rVal = V_UNION(right,lVal); break;
5605     case VT_UI1  : rVal = V_UNION(right,bVal); break;
5606     case VT_UI2  : rVal = V_UNION(right,uiVal); break;
5607     case VT_UI4  : rVal = V_UNION(right,ulVal); break;
5608     case VT_UINT : rVal = V_UNION(right,ulVal); break;
5609     case VT_BOOL : rVal = V_UNION(right,boolVal); break;
5610     default: rOk = FALSE;
5611     }
5612
5613     if (lOk && rOk) {
5614         if (lVal < rVal) {
5615             return VARCMP_LT;
5616         } else if (lVal > rVal) {
5617             return VARCMP_GT;
5618         } else {
5619             return VARCMP_EQ;
5620         }
5621     }
5622
5623     /* Strings - use VarBstrCmp */
5624     if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
5625         (V_VT(right)&VT_TYPEMASK) == VT_DATE) {
5626
5627         if (floor(V_UNION(left,date)) == floor(V_UNION(right,date))) {
5628             /* Due to floating point rounding errors, calculate varDate in whole numbers) */
5629             double wholePart = 0.0;
5630             double leftR;
5631             double rightR;
5632
5633             /* Get the fraction * 24*60*60 to make it into whole seconds */
5634             wholePart = (double) floor( V_UNION(left,date) );
5635             if (wholePart == 0) wholePart = 1;
5636             leftR = floor(fmod( V_UNION(left,date), wholePart ) * (24*60*60));
5637
5638             wholePart = (double) floor( V_UNION(right,date) );
5639             if (wholePart == 0) wholePart = 1;
5640             rightR = floor(fmod( V_UNION(right,date), wholePart ) * (24*60*60));
5641
5642             if (leftR < rightR) {
5643                 return VARCMP_LT;
5644             } else if (leftR > rightR) {
5645                 return VARCMP_GT;
5646             } else {
5647                 return VARCMP_EQ;
5648             }
5649
5650         } else if (V_UNION(left,date) < V_UNION(right,date)) {
5651             return VARCMP_LT;
5652         } else if (V_UNION(left,date) > V_UNION(right,date)) {
5653             return VARCMP_GT;
5654         }
5655     }
5656     FIXME("VarCmp partial implementation, doesnt support vt 0x%x / 0x%x\n",V_VT(left), V_VT(right));
5657     return E_FAIL;
5658 }
5659
5660 /**********************************************************************
5661  *              VarAnd [OLEAUT32.142]
5662  *
5663  */
5664 HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5665 {
5666     HRESULT rc = E_FAIL;
5667
5668     TRACE("Left Var:\n");
5669     dump_Variant(left);
5670     TRACE("Right Var:\n");
5671     dump_Variant(right);
5672
5673     if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5674         (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5675
5676         V_VT(result) = VT_BOOL;
5677         if (V_BOOL(left) && V_BOOL(right)) {
5678             V_BOOL(result) = VARIANT_TRUE;
5679         } else {
5680             V_BOOL(result) = VARIANT_FALSE;
5681         }
5682         rc = S_OK;
5683
5684     } else {
5685         /* Integers */
5686         BOOL         lOk        = TRUE;
5687         BOOL         rOk        = TRUE;
5688         LONGLONG     lVal = -1;
5689         LONGLONG     rVal = -1;
5690         LONGLONG     res  = -1;
5691         int          resT = 0; /* Testing has shown I2 & I2 == I2, all else
5692                                   becomes I4, even unsigned ints (incl. UI2) */
5693
5694         lOk = TRUE;
5695         switch (V_VT(left)&VT_TYPEMASK) {
5696         case VT_I1   : lVal = V_UNION(left,cVal);  resT=VT_I4; break;
5697         case VT_I2   : lVal = V_UNION(left,iVal);  resT=VT_I2; break;
5698         case VT_I4   : lVal = V_UNION(left,lVal);  resT=VT_I4; break;
5699         case VT_INT  : lVal = V_UNION(left,lVal);  resT=VT_I4; break;
5700         case VT_UI1  : lVal = V_UNION(left,bVal);  resT=VT_I4; break;
5701         case VT_UI2  : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5702         case VT_UI4  : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5703         case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5704         default: lOk = FALSE;
5705         }
5706
5707         rOk = TRUE;
5708         switch (V_VT(right)&VT_TYPEMASK) {
5709         case VT_I1   : rVal = V_UNION(right,cVal);  resT=VT_I4; break;
5710         case VT_I2   : rVal = V_UNION(right,iVal);  resT=max(VT_I2, resT); break;
5711         case VT_I4   : rVal = V_UNION(right,lVal);  resT=VT_I4; break;
5712         case VT_INT  : rVal = V_UNION(right,lVal);  resT=VT_I4; break;
5713         case VT_UI1  : rVal = V_UNION(right,bVal);  resT=VT_I4; break;
5714         case VT_UI2  : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5715         case VT_UI4  : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5716         case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5717         default: rOk = FALSE;
5718         }
5719
5720         if (lOk && rOk) {
5721             res = (lVal & rVal);
5722             V_VT(result) = resT;
5723             switch (resT) {
5724             case VT_I2   : V_UNION(result,iVal)  = res; break;
5725             case VT_I4   : V_UNION(result,lVal)  = res; break;
5726             default:
5727                 FIXME("Unexpected result variant type %x\n", resT);
5728                 V_UNION(result,lVal)  = res;
5729             }
5730             rc = S_OK;
5731
5732         } else {
5733             FIXME("VarAnd stub\n");
5734         }
5735     }
5736
5737     TRACE("rc=%d, Result:\n", (int) rc);
5738     dump_Variant(result);
5739     return rc;
5740 }
5741
5742 /**********************************************************************
5743  *              VarAdd [OLEAUT32.141]
5744  * FIXME: From MSDN: If ... Then
5745  * Both expressions are of the string type Concatenated.
5746  * One expression is a string type and the other a character Addition.
5747  * One expression is numeric and the other is a string Addition.
5748  * Both expressions are numeric Addition.
5749  * Either expression is NULL NULL is returned.
5750  * Both expressions are empty  Integer subtype is returned.
5751  *
5752  */
5753 HRESULT WINAPI VarAdd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5754 {
5755     HRESULT rc = E_FAIL;
5756
5757     TRACE("Left Var:\n");
5758     dump_Variant(left);
5759     TRACE("Right Var:\n");
5760     dump_Variant(right);
5761
5762     if ((V_VT(left)&VT_TYPEMASK) == VT_EMPTY)
5763         return VariantCopy(result,right);
5764
5765     if ((V_VT(right)&VT_TYPEMASK) == VT_EMPTY)
5766         return VariantCopy(result,left);
5767
5768     if (((V_VT(left)&VT_TYPEMASK) == VT_R8) || ((V_VT(right)&VT_TYPEMASK) == VT_R8)) {
5769         BOOL         lOk        = TRUE;
5770         BOOL         rOk        = TRUE;
5771         double       lVal = -1;
5772         double       rVal = -1;
5773         double       res  = -1;
5774
5775         lOk = TRUE;
5776         switch (V_VT(left)&VT_TYPEMASK) {
5777         case VT_I1   : lVal = V_UNION(left,cVal);   break;
5778         case VT_I2   : lVal = V_UNION(left,iVal);   break;
5779         case VT_I4   : lVal = V_UNION(left,lVal);   break;
5780         case VT_INT  : lVal = V_UNION(left,lVal);   break;
5781         case VT_UI1  : lVal = V_UNION(left,bVal);   break;
5782         case VT_UI2  : lVal = V_UNION(left,uiVal);  break;
5783         case VT_UI4  : lVal = V_UNION(left,ulVal);  break;
5784         case VT_UINT : lVal = V_UNION(left,ulVal);  break;
5785         case VT_R4   : lVal = V_UNION(left,fltVal);  break;
5786         case VT_R8   : lVal = V_UNION(left,dblVal);  break;
5787         case VT_NULL : lVal = 0.0;  break;
5788         default: lOk = FALSE;
5789         }
5790
5791         rOk = TRUE;
5792         switch (V_VT(right)&VT_TYPEMASK) {
5793         case VT_I1   : rVal = V_UNION(right,cVal);  break;
5794         case VT_I2   : rVal = V_UNION(right,iVal);  break;
5795         case VT_I4   : rVal = V_UNION(right,lVal);  break;
5796         case VT_INT  : rVal = V_UNION(right,lVal);  break;
5797         case VT_UI1  : rVal = V_UNION(right,bVal);  break;
5798         case VT_UI2  : rVal = V_UNION(right,uiVal); break;
5799         case VT_UI4  : rVal = V_UNION(right,ulVal); break;
5800         case VT_UINT : rVal = V_UNION(right,ulVal); break;
5801         case VT_R4   : rVal = V_UNION(right,fltVal);break;
5802         case VT_R8   : rVal = V_UNION(right,dblVal);break;
5803         case VT_NULL : rVal = 0.0; break;
5804         default: rOk = FALSE;
5805         }
5806
5807         if (lOk && rOk) {
5808             res = (lVal + rVal);
5809             V_VT(result) = VT_R8;
5810             V_UNION(result,dblVal)  = res;
5811             rc = S_OK;
5812         } else {
5813             FIXME("Unhandled type pair %d / %d in double addition.\n", 
5814                 (V_VT(left)&VT_TYPEMASK),
5815                 (V_VT(right)&VT_TYPEMASK)
5816             );
5817         }
5818         return rc;
5819     }
5820
5821     /* Handle strings as concat */
5822     if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
5823         (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
5824         V_VT(result) = VT_BSTR;
5825         rc = VarBstrCat(V_BSTR(left), V_BSTR(right), &V_BSTR(result));
5826     } else {
5827
5828         /* Integers */
5829         BOOL         lOk        = TRUE;
5830         BOOL         rOk        = TRUE;
5831         LONGLONG     lVal = -1;
5832         LONGLONG     rVal = -1;
5833         LONGLONG     res  = -1;
5834         int          resT = 0; /* Testing has shown I2 + I2 == I2, all else
5835                                   becomes I4                                */
5836
5837         lOk = TRUE;
5838         switch (V_VT(left)&VT_TYPEMASK) {
5839         case VT_I1   : lVal = V_UNION(left,cVal);  resT=VT_I4; break;
5840         case VT_I2   : lVal = V_UNION(left,iVal);  resT=VT_I2; break;
5841         case VT_I4   : lVal = V_UNION(left,lVal);  resT=VT_I4; break;
5842         case VT_INT  : lVal = V_UNION(left,lVal);  resT=VT_I4; break;
5843         case VT_UI1  : lVal = V_UNION(left,bVal);  resT=VT_I4; break;
5844         case VT_UI2  : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5845         case VT_UI4  : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5846         case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5847         case VT_NULL : lVal = 0; resT = VT_I4; break;
5848         default: lOk = FALSE;
5849         }
5850
5851         rOk = TRUE;
5852         switch (V_VT(right)&VT_TYPEMASK) {
5853         case VT_I1   : rVal = V_UNION(right,cVal);  resT=VT_I4; break;
5854         case VT_I2   : rVal = V_UNION(right,iVal);  resT=max(VT_I2, resT); break;
5855         case VT_I4   : rVal = V_UNION(right,lVal);  resT=VT_I4; break;
5856         case VT_INT  : rVal = V_UNION(right,lVal);  resT=VT_I4; break;
5857         case VT_UI1  : rVal = V_UNION(right,bVal);  resT=VT_I4; break;
5858         case VT_UI2  : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5859         case VT_UI4  : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5860         case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5861         case VT_NULL : rVal = 0; resT=VT_I4; break;
5862         default: rOk = FALSE;
5863         }
5864
5865         if (lOk && rOk) {
5866             res = (lVal + rVal);
5867             V_VT(result) = resT;
5868             switch (resT) {
5869             case VT_I2   : V_UNION(result,iVal)  = res; break;
5870             case VT_I4   : V_UNION(result,lVal)  = res; break;
5871             default:
5872                 FIXME("Unexpected result variant type %x\n", resT);
5873                 V_UNION(result,lVal)  = res;
5874             }
5875             rc = S_OK;
5876
5877         } else {
5878             FIXME("unimplemented part (0x%x + 0x%x)\n",V_VT(left), V_VT(right));
5879         }
5880     }
5881
5882     TRACE("rc=%d, Result:\n", (int) rc);
5883     dump_Variant(result);
5884     return rc;
5885 }
5886
5887 /**********************************************************************
5888  *              VarMul [OLEAUT32.156]
5889  *
5890  */
5891 HRESULT WINAPI VarMul(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5892 {
5893     HRESULT rc = E_FAIL;
5894     VARTYPE lvt,rvt,resvt;
5895     VARIANT lv,rv;
5896     BOOL found;
5897
5898     TRACE("left: ");dump_Variant(left);
5899     TRACE("right: ");dump_Variant(right);
5900
5901     VariantInit(&lv);VariantInit(&rv);
5902     lvt = V_VT(left)&VT_TYPEMASK;
5903     rvt = V_VT(right)&VT_TYPEMASK;
5904     found = FALSE;resvt=VT_VOID;
5905     if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
5906         found = TRUE;
5907         resvt = VT_R8;
5908     }
5909     if (!found && (((1<<lvt) | (1<<rvt)) & ((1<<VT_I1)|(1<<VT_I2)|(1<<VT_UI1)|(1<<VT_UI2)|(1<<VT_I4)|(1<<VT_UI4)|(1<<VT_INT)|(1<<VT_UINT)))) {
5910         found = TRUE;
5911         resvt = VT_I4;
5912     }
5913     if (!found) {
5914         FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
5915         return E_FAIL;
5916     }
5917     rc = VariantChangeType(&lv, left, 0, resvt);
5918     if (FAILED(rc)) {
5919         FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
5920         return rc;
5921     }
5922     rc = VariantChangeType(&rv, right, 0, resvt);
5923     if (FAILED(rc)) {
5924         FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
5925         return rc;
5926     }
5927     switch (resvt) {
5928     case VT_R8:
5929         V_VT(result) = resvt;
5930         V_R8(result) = V_R8(&lv) * V_R8(&rv);
5931         rc = S_OK;
5932         break;
5933     case VT_I4:
5934         V_VT(result) = resvt;
5935         V_I4(result) = V_I4(&lv) * V_I4(&rv);
5936         rc = S_OK;
5937         break;
5938     }
5939     TRACE("rc=%d, Result:\n", (int) rc);
5940     dump_Variant(result);
5941     return rc;
5942 }
5943
5944 /**********************************************************************
5945  *              VarDiv [OLEAUT32.143]
5946  *
5947  */
5948 HRESULT WINAPI VarDiv(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5949 {
5950     HRESULT rc = E_FAIL;
5951     VARTYPE lvt,rvt,resvt;
5952     VARIANT lv,rv;
5953     BOOL found;
5954
5955     TRACE("left: ");dump_Variant(left);
5956     TRACE("right: ");dump_Variant(right);
5957
5958     VariantInit(&lv);VariantInit(&rv);
5959     lvt = V_VT(left)&VT_TYPEMASK;
5960     rvt = V_VT(right)&VT_TYPEMASK;
5961     found = FALSE;resvt = VT_VOID;
5962     if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
5963         found = TRUE;
5964         resvt = VT_R8;
5965     }
5966     if (!found && (((1<<lvt) | (1<<rvt)) & ((1<<VT_I1)|(1<<VT_I2)|(1<<VT_UI1)|(1<<VT_UI2)|(1<<VT_I4)|(1<<VT_UI4)|(1<<VT_INT)|(1<<VT_UINT)))) {
5967         found = TRUE;
5968         resvt = VT_I4;
5969     }
5970     if (!found) {
5971         FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
5972         return E_FAIL;
5973     }
5974     rc = VariantChangeType(&lv, left, 0, resvt);
5975     if (FAILED(rc)) {
5976         FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
5977         return rc;
5978     }
5979     rc = VariantChangeType(&rv, right, 0, resvt);
5980     if (FAILED(rc)) {
5981         FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
5982         return rc;
5983     }
5984     switch (resvt) {
5985     case VT_R8:
5986         V_VT(result) = resvt;
5987         V_R8(result) = V_R8(&lv) / V_R8(&rv);
5988         rc = S_OK;
5989         break;
5990     case VT_I4:
5991         V_VT(result) = resvt;
5992         V_I4(result) = V_I4(&lv) / V_I4(&rv);
5993         rc = S_OK;
5994         break;
5995     }
5996     TRACE("rc=%d, Result:\n", (int) rc);
5997     dump_Variant(result);
5998     return rc;
5999 }
6000
6001 /**********************************************************************
6002  *              VarSub [OLEAUT32.159]
6003  *
6004  */
6005 HRESULT WINAPI VarSub(LPVARIANT left, LPVARIANT right, LPVARIANT result)
6006 {
6007     HRESULT rc = E_FAIL;
6008     VARTYPE lvt,rvt,resvt;
6009     VARIANT lv,rv;
6010     BOOL found;
6011
6012     TRACE("left: ");dump_Variant(left);
6013     TRACE("right: ");dump_Variant(right);
6014
6015     VariantInit(&lv);VariantInit(&rv);
6016     lvt = V_VT(left)&VT_TYPEMASK;
6017     rvt = V_VT(right)&VT_TYPEMASK;
6018     found = FALSE;resvt = VT_VOID;
6019     if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
6020         found = TRUE;
6021         resvt = VT_R8;
6022     }
6023     if (!found && (((1<<lvt) | (1<<rvt)) & ((1<<VT_I1)|(1<<VT_I2)|(1<<VT_UI1)|(1<<VT_UI2)|(1<<VT_I4)|(1<<VT_UI4)|(1<<VT_INT)|(1<<VT_UINT)))) {
6024         found = TRUE;
6025         resvt = VT_I4;
6026     }
6027     if (!found) {
6028         FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
6029         return E_FAIL;
6030     }
6031     rc = VariantChangeType(&lv, left, 0, resvt);
6032     if (FAILED(rc)) {
6033         FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
6034         return rc;
6035     }
6036     rc = VariantChangeType(&rv, right, 0, resvt);
6037     if (FAILED(rc)) {
6038         FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
6039         return rc;
6040     }
6041     switch (resvt) {
6042     case VT_R8:
6043         V_VT(result) = resvt;
6044         V_R8(result) = V_R8(&lv) - V_R8(&rv);
6045         rc = S_OK;
6046         break;
6047     case VT_I4:
6048         V_VT(result) = resvt;
6049         V_I4(result) = V_I4(&lv) - V_I4(&rv);
6050         rc = S_OK;
6051         break;
6052     }
6053     TRACE("rc=%d, Result:\n", (int) rc);
6054     dump_Variant(result);
6055     return rc;
6056 }
6057
6058 /**********************************************************************
6059  *              VarOr [OLEAUT32.157]
6060  *
6061  */
6062 HRESULT WINAPI VarOr(LPVARIANT left, LPVARIANT right, LPVARIANT result)
6063 {
6064     HRESULT rc = E_FAIL;
6065
6066     TRACE("Left Var:\n");
6067     dump_Variant(left);
6068     TRACE("Right Var:\n");
6069     dump_Variant(right);
6070
6071     if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
6072         (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
6073
6074         V_VT(result) = VT_BOOL;
6075         if (V_BOOL(left) || V_BOOL(right)) {
6076             V_BOOL(result) = VARIANT_TRUE;
6077         } else {
6078             V_BOOL(result) = VARIANT_FALSE;
6079         }
6080         rc = S_OK;
6081
6082     } else {
6083         /* Integers */
6084         BOOL         lOk        = TRUE;
6085         BOOL         rOk        = TRUE;
6086         LONGLONG     lVal = -1;
6087         LONGLONG     rVal = -1;
6088         LONGLONG     res  = -1;
6089         int          resT = 0; /* Testing has shown I2 & I2 == I2, all else
6090                                   becomes I4, even unsigned ints (incl. UI2) */
6091
6092         lOk = TRUE;
6093         switch (V_VT(left)&VT_TYPEMASK) {
6094         case VT_I1   : lVal = V_UNION(left,cVal);  resT=VT_I4; break;
6095         case VT_I2   : lVal = V_UNION(left,iVal);  resT=VT_I2; break;
6096         case VT_I4   : lVal = V_UNION(left,lVal);  resT=VT_I4; break;
6097         case VT_INT  : lVal = V_UNION(left,lVal);  resT=VT_I4; break;
6098         case VT_UI1  : lVal = V_UNION(left,bVal);  resT=VT_I4; break;
6099         case VT_UI2  : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
6100         case VT_UI4  : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
6101         case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
6102         default: lOk = FALSE;
6103         }
6104
6105         rOk = TRUE;
6106         switch (V_VT(right)&VT_TYPEMASK) {
6107         case VT_I1   : rVal = V_UNION(right,cVal);  resT=VT_I4; break;
6108         case VT_I2   : rVal = V_UNION(right,iVal);  resT=max(VT_I2, resT); break;
6109         case VT_I4   : rVal = V_UNION(right,lVal);  resT=VT_I4; break;
6110         case VT_INT  : rVal = V_UNION(right,lVal);  resT=VT_I4; break;
6111         case VT_UI1  : rVal = V_UNION(right,bVal);  resT=VT_I4; break;
6112         case VT_UI2  : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
6113         case VT_UI4  : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
6114         case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
6115         default: rOk = FALSE;
6116         }
6117
6118         if (lOk && rOk) {
6119             res = (lVal | rVal);
6120             V_VT(result) = resT;
6121             switch (resT) {
6122             case VT_I2   : V_UNION(result,iVal)  = res; break;
6123             case VT_I4   : V_UNION(result,lVal)  = res; break;
6124             default:
6125                 FIXME("Unexpected result variant type %x\n", resT);
6126                 V_UNION(result,lVal)  = res;
6127             }
6128             rc = S_OK;
6129
6130         } else {
6131             FIXME("unimplemented part\n");
6132         }
6133     }
6134
6135     TRACE("rc=%d, Result:\n", (int) rc);
6136     dump_Variant(result);
6137     return rc;
6138 }
6139
6140 /**********************************************************************
6141  *              VarNot [OLEAUT32.174]
6142  *
6143  */
6144 HRESULT WINAPI VarNot(LPVARIANT in, LPVARIANT result)
6145 {
6146     HRESULT rc = E_FAIL;
6147
6148     TRACE("Var In:\n");
6149     dump_Variant(in);
6150
6151     if ((V_VT(in)&VT_TYPEMASK) == VT_BOOL) {
6152
6153         V_VT(result) = VT_BOOL;
6154         if (V_BOOL(in)) {
6155             V_BOOL(result) = VARIANT_FALSE;
6156         } else {
6157             V_BOOL(result) = VARIANT_TRUE;
6158         }
6159         rc = S_OK;
6160
6161     } else {
6162         FIXME("VarNot stub\n");
6163     }
6164
6165     TRACE("rc=%d, Result:\n", (int) rc);
6166     dump_Variant(result);
6167     return rc;
6168 }
6169
6170 /**********************************************************************
6171  *              VarTokenizeFormatString [OLEAUT32.140]
6172  *
6173  * From investigation on W2K, a list is built up which is:
6174  *
6175  * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
6176  * <token> - Insert appropriate token
6177  *
6178  */
6179 HRESULT WINAPI VarTokenizeFormatString(LPOLESTR  format, LPBYTE rgbTok,
6180                      int   cbTok, int iFirstDay, int iFirstWeek,
6181                      LCID  lcid, int *pcbActual) {
6182
6183     FORMATHDR *hdr;
6184     int        realLen, formatLeft;
6185     BYTE      *pData;
6186     LPSTR      pFormatA, pStart;
6187     int        checkStr;
6188     BOOL       insertCopy = FALSE;
6189     LPSTR      copyFrom = NULL;
6190
6191     TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format), rgbTok, cbTok,
6192                    iFirstDay, iFirstWeek);
6193
6194     /* Big enough for header? */
6195     if (cbTok < sizeof(FORMATHDR)) {
6196         return TYPE_E_BUFFERTOOSMALL;
6197     }
6198
6199     /* Insert header */
6200     hdr = (FORMATHDR *) rgbTok;
6201     memset(hdr, 0x00, sizeof(FORMATHDR));
6202     hdr->hex3 = 0x03; /* No idea what these are */
6203     hdr->hex6 = 0x06;
6204
6205     /* Start parsing string */
6206     realLen    = sizeof(FORMATHDR);
6207     pData      = rgbTok + realLen;
6208     pFormatA   = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
6209     pStart     = pFormatA;
6210     formatLeft = strlen(pFormatA);
6211
6212     /* Work through the format */
6213     while (*pFormatA != 0x00) {
6214
6215         checkStr = 0;
6216         while (checkStr>=0 && (formatTokens[checkStr].tokenSize != 0x00)) {
6217             if (formatLeft >= formatTokens[checkStr].tokenSize &&
6218                 strncmp(formatTokens[checkStr].str, pFormatA,
6219                         formatTokens[checkStr].tokenSize) == 0) {
6220                 TRACE("match on '%s'\n", formatTokens[checkStr].str);
6221
6222                 /* Found Match! */
6223
6224                 /* If we have skipped chars, insert the copy */
6225                 if (insertCopy == TRUE) {
6226
6227                     if ((realLen + 3) > cbTok) {
6228                         HeapFree( GetProcessHeap(), 0, pFormatA );
6229                         return TYPE_E_BUFFERTOOSMALL;
6230                     }
6231                     insertCopy = FALSE;
6232                     *pData = TOK_COPY;
6233                     pData++;
6234                     *pData = (BYTE)(copyFrom - pStart);
6235                     pData++;
6236                     *pData = (BYTE)(pFormatA - copyFrom);
6237                     pData++;
6238                     realLen = realLen + 3;
6239                 }
6240
6241
6242                 /* Now insert the token itself */
6243                 if ((realLen + 1) > cbTok) {
6244                     HeapFree( GetProcessHeap(), 0, pFormatA );
6245                     return TYPE_E_BUFFERTOOSMALL;
6246                 }
6247                 *pData = formatTokens[checkStr].tokenId;
6248                 pData = pData + 1;
6249                 realLen = realLen + 1;
6250
6251                 pFormatA = pFormatA + formatTokens[checkStr].tokenSize;
6252                 formatLeft = formatLeft - formatTokens[checkStr].tokenSize;
6253                 checkStr = -1; /* Flag as found and break out of while loop */
6254             } else {
6255                 checkStr++;
6256             }
6257         }
6258
6259         /* Did we ever match a token? */
6260         if (checkStr != -1 && insertCopy == FALSE) {
6261             TRACE("No match - need to insert copy from %p [%p]\n", pFormatA, pStart);
6262             insertCopy = TRUE;
6263             copyFrom   = pFormatA;
6264         } else if (checkStr != -1) {
6265             pFormatA = pFormatA + 1;
6266         }
6267
6268     }
6269
6270     /* Finally, if we have skipped chars, insert the copy */
6271     if (insertCopy == TRUE) {
6272
6273         TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom, pStart, pFormatA);
6274         if ((realLen + 3) > cbTok) {
6275             HeapFree( GetProcessHeap(), 0, pFormatA );
6276             return TYPE_E_BUFFERTOOSMALL;
6277         }
6278         insertCopy = FALSE;
6279         *pData = TOK_COPY;
6280         pData++;
6281         *pData = (BYTE)(copyFrom - pStart);
6282         pData++;
6283         *pData = (BYTE)(pFormatA - copyFrom);
6284         pData++;
6285         realLen = realLen + 3;
6286     }
6287
6288     /* Finally insert the terminator */
6289     if ((realLen + 1) > cbTok) {
6290         HeapFree( GetProcessHeap(), 0, pFormatA );
6291         return TYPE_E_BUFFERTOOSMALL;
6292     }
6293     *pData++ = TOK_END;
6294     realLen = realLen + 1;
6295
6296     /* Finally fill in the length */
6297     hdr->len = realLen;
6298     *pcbActual = realLen;
6299
6300 #if 0
6301     { int i,j;
6302       for (i=0; i<realLen; i=i+0x10) {
6303           printf(" %4.4x : ", i);
6304           for (j=0; j<0x10 && (i+j < realLen); j++) {
6305               printf("%2.2x ", rgbTok[i+j]);
6306           }
6307           printf("\n");
6308       }
6309     }
6310 #endif
6311     HeapFree( GetProcessHeap(), 0, pFormatA );
6312
6313     return S_OK;
6314 }
6315
6316 /**********************************************************************
6317  *              VarFormatFromTokens [OLEAUT32.139]
6318  * FIXME: No account of flags or iFirstDay etc
6319  */
6320 HRESULT WINAPI VarFormatFromTokens(LPVARIANT varIn, LPOLESTR format,
6321                             LPBYTE pbTokCur, ULONG dwFlags, BSTR *pbstrOut,
6322                             LCID  lcid) {
6323
6324     FORMATHDR   *hdr = (FORMATHDR *)pbTokCur;
6325     BYTE        *pData    = pbTokCur + sizeof (FORMATHDR);
6326     LPSTR        pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
6327     char         output[BUFFER_MAX];
6328     char        *pNextPos;
6329     int          size, whichToken;
6330     VARIANTARG   Variant;
6331     struct tm    TM;
6332
6333
6334
6335     TRACE("'%s', %p %lx %p only date support\n", pFormatA, pbTokCur, dwFlags, pbstrOut);
6336     TRACE("varIn:\n");
6337     dump_Variant(varIn);
6338
6339     memset(output, 0x00, BUFFER_MAX);
6340     pNextPos = output;
6341
6342     while (*pData != TOK_END && ((pData - pbTokCur) <= (hdr->len))) {
6343
6344         TRACE("Output looks like : '%s'\n", output);
6345
6346         /* Convert varient to appropriate data type */
6347         whichToken = 0;
6348         while ((formatTokens[whichToken].tokenSize != 0x00) &&
6349                (formatTokens[whichToken].tokenId   != *pData)) {
6350             whichToken++;
6351         }
6352
6353         /* Use Variant local from here downwards as always correct type */
6354         if (formatTokens[whichToken].tokenSize > 0 &&
6355             formatTokens[whichToken].varTypeRequired != 0) {
6356                         VariantInit( &Variant );
6357             if (Coerce( &Variant, lcid, dwFlags, varIn,
6358                         formatTokens[whichToken].varTypeRequired ) != S_OK) {
6359                 HeapFree( GetProcessHeap(), 0, pFormatA );
6360                 return DISP_E_TYPEMISMATCH;
6361             } else if (formatTokens[whichToken].varTypeRequired == VT_DATE) {
6362                 if( DateToTm( V_UNION(&Variant,date), dwFlags, &TM ) == FALSE ) {
6363                     HeapFree( GetProcessHeap(), 0, pFormatA );
6364                     return E_INVALIDARG;
6365                 }
6366             }
6367         }
6368
6369         TRACE("Looking for match on token '%x'\n", *pData);
6370         switch (*pData) {
6371         case TOK_COPY:
6372             TRACE("Copy from %d for %d bytes\n", *(pData+1), *(pData+2));
6373             memcpy(pNextPos, &pFormatA[*(pData+1)], *(pData+2));
6374             pNextPos = pNextPos + *(pData+2);
6375             pData = pData + 3;
6376             break;
6377
6378         case TOK_COLON   :
6379             /* Get locale information - Time Separator */
6380             size = GetLocaleInfoA(lcid, LOCALE_STIME, NULL, 0);
6381             GetLocaleInfoA(lcid, LOCALE_STIME, pNextPos, size);
6382             TRACE("TOK_COLON Time separator is '%s'\n", pNextPos);
6383             pNextPos = pNextPos + size;
6384             pData = pData + 1;
6385             break;
6386
6387         case TOK_SLASH   :
6388             /* Get locale information - Date Separator */
6389             size = GetLocaleInfoA(lcid, LOCALE_SDATE, NULL, 0);
6390             GetLocaleInfoA(lcid, LOCALE_SDATE, pNextPos, size);
6391             TRACE("TOK_COLON Time separator is '%s'\n", pNextPos);
6392             pNextPos = pNextPos + size;
6393             pData = pData + 1;
6394             break;
6395
6396         case TOK_d       :
6397             sprintf(pNextPos, "%d", TM.tm_mday);
6398             pNextPos = pNextPos + strlen(pNextPos);
6399             pData = pData + 1;
6400             break;
6401
6402         case TOK_dd      :
6403             sprintf(pNextPos, "%2.2d", TM.tm_mday);
6404             pNextPos = pNextPos + strlen(pNextPos);
6405             pData = pData + 1;
6406             break;
6407
6408         case TOK_w       :
6409             sprintf(pNextPos, "%d", TM.tm_wday+1);
6410             pNextPos = pNextPos + strlen(pNextPos);
6411             pData = pData + 1;
6412             break;
6413
6414         case TOK_m       :
6415             sprintf(pNextPos, "%d", TM.tm_mon+1);
6416             pNextPos = pNextPos + strlen(pNextPos);
6417             pData = pData + 1;
6418             break;
6419
6420         case TOK_mm      :
6421             sprintf(pNextPos, "%2.2d", TM.tm_mon+1);
6422             pNextPos = pNextPos + strlen(pNextPos);
6423             pData = pData + 1;
6424             break;
6425
6426         case TOK_q       :
6427             sprintf(pNextPos, "%d", ((TM.tm_mon+1)/4)+1);
6428             pNextPos = pNextPos + strlen(pNextPos);
6429             pData = pData + 1;
6430             break;
6431
6432         case TOK_y       :
6433             sprintf(pNextPos, "%2.2d", TM.tm_yday+1);
6434             pNextPos = pNextPos + strlen(pNextPos);
6435             pData = pData + 1;
6436             break;
6437
6438         case TOK_yy      :
6439             sprintf(pNextPos, "%2.2d", TM.tm_year);
6440             pNextPos = pNextPos + strlen(pNextPos);
6441             pData = pData + 1;
6442             break;
6443
6444         case TOK_yyyy    :
6445             sprintf(pNextPos, "%4.4d", TM.tm_year);
6446             pNextPos = pNextPos + strlen(pNextPos);
6447             pData = pData + 1;
6448             break;
6449
6450         case TOK_h       :
6451             sprintf(pNextPos, "%d", TM.tm_hour);
6452             pNextPos = pNextPos + strlen(pNextPos);
6453             pData = pData + 1;
6454             break;
6455
6456         case TOK_Hh      :
6457             sprintf(pNextPos, "%2.2d", TM.tm_hour);
6458             pNextPos = pNextPos + strlen(pNextPos);
6459             pData = pData + 1;
6460             break;
6461
6462         case TOK_N       :
6463             sprintf(pNextPos, "%d", TM.tm_min);
6464             pNextPos = pNextPos + strlen(pNextPos);
6465             pData = pData + 1;
6466             break;
6467
6468         case TOK_Nn      :
6469             sprintf(pNextPos, "%2.2d", TM.tm_min);
6470             pNextPos = pNextPos + strlen(pNextPos);
6471             pData = pData + 1;
6472             break;
6473
6474         case TOK_S       :
6475             sprintf(pNextPos, "%d", TM.tm_sec);
6476             pNextPos = pNextPos + strlen(pNextPos);
6477             pData = pData + 1;
6478             break;
6479
6480         case TOK_Ss      :
6481             sprintf(pNextPos, "%2.2d", TM.tm_sec);
6482             pNextPos = pNextPos + strlen(pNextPos);
6483             pData = pData + 1;
6484             break;
6485
6486         /* FIXME: To Do! */
6487         case TOK_ttttt   :
6488         case TOK_AMsPM   :
6489         case TOK_amspm   :
6490         case TOK_AsP     :
6491         case TOK_asp     :
6492         case TOK_AMPM    :
6493         case TOK_c       :
6494         case TOK_ddd     :
6495         case TOK_dddd    :
6496         case TOK_ddddd   :
6497         case TOK_dddddd  :
6498         case TOK_ww      :
6499         case TOK_mmm     :
6500         case TOK_mmmm    :
6501         default:
6502             FIXME("Unhandled token for VarFormat %d\n", *pData);
6503             HeapFree( GetProcessHeap(), 0, pFormatA );
6504             return E_INVALIDARG;
6505         }
6506
6507     }
6508
6509     *pbstrOut = StringDupAtoBstr( output );
6510     HeapFree( GetProcessHeap(), 0, pFormatA );
6511     return S_OK;
6512 }
6513
6514 /**********************************************************************
6515  *              VarFormat [OLEAUT32.87]
6516  *
6517  */
6518 HRESULT WINAPI VarFormat(LPVARIANT varIn, LPOLESTR format,
6519                          int firstDay, int firstWeek, ULONG dwFlags,
6520                          BSTR *pbstrOut) {
6521
6522     LPSTR   pNewString = NULL;
6523     HRESULT rc = S_OK;
6524
6525     TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
6526           debugstr_w(format), firstDay, firstWeek, dwFlags);
6527     TRACE("varIn:\n");
6528     dump_Variant(varIn);
6529
6530     /* Note: Must Handle references type Variants (contain ptrs
6531           to values rather than values */
6532
6533     /* Get format string */
6534     pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
6535
6536     /* FIXME: Handle some simple pre-definted format strings : */
6537     if (((V_VT(varIn)&VT_TYPEMASK) == VT_CY) && (lstrcmpiA(pNewString, "Currency") == 0)) {
6538
6539         /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
6540         double curVal;
6541
6542
6543         /* Handle references type Variants (contain ptrs to values rather than values */
6544         if (V_VT(varIn)&VT_BYREF) {
6545             rc = VarR8FromCy(*(CY *)V_UNION(varIn,byref), &curVal);
6546         } else {
6547             rc = VarR8FromCy(V_UNION(varIn,cyVal), &curVal);
6548         }
6549
6550         if (rc == S_OK) {
6551             char tmpStr[BUFFER_MAX];
6552             sprintf(tmpStr, "%f", curVal);
6553             if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags, tmpStr, NULL, pBuffer, BUFFER_MAX) == 0) {
6554                 return E_FAIL;
6555             } else {
6556                 *pbstrOut = StringDupAtoBstr( pBuffer );
6557             }
6558         }
6559
6560     } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_DATE) {
6561
6562         /* Attempt to do proper formatting! */
6563         int firstToken = -1;
6564
6565         rc = VarTokenizeFormatString(format, pBuffer, sizeof(pBuffer), firstDay,
6566                                   firstWeek, GetUserDefaultLCID(), &firstToken);
6567         if (rc==S_OK) {
6568             rc = VarFormatFromTokens(varIn, format, pBuffer, dwFlags, pbstrOut, GetUserDefaultLCID());
6569         }
6570
6571     } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_R8) {
6572         if (V_VT(varIn)&VT_BYREF) {
6573             sprintf(pBuffer, "%f", *V_UNION(varIn,pdblVal));
6574         } else {
6575             sprintf(pBuffer, "%f", V_UNION(varIn,dblVal));
6576         }
6577         *pbstrOut = StringDupAtoBstr( pBuffer );
6578     } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_I2) {
6579         if (V_VT(varIn)&VT_BYREF) {
6580             sprintf(pBuffer, "%d", *V_UNION(varIn,piVal));
6581         } else {
6582             sprintf(pBuffer, "%d", V_UNION(varIn,iVal));
6583         }
6584         *pbstrOut = StringDupAtoBstr( pBuffer );
6585     } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_BSTR) {
6586         if (V_VT(varIn)&VT_BYREF)
6587             *pbstrOut = SysAllocString( *V_UNION(varIn,pbstrVal) );
6588         else
6589             *pbstrOut = SysAllocString( V_UNION(varIn,bstrVal) );
6590     } else {
6591         FIXME("VarFormat: Unsupported format %d!\n", V_VT(varIn)&VT_TYPEMASK);
6592         *pbstrOut = StringDupAtoBstr( "??" );
6593     }
6594
6595     /* Free allocated storage */
6596     HeapFree( GetProcessHeap(), 0, pNewString );
6597     TRACE("result: '%s'\n", debugstr_w(*pbstrOut));
6598     return rc;
6599 }
6600
6601 /**********************************************************************
6602  *              VarCyMulI4 [OLEAUT32.304]
6603  * Multiply currency value by integer
6604  */
6605 HRESULT WINAPI VarCyMulI4(CY cyIn, LONG mulBy, CY *pcyOut) {
6606
6607     double cyVal = 0;
6608     HRESULT rc = S_OK;
6609
6610     rc = VarR8FromCy(cyIn, &cyVal);
6611     if (rc == S_OK) {
6612         rc = VarCyFromR8((cyVal * (double) mulBy), pcyOut);
6613         TRACE("Multiply %f by %ld = %f [%ld,%lu]\n", cyVal, mulBy, (cyVal * (double) mulBy),
6614                     pcyOut->s.Hi, pcyOut->s.Lo);
6615     }
6616     return rc;
6617 }
6618
6619 /**********************************************************************
6620  *              VarMod [OLEAUT32.154]
6621  *
6622  */
6623 HRESULT WINAPI VarMod(LPVARIANT left, LPVARIANT right, LPVARIANT result)
6624 {
6625     FIXME("%p %p %p\n", left, right, result);
6626     return E_FAIL;
6627 }