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