Support images on the tabs of pages that are added (not just the
[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 #include "windef.h"
50 #include "oleauto.h"
51 #include "heap.h"
52 #include "wine/debug.h"
53 #include "winerror.h"
54 #include "parsedt.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(ole);
57
58 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
59
60 #ifndef FLT_MAX
61 # ifdef MAXFLOAT
62 #  define FLT_MAX MAXFLOAT
63 # else
64 #  error "Can't find #define for MAXFLOAT/FLT_MAX"
65 # endif
66 #endif
67
68 #undef CHAR_MAX
69 #undef CHAR_MIN
70 static const char CHAR_MAX = 127;
71 static const char CHAR_MIN = -128;
72 static const BYTE UI1_MAX = 255;
73 static const BYTE UI1_MIN = 0;
74 static const unsigned short UI2_MAX = 65535;
75 static const unsigned short UI2_MIN = 0;
76 static const short I2_MAX = 32767;
77 static const short I2_MIN =  -32768;
78 static const unsigned long UI4_MAX = 4294967295U;
79 static const unsigned long UI4_MIN = 0;
80 static const long I4_MAX = 2147483647;
81 static const long I4_MIN = -(2147483648U);
82 static const DATE DATE_MIN = -657434;
83 static const DATE DATE_MAX = 2958465;
84
85
86 /* This mask is used to set a flag in wReserved1 of
87  * the VARIANTARG structure. The flag indicates if
88  * the API function is using an inner variant or not.
89  */
90 #define PROCESSING_INNER_VARIANT 0x0001
91
92 /* General use buffer.
93  */
94 #define BUFFER_MAX 1024
95 static char pBuffer[BUFFER_MAX];
96
97 /*
98  * Note a leap year is one that is a multiple of 4
99  * but not of a 100.  Except if it is a multiple of
100  * 400 then it is a leap year.
101  */
102 /* According to postgreSQL date parsing functions there is
103  * a leap year when this expression is true.
104  * (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
105  * So according to this there is 365.2515 days in one year.
106  * One + every four years: 1/4 -> 365.25
107  * One - every 100 years: 1/100 -> 365.01
108  * One + every 400 years: 1/400 -> 365.0025
109  */
110 /* static const double DAYS_IN_ONE_YEAR = 365.2515;
111  *
112  *  ^^  Might this be the key to an easy way to factor large prime numbers?
113  *  Let's try using arithmetic.  <lawson_whitney@juno.com> 7 Mar 2000
114  */
115 static const double DAYS_IN_ONE_YEAR = 365.2425;
116
117
118 /******************************************************************************
119  *         DateTimeStringToTm   [INTERNAL]
120  *
121  * Converts a string representation of a date and/or time to a tm structure.
122  *
123  * Note this function uses the postgresql date parsing functions found
124  * in the parsedt.c file.
125  *
126  * Returns TRUE if successful.
127  *
128  * Note: This function does not parse the day of the week,
129  * daylight savings time. It will only fill the followin fields in
130  * the tm struct, tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
131  *
132  ******************************************************************************/
133 static BOOL DateTimeStringToTm( OLECHAR* strIn, DWORD dwFlags, struct tm* pTm )
134 {
135         BOOL res = FALSE;
136         double          fsec;
137         int             tzp;
138         int             dtype;
139         int             nf;
140         char       *field[MAXDATEFIELDS];
141         int             ftype[MAXDATEFIELDS];
142         char            lowstr[MAXDATELEN + 1];
143         char* strDateTime = NULL;
144
145         /* Convert the string to ASCII since this is the only format
146          * postgesql can handle.
147          */
148         strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
149
150         if( strDateTime != NULL )
151         {
152                 /* Make sure we don't go over the maximum length
153                  * accepted by postgesql.
154                  */
155                 if( strlen( strDateTime ) <= MAXDATELEN )
156                 {
157                         if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
158                         {
159                                 if( dwFlags & VAR_DATEVALUEONLY )
160                                 {
161                                         /* Get the date information.
162                                          * It returns 0 if date information was
163                                          * present and 1 if only time information was present.
164                                          * -1 if an error occures.
165                                          */
166                                         if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
167                                         {
168                                                 /* Eliminate the time information since we
169                                                  * were asked to get date information only.
170                                                  */
171                                                 pTm->tm_sec = 0;
172                                                 pTm->tm_min = 0;
173                                                 pTm->tm_hour = 0;
174                                                 res = TRUE;
175                                         }
176                                 }
177                                 if( dwFlags & VAR_TIMEVALUEONLY )
178                                 {
179                                         /* Get time information only.
180                                          */
181                                         if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
182                                         {
183                                                 res = TRUE;
184                                         }
185                                 }
186                                 else
187                                 {
188                                         /* Get both date and time information.
189                                          * It returns 0 if date information was
190                                          * present and 1 if only time information was present.
191                                          * -1 if an error occures.
192                                          */
193                                         if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
194                                         {
195                                                 res = TRUE;
196                                         }
197                                 }
198                         }
199                 }
200                 HeapFree( GetProcessHeap(), 0, strDateTime );
201         }
202
203         return res;
204 }
205
206
207
208
209
210
211 /******************************************************************************
212  *         TmToDATE     [INTERNAL]
213  *
214  * The date is implemented using an 8 byte floating-point number.
215  * Days are represented by whole numbers increments starting with 0.00 has
216  * being December 30 1899, midnight.
217  * The hours are expressed as the fractional part of the number.
218  * December 30 1899 at midnight = 0.00
219  * January 1 1900 at midnight = 2.00
220  * January 4 1900 at 6 AM = 5.25
221  * January 4 1900 at noon = 5.50
222  * December 29 1899 at midnight = -1.00
223  * December 18 1899 at midnight = -12.00
224  * December 18 1899 at 6AM = -12.25
225  * December 18 1899 at 6PM = -12.75
226  * December 19 1899 at midnight = -11.00
227  * The tm structure is as follows:
228  * struct tm {
229  *                int tm_sec;      seconds after the minute - [0,59]
230  *                int tm_min;      minutes after the hour - [0,59]
231  *                int tm_hour;     hours since midnight - [0,23]
232  *                int tm_mday;     day of the month - [1,31]
233  *                int tm_mon;      months since January - [0,11]
234  *                int tm_year;     years
235  *                int tm_wday;     days since Sunday - [0,6]
236  *                int tm_yday;     days since January 1 - [0,365]
237  *                int tm_isdst;    daylight savings time flag
238  *                };
239  *
240  * Note: This function does not use the tm_wday, tm_yday, tm_wday,
241  * and tm_isdst fields of the tm structure. And only converts years
242  * after 1900.
243  *
244  * Returns TRUE if successful.
245  */
246 static BOOL TmToDATE( struct tm* pTm, DATE *pDateOut )
247 {
248     int leapYear = 0;
249
250     if( (pTm->tm_year - 1900) < 0 ) return FALSE;
251
252     /* Start at 1. This is the way DATE is defined.
253      * January 1, 1900 at Midnight is 1.00.
254      * January 1, 1900 at 6AM is 1.25.
255      * and so on.
256      */
257     *pDateOut = 1;
258
259     /* Add the number of days corresponding to
260      * tm_year.
261      */
262     *pDateOut += (pTm->tm_year - 1900) * 365;
263
264     /* Add the leap days in the previous years between now and 1900.
265      * Note a leap year is one that is a multiple of 4
266      * but not of a 100.  Except if it is a multiple of
267      * 400 then it is a leap year.
268      */
269     *pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
270     *pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
271     *pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
272
273     /* Set the leap year flag if the
274      * current year specified by tm_year is a
275      * leap year. This will be used to add a day
276      * to the day count.
277      */
278     if( isleap( pTm->tm_year ) )
279         leapYear = 1;
280
281     /* Add the number of days corresponding to
282      * the month.
283      */
284     switch( pTm->tm_mon )
285     {
286     case 2:
287         *pDateOut += 31;
288         break;
289     case 3:
290         *pDateOut += ( 59 + leapYear );
291         break;
292     case 4:
293         *pDateOut += ( 90 + leapYear );
294         break;
295     case 5:
296         *pDateOut += ( 120 + leapYear );
297         break;
298     case 6:
299         *pDateOut += ( 151 + leapYear );
300         break;
301     case 7:
302         *pDateOut += ( 181 + leapYear );
303         break;
304     case 8:
305         *pDateOut += ( 212 + leapYear );
306         break;
307     case 9:
308         *pDateOut += ( 243 + leapYear );
309         break;
310     case 10:
311         *pDateOut += ( 273 + leapYear );
312         break;
313     case 11:
314         *pDateOut += ( 304 + leapYear );
315         break;
316     case 12:
317         *pDateOut += ( 334 + leapYear );
318         break;
319     }
320     /* Add the number of days in this month.
321      */
322     *pDateOut += pTm->tm_mday;
323
324     /* Add the number of seconds, minutes, and hours
325      * to the DATE. Note these are the fracionnal part
326      * of the DATE so seconds / number of seconds in a day.
327      */
328     *pDateOut += pTm->tm_hour / 24.0;
329     *pDateOut += pTm->tm_min / 1440.0;
330     *pDateOut += pTm->tm_sec / 86400.0;
331     return TRUE;
332 }
333
334 /******************************************************************************
335  *         DateToTm     [INTERNAL]
336  *
337  * This function converts a windows DATE to a tm structure.
338  *
339  * It does not fill all the fields of the tm structure.
340  * Here is a list of the fields that are filled:
341  * tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
342  *
343  * Note this function does not support dates before the January 1, 1900
344  * or ( dateIn < 2.0 ).
345  *
346  * Returns TRUE if successful.
347  */
348 static BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )
349 {
350     double decimalPart = 0.0;
351     double wholePart = 0.0;
352
353     /* Do not process dates smaller than January 1, 1900.
354      * Which corresponds to 2.0 in the windows DATE format.
355      */
356     if( dateIn < 2.0 ) return FALSE;
357
358     memset(pTm,0,sizeof(*pTm));
359
360     /* Because of the nature of DATE format which
361      * associates 2.0 to January 1, 1900. We will
362      * remove 1.0 from the whole part of the DATE
363      * so that in the following code 1.0
364      * will correspond to January 1, 1900.
365      * This simplifies the processing of the DATE value.
366      */
367     dateIn -= 1.0;
368
369     wholePart = (double) floor( dateIn );
370     decimalPart = fmod( dateIn, wholePart );
371
372     if( !(dwFlags & VAR_TIMEVALUEONLY) )
373     {
374         int nDay = 0;
375         int leapYear = 0;
376         double yearsSince1900 = 0;
377         /* Start at 1900, this is where the DATE time 0.0 starts.
378          */
379         pTm->tm_year = 1900;
380         /* find in what year the day in the "wholePart" falls into.
381          * add the value to the year field.
382          */
383         yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 );
384         pTm->tm_year += yearsSince1900;
385         /* determine if this is a leap year.
386          */
387         if( isleap( pTm->tm_year ) )
388         {
389             leapYear = 1;
390             wholePart++;
391         }
392
393         /* find what day of that year the "wholePart" corresponds to.
394          * Note: nDay is in [1-366] format
395          */
396         nDay = (int) ( wholePart - floor( yearsSince1900 * DAYS_IN_ONE_YEAR ) );
397         /* Set the tm_yday value.
398          * Note: The day must be converted from [1-366] to [0-365]
399          */
400         /*pTm->tm_yday = nDay - 1;*/
401         /* find which month this day corresponds to.
402          */
403         if( nDay <= 31 )
404         {
405             pTm->tm_mday = nDay;
406             pTm->tm_mon = 0;
407         }
408         else if( nDay <= ( 59 + leapYear ) )
409         {
410             pTm->tm_mday = nDay - 31;
411             pTm->tm_mon = 1;
412         }
413         else if( nDay <= ( 90 + leapYear ) )
414         {
415             pTm->tm_mday = nDay - ( 59 + leapYear );
416             pTm->tm_mon = 2;
417         }
418         else if( nDay <= ( 120 + leapYear ) )
419         {
420             pTm->tm_mday = nDay - ( 90 + leapYear );
421             pTm->tm_mon = 3;
422         }
423         else if( nDay <= ( 151 + leapYear ) )
424         {
425             pTm->tm_mday = nDay - ( 120 + leapYear );
426             pTm->tm_mon = 4;
427         }
428         else if( nDay <= ( 181 + leapYear ) )
429         {
430             pTm->tm_mday = nDay - ( 151 + leapYear );
431             pTm->tm_mon = 5;
432         }
433         else if( nDay <= ( 212 + leapYear ) )
434         {
435             pTm->tm_mday = nDay - ( 181 + leapYear );
436             pTm->tm_mon = 6;
437         }
438         else if( nDay <= ( 243 + leapYear ) )
439         {
440             pTm->tm_mday = nDay - ( 212 + leapYear );
441             pTm->tm_mon = 7;
442         }
443         else if( nDay <= ( 273 + leapYear ) )
444         {
445             pTm->tm_mday = nDay - ( 243 + leapYear );
446             pTm->tm_mon = 8;
447         }
448         else if( nDay <= ( 304 + leapYear ) )
449         {
450             pTm->tm_mday = nDay - ( 273 + leapYear );
451             pTm->tm_mon = 9;
452         }
453         else if( nDay <= ( 334 + leapYear ) )
454         {
455             pTm->tm_mday = nDay - ( 304 + leapYear );
456             pTm->tm_mon = 10;
457         }
458         else if( nDay <= ( 365 + leapYear ) )
459         {
460             pTm->tm_mday = nDay - ( 334 + leapYear );
461             pTm->tm_mon = 11;
462         }
463     }
464     if( !(dwFlags & VAR_DATEVALUEONLY) )
465     {
466         /* find the number of seconds in this day.
467          * fractional part times, hours, minutes, seconds.
468          */
469         pTm->tm_hour = (int) ( decimalPart * 24 );
470         pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
471         pTm->tm_sec = (int) ( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 );
472     }
473     return TRUE;
474 }
475
476
477
478 /******************************************************************************
479  *         SizeOfVariantData    [INTERNAL]
480  *
481  * This function finds the size of the data referenced by a Variant based
482  * the type "vt" of the Variant.
483  */
484 static int SizeOfVariantData( VARIANT* parg )
485 {
486     int size = 0;
487     switch( V_VT(parg) & VT_TYPEMASK )
488     {
489     case( VT_I2 ):
490         size = sizeof(short);
491         break;
492     case( VT_INT ):
493         size = sizeof(int);
494         break;
495     case( VT_I4 ):
496         size = sizeof(long);
497         break;
498     case( VT_UI1 ):
499         size = sizeof(BYTE);
500         break;
501     case( VT_UI2 ):
502         size = sizeof(unsigned short);
503         break;
504     case( VT_UINT ):
505         size = sizeof(unsigned int);
506         break;
507     case( VT_UI4 ):
508         size = sizeof(unsigned long);
509         break;
510     case( VT_R4 ):
511         size = sizeof(float);
512         break;
513     case( VT_R8 ):
514         size = sizeof(double);
515         break;
516     case( VT_DATE ):
517         size = sizeof(DATE);
518         break;
519     case( VT_BOOL ):
520         size = sizeof(VARIANT_BOOL);
521         break;
522     case( VT_BSTR ):
523         size = sizeof(void*);
524         break;
525     case( VT_CY ):
526     case( VT_DISPATCH ):
527     case( VT_UNKNOWN ):
528     case( VT_DECIMAL ):
529     default:
530         FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK );
531         break;
532     }
533
534     return size;
535 }
536 /******************************************************************************
537  *         StringDupAtoBstr             [INTERNAL]
538  *
539  */
540 static BSTR StringDupAtoBstr( char* strIn )
541 {
542         BSTR bstr = NULL;
543         OLECHAR* pNewString = NULL;
544         pNewString = HEAP_strdupAtoW( GetProcessHeap(), 0, strIn );
545         bstr = SysAllocString( pNewString );
546         HeapFree( GetProcessHeap(), 0, pNewString );
547         return bstr;
548 }
549
550 /******************************************************************************
551  *              round           [INTERNAL]
552  *
553  * Round the double value to the nearest integer value.
554  */
555 static double round( double d )
556 {
557    double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
558     BOOL bEvenNumber = FALSE;
559     int nSign = 0;
560
561     /* Save the sign of the number
562      */
563    nSign = (d >= 0.0) ? 1 : -1;
564     d = fabs( d );
565
566         /* Remove the decimals.
567          */
568    integerValue = floor( d );
569
570     /* Set the Even flag.  This is used to round the number when
571      * the decimals are exactly 1/2.  If the integer part is
572      * odd the number is rounded up. If the integer part
573      * is even the number is rounded down.  Using this method
574      * numbers are rounded up|down half the time.
575      */
576    bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
577
578     /* Remove the integral part of the number.
579      */
580     decimals = d - integerValue;
581
582         /* Note: Ceil returns the smallest integer that is greater that x.
583          * and floor returns the largest integer that is less than or equal to x.
584          */
585     if( decimals > 0.5 )
586     {
587         /* If the decimal part is greater than 1/2
588          */
589         roundedValue = ceil( d );
590     }
591     else if( decimals < 0.5 )
592     {
593         /* If the decimal part is smaller than 1/2
594          */
595         roundedValue = floor( d );
596     }
597     else
598     {
599         /* the decimals are exactly 1/2 so round according to
600          * the bEvenNumber flag.
601          */
602         if( bEvenNumber )
603         {
604             roundedValue = floor( d );
605         }
606         else
607         {
608             roundedValue = ceil( d );
609         }
610     }
611
612         return roundedValue * nSign;
613 }
614
615 /******************************************************************************
616  *              RemoveCharacterFromString               [INTERNAL]
617  *
618  * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
619  */
620 static void RemoveCharacterFromString( LPSTR str, LPSTR strOfCharToRemove )
621 {
622         LPSTR pNewString = NULL;
623         LPSTR strToken = NULL;
624
625         /* Check if we have a valid argument
626          */
627         if( str != NULL )
628         {
629                 pNewString = strdup( str );
630                 str[0] = '\0';
631                 strToken = strtok( pNewString, strOfCharToRemove );
632                 while( strToken != NULL ) {
633                         strcat( str, strToken );
634                         strToken = strtok( NULL, strOfCharToRemove );
635                 }
636                 free( pNewString );
637         }
638         return;
639 }
640
641 /******************************************************************************
642  *              GetValidRealString              [INTERNAL]
643  *
644  * Checks if the string is of proper format to be converted to a real value.
645  */
646 static BOOL IsValidRealString( LPSTR strRealString )
647 {
648         /* Real values that have a decimal point are required to either have
649          * digits before or after the decimal point.  We will assume that
650          * we do not have any digits at either position. If we do encounter
651          * some we will disable this flag.
652          */
653         BOOL bDigitsRequired = TRUE;
654         /* Processed fields in the string representation of the real number.
655          */
656         BOOL bWhiteSpaceProcessed = FALSE;
657         BOOL bFirstSignProcessed = FALSE;
658         BOOL bFirstDigitsProcessed = FALSE;
659         BOOL bDecimalPointProcessed = FALSE;
660         BOOL bSecondDigitsProcessed = FALSE;
661         BOOL bExponentProcessed = FALSE;
662         BOOL bSecondSignProcessed = FALSE;
663         BOOL bThirdDigitsProcessed = FALSE;
664         /* Assume string parameter "strRealString" is valid and try to disprove it.
665          */
666         BOOL bValidRealString = TRUE;
667
668         /* Used to count the number of tokens in the "strRealString".
669          */
670         LPSTR strToken = NULL;
671         int nTokens = 0;
672         LPSTR pChar = NULL;
673
674         /* Check if we have a valid argument
675          */
676         if( strRealString == NULL )
677         {
678                 bValidRealString = FALSE;
679         }
680
681         if( bValidRealString == TRUE )
682         {
683                 /* Make sure we only have ONE token in the string.
684                  */
685                 strToken = strtok( strRealString, " " );
686                 while( strToken != NULL ) {
687                         nTokens++;
688                         strToken = strtok( NULL, " " );
689                 }
690
691                 if( nTokens != 1 )
692                 {
693                         bValidRealString = FALSE;
694                 }
695         }
696
697
698         /* Make sure this token contains only valid characters.
699          * The string argument to atof has the following form:
700          * [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
701          * Whitespace consists of space and|or <TAB> characters, which are ignored.
702      * Sign is either plus '+' or minus '-'.
703      * Digits are one or more decimal digits.
704      * Note: If no digits appear before the decimal point, at least one must
705      * appear after the decimal point.
706      * The decimal digits may be followed by an exponent.
707      * An Exponent consists of an introductory letter ( D, d, E, or e) and
708          * an optionally signed decimal integer.
709          */
710         pChar = strRealString;
711         while( bValidRealString == TRUE && *pChar != '\0' )
712         {
713                 switch( *pChar )
714                 {
715                 /* If whitespace...
716                  */
717                 case ' ':
718                 case '\t':
719                         if( bWhiteSpaceProcessed ||
720                                 bFirstSignProcessed ||
721                                 bFirstDigitsProcessed ||
722                                 bDecimalPointProcessed ||
723                                 bSecondDigitsProcessed ||
724                                 bExponentProcessed ||
725                                 bSecondSignProcessed ||
726                                 bThirdDigitsProcessed )
727                         {
728                                 bValidRealString = FALSE;
729                         }
730                         break;
731                 /* If sign...
732                  */
733                 case '+':
734                 case '-':
735                         if( bFirstSignProcessed == FALSE )
736                         {
737                                 if( bFirstDigitsProcessed ||
738                                         bDecimalPointProcessed ||
739                                         bSecondDigitsProcessed ||
740                                         bExponentProcessed ||
741                                         bSecondSignProcessed ||
742                                         bThirdDigitsProcessed )
743                                 {
744                                         bValidRealString = FALSE;
745                                 }
746                                 bWhiteSpaceProcessed = TRUE;
747                                 bFirstSignProcessed = TRUE;
748                         }
749                         else if( bSecondSignProcessed == FALSE )
750                         {
751                 /* Note: The exponent must be present in
752                                  * order to accept the second sign...
753                                  */
754                                 if( bExponentProcessed == FALSE ||
755                                         bThirdDigitsProcessed ||
756                                         bDigitsRequired )
757                                 {
758                                         bValidRealString = FALSE;
759                                 }
760                                 bFirstSignProcessed = TRUE;
761                                 bWhiteSpaceProcessed = TRUE;
762                                 bFirstDigitsProcessed = TRUE;
763                                 bDecimalPointProcessed = TRUE;
764                                 bSecondDigitsProcessed = TRUE;
765                                 bSecondSignProcessed = TRUE;
766                         }
767                         break;
768
769                 /* If decimals...
770                  */
771                 case '0':
772                 case '1':
773                 case '2':
774                 case '3':
775                 case '4':
776                 case '5':
777                 case '6':
778                 case '7':
779                 case '8':
780                 case '9':
781                         if( bFirstDigitsProcessed == FALSE )
782                         {
783                                 if( bDecimalPointProcessed ||
784                                         bSecondDigitsProcessed ||
785                                         bExponentProcessed ||
786                                         bSecondSignProcessed ||
787                                         bThirdDigitsProcessed )
788                                 {
789                                         bValidRealString = FALSE;
790                                 }
791                                 bFirstSignProcessed = TRUE;
792                                 bWhiteSpaceProcessed = TRUE;
793                                 /* We have found some digits before the decimal point
794                                  * so disable the "Digits required" flag.
795                                  */
796                                 bDigitsRequired = FALSE;
797                         }
798                         else if( bSecondDigitsProcessed == FALSE )
799                         {
800                                 if( bExponentProcessed ||
801                                         bSecondSignProcessed ||
802                                         bThirdDigitsProcessed )
803                                 {
804                                         bValidRealString = FALSE;
805                                 }
806                                 bFirstSignProcessed = TRUE;
807                                 bWhiteSpaceProcessed = TRUE;
808                                 bFirstDigitsProcessed = TRUE;
809                                 bDecimalPointProcessed = TRUE;
810                                 /* We have found some digits after the decimal point
811                                  * so disable the "Digits required" flag.
812                                  */
813                                 bDigitsRequired = FALSE;
814                         }
815                         else if( bThirdDigitsProcessed == FALSE )
816                         {
817                                 /* Getting here means everything else should be processed.
818                  * If we get anything else than a decimal following this
819                  * digit it will be flagged by the other cases, so
820                                  * we do not really need to do anything in here.
821                                  */
822                         }
823                         break;
824                 /* If DecimalPoint...
825                  */
826                 case '.':
827                         if( bDecimalPointProcessed ||
828                                 bSecondDigitsProcessed ||
829                                 bExponentProcessed ||
830                                 bSecondSignProcessed ||
831                                 bThirdDigitsProcessed )
832                         {
833                                 bValidRealString = FALSE;
834                         }
835                         bFirstSignProcessed = TRUE;
836                         bWhiteSpaceProcessed = TRUE;
837                         bFirstDigitsProcessed = TRUE;
838                         bDecimalPointProcessed = TRUE;
839                         break;
840                 /* If Exponent...
841                  */
842                 case 'e':
843                 case 'E':
844                 case 'd':
845                 case 'D':
846                         if( bExponentProcessed ||
847                                 bSecondSignProcessed ||
848                                 bThirdDigitsProcessed ||
849                                 bDigitsRequired )
850                         {
851                                 bValidRealString = FALSE;
852                         }
853                         bFirstSignProcessed = TRUE;
854                         bWhiteSpaceProcessed = TRUE;
855                         bFirstDigitsProcessed = TRUE;
856                         bDecimalPointProcessed = TRUE;
857                         bSecondDigitsProcessed = TRUE;
858                         bExponentProcessed = TRUE;
859                         break;
860                 default:
861                         bValidRealString = FALSE;
862                         break;
863                 }
864                 /* Process next character.
865                  */
866                 pChar++;
867         }
868
869         /* If the required digits were not present we have an invalid
870          * string representation of a real number.
871          */
872         if( bDigitsRequired == TRUE )
873         {
874                 bValidRealString = FALSE;
875         }
876
877         return bValidRealString;
878 }
879
880
881 /******************************************************************************
882  *              Coerce  [INTERNAL]
883  *
884  * This function dispatches execution to the proper conversion API
885  * to do the necessary coercion.
886  *
887  * FIXME: Passing down dwFlags to the conversion functions is wrong, this
888  *        is a different flagmask. Check MSDN.
889  */
890 static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
891 {
892         HRESULT res = S_OK;
893         unsigned short vtFrom = 0;
894         vtFrom = V_VT(ps) & VT_TYPEMASK;
895
896
897         /* Note: Since "long" and "int" values both have 4 bytes and are
898          * both signed integers "int" will be treated as "long" in the
899          * following code.
900          * The same goes for their unsigned versions.
901          */
902
903         /* Trivial Case: If the coercion is from two types that are
904          * identical then we can blindly copy from one argument to another.*/
905         if ((vt==vtFrom))
906         {
907            return VariantCopy(pd,ps);
908         }
909
910         /* Cases requiring thought*/
911         switch( vt )
912         {
913
914     case( VT_EMPTY ):
915         res = VariantClear( pd );
916         break;
917     case( VT_NULL ):
918         res = VariantClear( pd );
919         if( res == S_OK )
920         {
921             V_VT(pd) = VT_NULL;
922         }
923         break;
924         case( VT_I1 ):
925                 switch( vtFrom )
926         {
927         case( VT_I1 ):
928             res = VariantCopy( pd, ps );
929             break;
930                 case( VT_I2 ):
931                         res = VarI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,cVal) );
932                         break;
933                 case( VT_INT ):
934                 case( VT_I4 ):
935                         res = VarI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,cVal) );
936                         break;
937                 case( VT_UI1 ):
938                         res = VarI1FromUI1( V_UNION(ps,bVal), &V_UNION(pd,cVal) );
939                         break;
940                 case( VT_UI2 ):
941                         res = VarI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cVal) );
942                         break;
943                 case( VT_UINT ):
944                 case( VT_UI4 ):
945                         res = VarI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cVal) );
946                         break;
947                 case( VT_R4 ):
948                         res = VarI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,cVal) );
949                         break;
950                 case( VT_R8 ):
951                         res = VarI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,cVal) );
952                         break;
953                 case( VT_DATE ):
954                         res = VarI1FromDate( V_UNION(ps,date), &V_UNION(pd,cVal) );
955                         break;
956                 case( VT_BOOL ):
957                         res = VarI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,cVal) );
958                         break;
959                 case( VT_BSTR ):
960                         res = VarI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cVal) );
961                         break;
962                 case( VT_CY ):
963                         res = VarI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,cVal) );
964                         break;
965                 case( VT_DISPATCH ):
966                         /*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
967                 case( VT_DECIMAL ):
968                         /*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
969                 case( VT_UNKNOWN ):
970                 default:
971                         res = DISP_E_TYPEMISMATCH;
972                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
973                         break;
974                 }
975                 break;
976
977         case( VT_I2 ):
978                 switch( vtFrom )
979                 {
980                 case( VT_I1 ):
981                         res = VarI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,iVal) );
982                         break;
983         case( VT_I2 ):
984             res = VariantCopy( pd, ps );
985             break;
986                 case( VT_INT ):
987                 case( VT_I4 ):
988                         res = VarI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,iVal) );
989                         break;
990                 case( VT_UI1 ):
991                         res = VarI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,iVal) );
992                         break;
993                 case( VT_UI2 ):
994                         res = VarI2FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,iVal) );
995                         break;
996                 case( VT_UINT ):
997                 case( VT_UI4 ):
998                         res = VarI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,iVal) );
999                         break;
1000                 case( VT_R4 ):
1001                         res = VarI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,iVal) );
1002                         break;
1003                 case( VT_R8 ):
1004                         res = VarI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,iVal) );
1005                         break;
1006                 case( VT_DATE ):
1007                         res = VarI2FromDate( V_UNION(ps,date), &V_UNION(pd,iVal) );
1008                         break;
1009                 case( VT_BOOL ):
1010                         res = VarI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,iVal) );
1011                         break;
1012                 case( VT_BSTR ):
1013                         res = VarI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,iVal) );
1014                         break;
1015                 case( VT_CY ):
1016                         res = VarI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,iVal) );
1017                         break;
1018                 case( VT_DISPATCH ):
1019                         /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
1020                 case( VT_DECIMAL ):
1021                         /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
1022                 case( VT_UNKNOWN ):
1023                 default:
1024                         res = DISP_E_TYPEMISMATCH;
1025                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1026                         break;
1027                 }
1028                 break;
1029
1030         case( VT_INT ):
1031         case( VT_I4 ):
1032                 switch( vtFrom )
1033                 {
1034                 case( VT_EMPTY ):
1035                         V_UNION(pd,lVal) = 0;
1036                         res = S_OK;
1037                         break;
1038                 case( VT_I1 ):
1039                         res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
1040                         break;
1041                 case( VT_I2 ):
1042                         res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
1043             break;
1044         case( VT_INT ):
1045         case( VT_I4 ):
1046             res = VariantCopy( pd, ps );
1047             break;
1048                 case( VT_UI1 ):
1049                         res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
1050                         break;
1051                 case( VT_UI2 ):
1052                         res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
1053                         break;
1054                 case( VT_UINT ):
1055                 case( VT_UI4 ):
1056                         res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
1057                         break;
1058                 case( VT_R4 ):
1059                         res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
1060                         break;
1061                 case( VT_R8 ):
1062                         res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
1063                         break;
1064                 case( VT_DATE ):
1065                         res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
1066                         break;
1067                 case( VT_BOOL ):
1068                         res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
1069                         break;
1070                 case( VT_BSTR ):
1071                         res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
1072                         break;
1073                 case( VT_CY ):
1074                         res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
1075                         break;
1076                 case( VT_DISPATCH ):
1077                         /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1078                 case( VT_DECIMAL ):
1079                         /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1080                 case( VT_UNKNOWN ):
1081                 default:
1082                         res = DISP_E_TYPEMISMATCH;
1083                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1084                         break;
1085                 }
1086                 break;
1087
1088         case( VT_UI1 ):
1089                 switch( vtFrom )
1090                 {
1091                 case( VT_I1 ):
1092                         res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
1093                         break;
1094                 case( VT_I2 ):
1095                         res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
1096                         break;
1097                 case( VT_INT ):
1098                 case( VT_I4 ):
1099                         res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
1100                         break;
1101         case( VT_UI1 ):
1102             res = VariantCopy( pd, ps );
1103             break;
1104                 case( VT_UI2 ):
1105                         res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
1106                         break;
1107                 case( VT_UINT ):
1108                 case( VT_UI4 ):
1109                         res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
1110                         break;
1111                 case( VT_R4 ):
1112                         res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
1113                         break;
1114                 case( VT_R8 ):
1115                         res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
1116                         break;
1117                 case( VT_DATE ):
1118                         res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
1119                         break;
1120                 case( VT_BOOL ):
1121                         res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
1122                         break;
1123                 case( VT_BSTR ):
1124                         res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
1125                         break;
1126                 case( VT_CY ):
1127                         res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
1128                         break;
1129                 case( VT_DISPATCH ):
1130                         /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1131                 case( VT_DECIMAL ):
1132                         /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1133                 case( VT_UNKNOWN ):
1134                 default:
1135                         res = DISP_E_TYPEMISMATCH;
1136                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1137                         break;
1138                 }
1139                 break;
1140
1141         case( VT_UI2 ):
1142                 switch( vtFrom )
1143                 {
1144                 case( VT_I1 ):
1145                         res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
1146                         break;
1147                 case( VT_I2 ):
1148                         res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
1149                         break;
1150                 case( VT_INT ):
1151                 case( VT_I4 ):
1152                         res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
1153                         break;
1154                 case( VT_UI1 ):
1155                         res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
1156                         break;
1157         case( VT_UI2 ):
1158             res = VariantCopy( pd, ps );
1159             break;
1160                 case( VT_UINT ):
1161                 case( VT_UI4 ):
1162                         res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
1163                         break;
1164                 case( VT_R4 ):
1165                         res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
1166                         break;
1167                 case( VT_R8 ):
1168                         res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
1169                         break;
1170                 case( VT_DATE ):
1171                         res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
1172                         break;
1173                 case( VT_BOOL ):
1174                         res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
1175                         break;
1176                 case( VT_BSTR ):
1177                         res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
1178                         break;
1179                 case( VT_CY ):
1180                         res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
1181                         break;
1182                 case( VT_DISPATCH ):
1183                         /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1184                 case( VT_DECIMAL ):
1185                         /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1186                 case( VT_UNKNOWN ):
1187                 default:
1188                         res = DISP_E_TYPEMISMATCH;
1189                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1190                         break;
1191                 }
1192                 break;
1193
1194         case( VT_UINT ):
1195         case( VT_UI4 ):
1196                 switch( vtFrom )
1197                 {
1198                 case( VT_I1 ):
1199                         res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
1200                         break;
1201                 case( VT_I2 ):
1202                         res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
1203                         break;
1204                 case( VT_INT ):
1205                 case( VT_I4 ):
1206                         res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
1207                         break;
1208                 case( VT_UI1 ):
1209                         res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
1210                         break;
1211                 case( VT_UI2 ):
1212                         res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
1213                         break;
1214         case( VT_UI4 ):
1215             res = VariantCopy( pd, ps );
1216             break;
1217                 case( VT_R4 ):
1218                         res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
1219                         break;
1220                 case( VT_R8 ):
1221                         res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
1222                         break;
1223                 case( VT_DATE ):
1224                         res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
1225                         break;
1226                 case( VT_BOOL ):
1227                         res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
1228                         break;
1229                 case( VT_BSTR ):
1230                         res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
1231                         break;
1232                 case( VT_CY ):
1233                         res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
1234                         break;
1235                 case( VT_DISPATCH ):
1236                         /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1237                 case( VT_DECIMAL ):
1238                         /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1239                 case( VT_UNKNOWN ):
1240                 default:
1241                         res = DISP_E_TYPEMISMATCH;
1242                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1243                         break;
1244                 }
1245                 break;
1246
1247         case( VT_R4 ):
1248                 switch( vtFrom )
1249                 {
1250                 case( VT_I1 ):
1251                         res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
1252                         break;
1253                 case( VT_I2 ):
1254                         res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
1255                         break;
1256                 case( VT_INT ):
1257                 case( VT_I4 ):
1258                         res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
1259                         break;
1260                 case( VT_UI1 ):
1261                         res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
1262                         break;
1263                 case( VT_UI2 ):
1264                         res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
1265                         break;
1266                 case( VT_UINT ):
1267                 case( VT_UI4 ):
1268                         res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
1269                         break;
1270         case( VT_R4 ):
1271             res = VariantCopy( pd, ps );
1272             break;
1273                 case( VT_R8 ):
1274                         res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
1275                         break;
1276                 case( VT_DATE ):
1277                         res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
1278                         break;
1279                 case( VT_BOOL ):
1280                         res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
1281                         break;
1282                 case( VT_BSTR ):
1283                         res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
1284                         break;
1285                 case( VT_CY ):
1286                         res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
1287                         break;
1288                 case( VT_DISPATCH ):
1289                         /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1290                 case( VT_DECIMAL ):
1291                         /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1292                 case( VT_UNKNOWN ):
1293                 default:
1294                         res = DISP_E_TYPEMISMATCH;
1295                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1296                         break;
1297                 }
1298                 break;
1299
1300         case( VT_R8 ):
1301                 switch( vtFrom )
1302                 {
1303                 case( VT_I1 ):
1304                         res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
1305                         break;
1306                 case( VT_I2 ):
1307                         res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
1308                         break;
1309                 case( VT_INT ):
1310                 case( VT_I4 ):
1311                         res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
1312                         break;
1313                 case( VT_UI1 ):
1314                         res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
1315                         break;
1316                 case( VT_UI2 ):
1317                         res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
1318                         break;
1319                 case( VT_UINT ):
1320                 case( VT_UI4 ):
1321                         res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
1322                         break;
1323                 case( VT_R4 ):
1324                         res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
1325                         break;
1326         case( VT_R8 ):
1327             res = VariantCopy( pd, ps );
1328             break;
1329                 case( VT_DATE ):
1330                         res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
1331                         break;
1332                 case( VT_BOOL ):
1333                         res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
1334                         break;
1335                 case( VT_BSTR ):
1336                         res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
1337                         break;
1338                 case( VT_CY ):
1339                         res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
1340                         break;
1341                 case( VT_DISPATCH ):
1342                         /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1343                 case( VT_DECIMAL ):
1344                         /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1345                 case( VT_UNKNOWN ):
1346                 default:
1347                         res = DISP_E_TYPEMISMATCH;
1348                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1349                         break;
1350                 }
1351                 break;
1352
1353         case( VT_DATE ):
1354                 switch( vtFrom )
1355                 {
1356                 case( VT_I1 ):
1357                         res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
1358                         break;
1359                 case( VT_I2 ):
1360                         res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
1361                         break;
1362                 case( VT_INT ):
1363                         res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
1364                         break;
1365                 case( VT_I4 ):
1366                         res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
1367                         break;
1368                 case( VT_UI1 ):
1369                         res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
1370                         break;
1371                 case( VT_UI2 ):
1372                         res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
1373                         break;
1374                 case( VT_UINT ):
1375                         res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
1376                         break;
1377                 case( VT_UI4 ):
1378                         res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
1379                         break;
1380                 case( VT_R4 ):
1381                         res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
1382                         break;
1383                 case( VT_R8 ):
1384                         res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
1385                         break;
1386         case( VT_DATE ):
1387             res = VariantCopy( pd, ps );
1388             break;
1389                 case( VT_BOOL ):
1390                         res = VarDateFromBool( V_UNION(ps,boolVal), &V_UNION(pd,date) );
1391                         break;
1392                 case( VT_BSTR ):
1393                         res = VarDateFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,date) );
1394                         break;
1395                 case( VT_CY ):
1396                         res = VarDateFromCy( V_UNION(ps,cyVal), &V_UNION(pd,date) );
1397                         break;
1398                 case( VT_DISPATCH ):
1399                         /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1400                 case( VT_DECIMAL ):
1401                         /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1402                 case( VT_UNKNOWN ):
1403                 default:
1404                         res = DISP_E_TYPEMISMATCH;
1405                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1406                         break;
1407                 }
1408                 break;
1409
1410         case( VT_BOOL ):
1411                 switch( vtFrom )
1412                 {
1413                 case( VT_EMPTY ):
1414                         res = S_OK;
1415                         V_UNION(pd,boolVal) = VARIANT_FALSE;
1416                         break;
1417                 case( VT_I1 ):
1418                         res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
1419                         break;
1420                 case( VT_I2 ):
1421                         res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
1422                         break;
1423                 case( VT_INT ):
1424                         res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
1425                         break;
1426                 case( VT_I4 ):
1427                         res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
1428                         break;
1429                 case( VT_UI1 ):
1430                         res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
1431                         break;
1432                 case( VT_UI2 ):
1433                         res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
1434                         break;
1435                 case( VT_UINT ):
1436                         res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
1437                         break;
1438                 case( VT_UI4 ):
1439                         res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
1440                         break;
1441                 case( VT_R4 ):
1442                         res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
1443                         break;
1444                 case( VT_R8 ):
1445                         res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
1446                         break;
1447                 case( VT_DATE ):
1448                         res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
1449                         break;
1450         case( VT_BOOL ):
1451             res = VariantCopy( pd, ps );
1452             break;
1453                 case( VT_BSTR ):
1454                         res = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
1455                         break;
1456                 case( VT_CY ):
1457                         res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
1458                         break;
1459                 case( VT_DISPATCH ):
1460                         /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1461                 case( VT_DECIMAL ):
1462                         /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1463                 case( VT_UNKNOWN ):
1464                 default:
1465                         res = DISP_E_TYPEMISMATCH;
1466                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1467                         break;
1468                 }
1469                 break;
1470
1471         case( VT_BSTR ):
1472                 switch( vtFrom )
1473                 {
1474                 case( VT_EMPTY ):
1475                         if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
1476                                 res = S_OK;
1477                         else
1478                                 res = E_OUTOFMEMORY;
1479                         break;
1480                 case( VT_I1 ):
1481                         res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
1482                         break;
1483                 case( VT_I2 ):
1484                         res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
1485                         break;
1486                 case( VT_INT ):
1487                         res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
1488                         break;
1489                 case( VT_I4 ):
1490                         res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
1491                         break;
1492                 case( VT_UI1 ):
1493                         res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
1494                         break;
1495                 case( VT_UI2 ):
1496                         res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
1497                         break;
1498                 case( VT_UINT ):
1499                         res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
1500                         break;
1501                 case( VT_UI4 ):
1502                         res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
1503                         break;
1504                 case( VT_R4 ):
1505                         res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
1506                         break;
1507                 case( VT_R8 ):
1508                         res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
1509                         break;
1510                 case( VT_DATE ):
1511                         res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
1512                         break;
1513                 case( VT_BOOL ):
1514                         res = VarBstrFromBool( V_UNION(ps,boolVal), lcid, 0, &V_UNION(pd,bstrVal) );
1515                         break;
1516                 case( VT_BSTR ):
1517                         res = VariantCopy( pd, ps );
1518                         break;
1519                 case( VT_CY ):
1520                         res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
1521                         break;
1522                 case( VT_DISPATCH ):
1523                         /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1524                 case( VT_DECIMAL ):
1525                         /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1526                 case( VT_UNKNOWN ):
1527                 default:
1528                         res = DISP_E_TYPEMISMATCH;
1529                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1530                         break;
1531                 }
1532                 break;
1533
1534      case( VT_CY ):
1535         switch( vtFrom )
1536           {
1537           case( VT_I1 ):
1538              res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
1539              break;
1540           case( VT_I2 ):
1541              res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
1542              break;
1543           case( VT_INT ):
1544              res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
1545              break;
1546           case( VT_I4 ):
1547              res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
1548              break;
1549           case( VT_UI1 ):
1550              res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
1551              break;
1552           case( VT_UI2 ):
1553              res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
1554              break;
1555           case( VT_UINT ):
1556              res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
1557              break;
1558           case( VT_UI4 ):
1559              res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
1560              break;
1561           case( VT_R4 ):
1562              res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
1563              break;
1564           case( VT_R8 ):
1565              res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
1566              break;
1567           case( VT_DATE ):
1568              res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1569              break;
1570           case( VT_BOOL ):
1571              res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1572              break;
1573           case( VT_CY ):
1574              res = VariantCopy( pd, ps );
1575              break;
1576           case( VT_BSTR ):
1577              res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
1578              break;
1579           case( VT_DISPATCH ):
1580              /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1581           case( VT_DECIMAL ):
1582              /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1583              break;
1584           case( VT_UNKNOWN ):
1585           default:
1586              res = DISP_E_TYPEMISMATCH;
1587              FIXME("Coercion from %d to %d\n", vtFrom, vt );
1588              break;
1589           }
1590         break;
1591
1592         case( VT_UNKNOWN ):
1593             if (vtFrom == VT_DISPATCH)
1594             {
1595                 res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1596             }
1597             else
1598             {
1599                 res = DISP_E_TYPEMISMATCH;
1600                 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1601             }
1602             break;
1603
1604         default:
1605                 res = DISP_E_TYPEMISMATCH;
1606                 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1607                 break;
1608         }
1609
1610         return res;
1611 }
1612
1613 /******************************************************************************
1614  *              ValidateVtRange [INTERNAL]
1615  *
1616  * Used internally by the hi-level Variant API to determine
1617  * if the vartypes are valid.
1618  */
1619 static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
1620 {
1621     /* if by value we must make sure it is in the
1622      * range of the valid types.
1623      */
1624     if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1625     {
1626         return DISP_E_BADVARTYPE;
1627     }
1628     return S_OK;
1629 }
1630
1631
1632 /******************************************************************************
1633  *              ValidateVartype [INTERNAL]
1634  *
1635  * Used internally by the hi-level Variant API to determine
1636  * if the vartypes are valid.
1637  */
1638 static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
1639 {
1640         HRESULT res = S_OK;
1641
1642         /* check if we have a valid argument.
1643          */
1644         if( vt & VT_BYREF )
1645     {
1646         /* if by reference check that the type is in
1647          * the valid range and that it is not of empty or null type
1648          */
1649         if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1650             ( vt & VT_TYPEMASK ) == VT_NULL ||
1651                         ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1652                 {
1653                         res = DISP_E_BADVARTYPE;
1654                 }
1655
1656     }
1657     else
1658     {
1659         res = ValidateVtRange( vt );
1660     }
1661
1662         return res;
1663 }
1664
1665 /******************************************************************************
1666  *              ValidateVt      [INTERNAL]
1667  *
1668  * Used internally by the hi-level Variant API to determine
1669  * if the vartypes are valid.
1670  */
1671 static HRESULT WINAPI ValidateVt( VARTYPE vt )
1672 {
1673         HRESULT res = S_OK;
1674
1675         /* check if we have a valid argument.
1676          */
1677         if( vt & VT_BYREF )
1678     {
1679         /* if by reference check that the type is in
1680          * the valid range and that it is not of empty or null type
1681          */
1682         if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1683             ( vt & VT_TYPEMASK ) == VT_NULL ||
1684                         ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1685                 {
1686                         res = DISP_E_BADVARTYPE;
1687                 }
1688
1689     }
1690     else
1691     {
1692         res = ValidateVtRange( vt );
1693     }
1694
1695         return res;
1696 }
1697
1698
1699
1700
1701
1702 /******************************************************************************
1703  *              VariantInit     [OLEAUT32.8]
1704  *
1705  * Initializes the Variant.  Unlike VariantClear it does not interpret
1706  * the current contents of the Variant.
1707  */
1708 void WINAPI VariantInit(VARIANTARG* pvarg)
1709 {
1710   TRACE("(%p)\n",pvarg);
1711
1712   memset(pvarg, 0, sizeof (VARIANTARG));
1713   V_VT(pvarg) = VT_EMPTY;
1714
1715   return;
1716 }
1717
1718 /******************************************************************************
1719  *              VariantClear    [OLEAUT32.9]
1720  *
1721  * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1722  * sets the wReservedX field to 0.      The current contents of the VARIANT are
1723  * freed.  If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1724  * released. If VT_ARRAY the array is freed.
1725  */
1726 HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
1727 {
1728   HRESULT res = S_OK;
1729   TRACE("(%p)\n",pvarg);
1730
1731   res = ValidateVariantType( V_VT(pvarg) );
1732   if( res == S_OK )
1733   {
1734     if( !( V_VT(pvarg) & VT_BYREF ) )
1735     {
1736       /*
1737        * The VT_ARRAY flag is a special case of a safe array.
1738        */
1739       if ( (V_VT(pvarg) & VT_ARRAY) != 0)
1740       {
1741         SafeArrayDestroy(V_UNION(pvarg,parray));
1742       }
1743       else
1744       {
1745         switch( V_VT(pvarg) & VT_TYPEMASK )
1746         {
1747           case( VT_BSTR ):
1748             SysFreeString( V_UNION(pvarg,bstrVal) );
1749             break;
1750           case( VT_DISPATCH ):
1751             if(V_UNION(pvarg,pdispVal)!=NULL)
1752               ICOM_CALL(Release,V_UNION(pvarg,pdispVal));
1753             break;
1754           case( VT_VARIANT ):
1755             VariantClear(V_UNION(pvarg,pvarVal));
1756             break;
1757           case( VT_UNKNOWN ):
1758             if(V_UNION(pvarg,punkVal)!=NULL)
1759               ICOM_CALL(Release,V_UNION(pvarg,punkVal));
1760             break;
1761           case( VT_SAFEARRAY ):
1762             SafeArrayDestroy(V_UNION(pvarg,parray));
1763             break;
1764           default:
1765             break;
1766         }
1767       }
1768     }
1769
1770     /*
1771      * Empty all the fields and mark the type as empty.
1772      */
1773     memset(pvarg, 0, sizeof (VARIANTARG));
1774     V_VT(pvarg) = VT_EMPTY;
1775   }
1776
1777   return res;
1778 }
1779
1780 /******************************************************************************
1781  *              VariantCopy     [OLEAUT32.10]
1782  *
1783  * Frees up the designation variant and makes a copy of the source.
1784  */
1785 HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
1786 {
1787   HRESULT res = S_OK;
1788
1789   TRACE("(%p, %p), vt=%d\n", pvargDest, pvargSrc, V_VT(pvargSrc));
1790
1791   res = ValidateVariantType( V_VT(pvargSrc) );
1792
1793   /* If the pointer are to the same variant we don't need
1794    * to do anything.
1795    */
1796   if( pvargDest != pvargSrc && res == S_OK )
1797   {
1798     res = VariantClear( pvargDest );
1799
1800     if( res == S_OK )
1801     {
1802       if( V_VT(pvargSrc) & VT_BYREF )
1803       {
1804         /* In the case of byreference we only need
1805          * to copy the pointer.
1806          */
1807         pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1808         V_VT(pvargDest) = V_VT(pvargSrc);
1809       }
1810       else
1811       {
1812         /*
1813          * The VT_ARRAY flag is another way to designate a safe array.
1814          */
1815         if (V_VT(pvargSrc) & VT_ARRAY)
1816         {
1817           SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1818         }
1819         else
1820         {
1821           /* In the case of by value we need to
1822            * copy the actual value. In the case of
1823            * VT_BSTR a copy of the string is made,
1824            * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1825            * called to increment the object's reference count.
1826            */
1827           switch( V_VT(pvargSrc) & VT_TYPEMASK )
1828           {
1829             case( VT_BSTR ):
1830               V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
1831               break;
1832             case( VT_DISPATCH ):
1833               V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
1834               if (V_UNION(pvargDest,pdispVal)!=NULL)
1835                 ICOM_CALL(AddRef,V_UNION(pvargDest,pdispVal));
1836               break;
1837             case( VT_VARIANT ):
1838               VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
1839               break;
1840             case( VT_UNKNOWN ):
1841               V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
1842               if (V_UNION(pvargDest,pdispVal)!=NULL)
1843                 ICOM_CALL(AddRef,V_UNION(pvargDest,punkVal));
1844               break;
1845             case( VT_SAFEARRAY ):
1846               SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1847               break;
1848             default:
1849               pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1850               break;
1851           }
1852         }
1853
1854         V_VT(pvargDest) = V_VT(pvargSrc);
1855       }
1856     }
1857   }
1858
1859   return res;
1860 }
1861
1862
1863 /******************************************************************************
1864  *              VariantCopyInd  [OLEAUT32.11]
1865  *
1866  * Frees up the destination variant and makes a copy of the source.  If
1867  * the source is of type VT_BYREF it performs the necessary indirections.
1868  */
1869 HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
1870 {
1871   HRESULT res = S_OK;
1872
1873   TRACE("(%p, %p)\n", pvargDest, pvargSrc);
1874
1875   res = ValidateVariantType( V_VT(pvargSrc) );
1876
1877   if( res != S_OK )
1878     return res;
1879
1880   if( V_VT(pvargSrc) & VT_BYREF )
1881   {
1882     VARIANTARG varg;
1883     VariantInit( &varg );
1884
1885     /* handle the in place copy.
1886      */
1887     if( pvargDest == pvargSrc )
1888     {
1889       /* we will use a copy of the source instead.
1890        */
1891       res = VariantCopy( &varg, pvargSrc );
1892       pvargSrc = &varg;
1893     }
1894
1895     if( res == S_OK )
1896     {
1897       res = VariantClear( pvargDest );
1898
1899       if( res == S_OK )
1900       {
1901         /*
1902          * The VT_ARRAY flag is another way to designate a safearray variant.
1903          */
1904         if ( V_VT(pvargSrc) & VT_ARRAY)
1905         {
1906           SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
1907         }
1908         else
1909         {
1910           /* In the case of by reference we need
1911            * to copy the date pointed to by the variant.
1912            */
1913
1914           /* Get the variant type.
1915            */
1916           switch( V_VT(pvargSrc) & VT_TYPEMASK )
1917           {
1918             case( VT_BSTR ):
1919               V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
1920               break;
1921             case( VT_DISPATCH ):
1922               break;
1923             case( VT_VARIANT ):
1924               {
1925                 /* Prevent from cycling.  According to tests on
1926                  * VariantCopyInd in Windows and the documentation
1927                  * this API dereferences the inner Variants to only one depth.
1928                  * If the inner Variant itself contains an
1929                  * other inner variant the E_INVALIDARG error is
1930                  * returned.
1931                  */
1932                 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
1933                 {
1934                   /* If we get here we are attempting to deference
1935                    * an inner variant that that is itself contained
1936                    * in an inner variant so report E_INVALIDARG error.
1937                    */
1938                   res = E_INVALIDARG;
1939                 }
1940                 else
1941                 {
1942                   /* Set the processing inner variant flag.
1943                    * We will set this flag in the inner variant
1944                    * that will be passed to the VariantCopyInd function.
1945                    */
1946                   (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
1947
1948                   /* Dereference the inner variant.
1949                    */
1950                   res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
1951                   /* We must also copy its type, I think.
1952                    */
1953                   V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
1954                 }
1955               }
1956               break;
1957             case( VT_UNKNOWN ):
1958               break;
1959             case( VT_SAFEARRAY ):
1960               SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
1961               break;
1962             default:
1963               /* This is a by reference Variant which means that the union
1964                * part of the Variant contains a pointer to some data of
1965                * type "V_VT(pvargSrc) & VT_TYPEMASK".
1966                * We will deference this data in a generic fashion using
1967                * the void pointer "Variant.u.byref".
1968                * We will copy this data into the union of the destination
1969                * Variant.
1970                */
1971               memcpy( &pvargDest->n1.n2.n3, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
1972               break;
1973           }
1974         }
1975
1976         if (res == S_OK) V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
1977       }
1978     }
1979
1980     /* this should not fail.
1981      */
1982     VariantClear( &varg );
1983   }
1984   else
1985   {
1986     res = VariantCopy( pvargDest, pvargSrc );
1987   }
1988
1989   return res;
1990 }
1991
1992 /******************************************************************************
1993  *              VariantChangeType       [OLEAUT32.12]
1994  */
1995 HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
1996                                                         USHORT wFlags, VARTYPE vt)
1997 {
1998         return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
1999 }
2000
2001 /******************************************************************************
2002  *              VariantChangeTypeEx     [OLEAUT32.147]
2003  */
2004 HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2005                                                           LCID lcid, USHORT wFlags, VARTYPE vt)
2006 {
2007         HRESULT res = S_OK;
2008         VARIANTARG varg;
2009         VariantInit( &varg );
2010
2011         TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
2012
2013         /* validate our source argument.
2014          */
2015         res = ValidateVariantType( V_VT(pvargSrc) );
2016
2017         /* validate the vartype.
2018          */
2019         if( res == S_OK )
2020         {
2021                 res = ValidateVt( vt );
2022         }
2023
2024         /* if we are doing an in-place conversion make a copy of the source.
2025          */
2026         if( res == S_OK && pvargDest == pvargSrc )
2027         {
2028                 res = VariantCopy( &varg, pvargSrc );
2029                 pvargSrc = &varg;
2030         }
2031
2032         if( res == S_OK )
2033         {
2034                 /* free up the destination variant.
2035                  */
2036                 res = VariantClear( pvargDest );
2037         }
2038
2039         if( res == S_OK )
2040         {
2041                 if( V_VT(pvargSrc) & VT_BYREF )
2042                 {
2043                         /* Convert the source variant to a "byvalue" variant.
2044                          */
2045                         VARIANTARG Variant;
2046                         VariantInit( &Variant );
2047                         res = VariantCopyInd( &Variant, pvargSrc );
2048                         if( res == S_OK )
2049                         {
2050                                 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2051                                 /* this should not fail.
2052                                  */
2053                                 VariantClear( &Variant );
2054                         }
2055
2056                 }
2057                 else
2058                 {
2059                         /* Use the current "byvalue" source variant.
2060                          */
2061                         res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2062                 }
2063         }
2064         /* this should not fail.
2065          */
2066         VariantClear( &varg );
2067
2068         /* set the type of the destination
2069          */
2070         if ( res == S_OK )
2071                 V_VT(pvargDest) = vt;
2072
2073         return res;
2074 }
2075
2076
2077
2078
2079 /******************************************************************************
2080  *              VarUI1FromI2            [OLEAUT32.130]
2081  */
2082 HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2083 {
2084         TRACE("( %d, %p ), stub\n", sIn, pbOut );
2085
2086         /* Check range of value.
2087          */
2088         if( sIn < UI1_MIN || sIn > UI1_MAX )
2089         {
2090                 return DISP_E_OVERFLOW;
2091         }
2092
2093         *pbOut = (BYTE) sIn;
2094
2095         return S_OK;
2096 }
2097
2098 /******************************************************************************
2099  *              VarUI1FromI4            [OLEAUT32.131]
2100  */
2101 HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2102 {
2103         TRACE("( %ld, %p ), stub\n", lIn, pbOut );
2104
2105         /* Check range of value.
2106          */
2107         if( lIn < UI1_MIN || lIn > UI1_MAX )
2108         {
2109                 return DISP_E_OVERFLOW;
2110         }
2111
2112         *pbOut = (BYTE) lIn;
2113
2114         return S_OK;
2115 }
2116
2117
2118 /******************************************************************************
2119  *              VarUI1FromR4            [OLEAUT32.132]
2120  */
2121 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2122 {
2123         TRACE("( %f, %p ), stub\n", fltIn, pbOut );
2124
2125         /* Check range of value.
2126      */
2127     fltIn = round( fltIn );
2128         if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2129         {
2130                 return DISP_E_OVERFLOW;
2131         }
2132
2133         *pbOut = (BYTE) fltIn;
2134
2135         return S_OK;
2136 }
2137
2138 /******************************************************************************
2139  *              VarUI1FromR8            [OLEAUT32.133]
2140  */
2141 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2142 {
2143         TRACE("( %f, %p ), stub\n", dblIn, pbOut );
2144
2145         /* Check range of value.
2146      */
2147     dblIn = round( dblIn );
2148         if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2149         {
2150                 return DISP_E_OVERFLOW;
2151         }
2152
2153         *pbOut = (BYTE) dblIn;
2154
2155         return S_OK;
2156 }
2157
2158 /******************************************************************************
2159  *              VarUI1FromDate          [OLEAUT32.135]
2160  */
2161 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2162 {
2163         TRACE("( %f, %p ), stub\n", dateIn, pbOut );
2164
2165         /* Check range of value.
2166      */
2167     dateIn = round( dateIn );
2168         if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2169         {
2170                 return DISP_E_OVERFLOW;
2171         }
2172
2173         *pbOut = (BYTE) dateIn;
2174
2175         return S_OK;
2176 }
2177
2178 /******************************************************************************
2179  *              VarUI1FromBool          [OLEAUT32.138]
2180  */
2181 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2182 {
2183         TRACE("( %d, %p ), stub\n", boolIn, pbOut );
2184
2185         *pbOut = (BYTE) boolIn;
2186
2187         return S_OK;
2188 }
2189
2190 /******************************************************************************
2191  *              VarUI1FromI1            [OLEAUT32.237]
2192  */
2193 HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
2194 {
2195         TRACE("( %c, %p ), stub\n", cIn, pbOut );
2196
2197         *pbOut = cIn;
2198
2199         return S_OK;
2200 }
2201
2202 /******************************************************************************
2203  *              VarUI1FromUI2           [OLEAUT32.238]
2204  */
2205 HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2206 {
2207         TRACE("( %d, %p ), stub\n", uiIn, pbOut );
2208
2209         /* Check range of value.
2210          */
2211         if( uiIn > UI1_MAX )
2212         {
2213                 return DISP_E_OVERFLOW;
2214         }
2215
2216         *pbOut = (BYTE) uiIn;
2217
2218         return S_OK;
2219 }
2220
2221 /******************************************************************************
2222  *              VarUI1FromUI4           [OLEAUT32.239]
2223  */
2224 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2225 {
2226         TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
2227
2228         /* Check range of value.
2229          */
2230         if( ulIn > UI1_MAX )
2231         {
2232                 return DISP_E_OVERFLOW;
2233         }
2234
2235         *pbOut = (BYTE) ulIn;
2236
2237         return S_OK;
2238 }
2239
2240
2241 /******************************************************************************
2242  *              VarUI1FromStr           [OLEAUT32.136]
2243  */
2244 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2245 {
2246         double dValue = 0.0;
2247         LPSTR pNewString = NULL;
2248
2249         TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
2250
2251         /* Check if we have a valid argument
2252          */
2253         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2254         RemoveCharacterFromString( pNewString, "," );
2255         if( IsValidRealString( pNewString ) == FALSE )
2256         {
2257                 return DISP_E_TYPEMISMATCH;
2258         }
2259
2260         /* Convert the valid string to a floating point number.
2261          */
2262         dValue = atof( pNewString );
2263
2264         /* We don't need the string anymore so free it.
2265          */
2266         HeapFree( GetProcessHeap(), 0 , pNewString );
2267
2268         /* Check range of value.
2269      */
2270     dValue = round( dValue );
2271         if( dValue < UI1_MIN || dValue > UI1_MAX )
2272         {
2273                 return DISP_E_OVERFLOW;
2274         }
2275
2276         *pbOut = (BYTE) dValue;
2277
2278         return S_OK;
2279 }
2280
2281 /**********************************************************************
2282  *              VarUI1FromCy [OLEAUT32.134]
2283  * Convert currency to unsigned char
2284  */
2285 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
2286    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2287
2288    if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
2289
2290    *pbOut = (BYTE)t;
2291    return S_OK;
2292 }
2293
2294 /******************************************************************************
2295  *              VarI2FromUI1            [OLEAUT32.48]
2296  */
2297 HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2298 {
2299         TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
2300
2301         *psOut = (short) bIn;
2302
2303         return S_OK;
2304 }
2305
2306 /******************************************************************************
2307  *              VarI2FromI4             [OLEAUT32.49]
2308  */
2309 HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2310 {
2311         TRACE("( %lx, %p ), stub\n", lIn, psOut );
2312
2313         /* Check range of value.
2314          */
2315         if( lIn < I2_MIN || lIn > I2_MAX )
2316         {
2317                 return DISP_E_OVERFLOW;
2318         }
2319
2320         *psOut = (short) lIn;
2321
2322         return S_OK;
2323 }
2324
2325 /******************************************************************************
2326  *              VarI2FromR4             [OLEAUT32.50]
2327  */
2328 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2329 {
2330         TRACE("( %f, %p ), stub\n", fltIn, psOut );
2331
2332         /* Check range of value.
2333      */
2334     fltIn = round( fltIn );
2335         if( fltIn < I2_MIN || fltIn > I2_MAX )
2336         {
2337                 return DISP_E_OVERFLOW;
2338         }
2339
2340         *psOut = (short) fltIn;
2341
2342         return S_OK;
2343 }
2344
2345 /******************************************************************************
2346  *              VarI2FromR8             [OLEAUT32.51]
2347  */
2348 HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2349 {
2350         TRACE("( %f, %p ), stub\n", dblIn, psOut );
2351
2352         /* Check range of value.
2353      */
2354     dblIn = round( dblIn );
2355         if( dblIn < I2_MIN || dblIn > I2_MAX )
2356         {
2357                 return DISP_E_OVERFLOW;
2358         }
2359
2360         *psOut = (short) dblIn;
2361
2362         return S_OK;
2363 }
2364
2365 /******************************************************************************
2366  *              VarI2FromDate           [OLEAUT32.53]
2367  */
2368 HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2369 {
2370         TRACE("( %f, %p ), stub\n", dateIn, psOut );
2371
2372         /* Check range of value.
2373      */
2374     dateIn = round( dateIn );
2375         if( dateIn < I2_MIN || dateIn > I2_MAX )
2376         {
2377                 return DISP_E_OVERFLOW;
2378         }
2379
2380         *psOut = (short) dateIn;
2381
2382         return S_OK;
2383 }
2384
2385 /******************************************************************************
2386  *              VarI2FromBool           [OLEAUT32.56]
2387  */
2388 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2389 {
2390         TRACE("( %d, %p ), stub\n", boolIn, psOut );
2391
2392         *psOut = (short) boolIn;
2393
2394         return S_OK;
2395 }
2396
2397 /******************************************************************************
2398  *              VarI2FromI1             [OLEAUT32.205]
2399  */
2400 HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
2401 {
2402         TRACE("( %c, %p ), stub\n", cIn, psOut );
2403
2404         *psOut = (short) cIn;
2405
2406         return S_OK;
2407 }
2408
2409 /******************************************************************************
2410  *              VarI2FromUI2            [OLEAUT32.206]
2411  */
2412 HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2413 {
2414         TRACE("( %d, %p ), stub\n", uiIn, psOut );
2415
2416         /* Check range of value.
2417          */
2418         if( uiIn > I2_MAX )
2419         {
2420                 return DISP_E_OVERFLOW;
2421         }
2422
2423         *psOut = (short) uiIn;
2424
2425         return S_OK;
2426 }
2427
2428 /******************************************************************************
2429  *              VarI2FromUI4            [OLEAUT32.207]
2430  */
2431 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2432 {
2433         TRACE("( %lx, %p ), stub\n", ulIn, psOut );
2434
2435         /* Check range of value.
2436          */
2437         if( ulIn < I2_MIN || ulIn > I2_MAX )
2438         {
2439                 return DISP_E_OVERFLOW;
2440         }
2441
2442         *psOut = (short) ulIn;
2443
2444         return S_OK;
2445 }
2446
2447 /******************************************************************************
2448  *              VarI2FromStr            [OLEAUT32.54]
2449  */
2450 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2451 {
2452         double dValue = 0.0;
2453         LPSTR pNewString = NULL;
2454
2455         TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, psOut );
2456
2457         /* Check if we have a valid argument
2458          */
2459         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2460         RemoveCharacterFromString( pNewString, "," );
2461         if( IsValidRealString( pNewString ) == FALSE )
2462         {
2463                 return DISP_E_TYPEMISMATCH;
2464         }
2465
2466         /* Convert the valid string to a floating point number.
2467          */
2468         dValue = atof( pNewString );
2469
2470         /* We don't need the string anymore so free it.
2471          */
2472         HeapFree( GetProcessHeap(), 0, pNewString );
2473
2474         /* Check range of value.
2475      */
2476     dValue = round( dValue );
2477         if( dValue < I2_MIN || dValue > I2_MAX )
2478         {
2479                 return DISP_E_OVERFLOW;
2480         }
2481
2482         *psOut = (short)  dValue;
2483
2484         return S_OK;
2485 }
2486
2487 /**********************************************************************
2488  *              VarI2FromCy [OLEAUT32.52]
2489  * Convert currency to signed short
2490  */
2491 HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
2492    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2493
2494    if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
2495
2496    *psOut = (SHORT)t;
2497    return S_OK;
2498 }
2499
2500 /******************************************************************************
2501  *              VarI4FromUI1            [OLEAUT32.58]
2502  */
2503 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2504 {
2505         TRACE("( %X, %p ), stub\n", bIn, plOut );
2506
2507         *plOut = (LONG) bIn;
2508
2509         return S_OK;
2510 }
2511
2512
2513 /******************************************************************************
2514  *              VarI4FromR4             [OLEAUT32.60]
2515  */
2516 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2517 {
2518         TRACE("( %f, %p ), stub\n", fltIn, plOut );
2519
2520         /* Check range of value.
2521      */
2522     fltIn = round( fltIn );
2523         if( fltIn < I4_MIN || fltIn > I4_MAX )
2524         {
2525                 return DISP_E_OVERFLOW;
2526         }
2527
2528         *plOut = (LONG) fltIn;
2529
2530         return S_OK;
2531 }
2532
2533 /******************************************************************************
2534  *              VarI4FromR8             [OLEAUT32.61]
2535  */
2536 HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2537 {
2538         TRACE("( %f, %p ), stub\n", dblIn, plOut );
2539
2540         /* Check range of value.
2541      */
2542     dblIn = round( dblIn );
2543         if( dblIn < I4_MIN || dblIn > I4_MAX )
2544         {
2545                 return DISP_E_OVERFLOW;
2546         }
2547
2548         *plOut = (LONG) dblIn;
2549
2550         return S_OK;
2551 }
2552
2553 /******************************************************************************
2554  *              VarI4FromDate           [OLEAUT32.63]
2555  */
2556 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2557 {
2558         TRACE("( %f, %p ), stub\n", dateIn, plOut );
2559
2560         /* Check range of value.
2561      */
2562     dateIn = round( dateIn );
2563         if( dateIn < I4_MIN || dateIn > I4_MAX )
2564         {
2565                 return DISP_E_OVERFLOW;
2566         }
2567
2568         *plOut = (LONG) dateIn;
2569
2570         return S_OK;
2571 }
2572
2573 /******************************************************************************
2574  *              VarI4FromBool           [OLEAUT32.66]
2575  */
2576 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2577 {
2578         TRACE("( %d, %p ), stub\n", boolIn, plOut );
2579
2580         *plOut = (LONG) boolIn;
2581
2582         return S_OK;
2583 }
2584
2585 /******************************************************************************
2586  *              VarI4FromI1             [OLEAUT32.209]
2587  */
2588 HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
2589 {
2590         TRACE("( %c, %p ), stub\n", cIn, plOut );
2591
2592         *plOut = (LONG) cIn;
2593
2594         return S_OK;
2595 }
2596
2597 /******************************************************************************
2598  *              VarI4FromUI2            [OLEAUT32.210]
2599  */
2600 HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2601 {
2602         TRACE("( %d, %p ), stub\n", uiIn, plOut );
2603
2604         *plOut = (LONG) uiIn;
2605
2606         return S_OK;
2607 }
2608
2609 /******************************************************************************
2610  *              VarI4FromUI4            [OLEAUT32.211]
2611  */
2612 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2613 {
2614         TRACE("( %lx, %p ), stub\n", ulIn, plOut );
2615
2616         /* Check range of value.
2617          */
2618         if( ulIn < I4_MIN || ulIn > I4_MAX )
2619         {
2620                 return DISP_E_OVERFLOW;
2621         }
2622
2623         *plOut = (LONG) ulIn;
2624
2625         return S_OK;
2626 }
2627
2628 /******************************************************************************
2629  *              VarI4FromI2             [OLEAUT32.59]
2630  */
2631 HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2632 {
2633         TRACE("( %d, %p ), stub\n", sIn, plOut );
2634
2635         *plOut = (LONG) sIn;
2636
2637         return S_OK;
2638 }
2639
2640 /******************************************************************************
2641  *              VarI4FromStr            [OLEAUT32.64]
2642  */
2643 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2644 {
2645         double dValue = 0.0;
2646         LPSTR pNewString = NULL;
2647
2648         TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
2649
2650         /* Check if we have a valid argument
2651          */
2652         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2653         RemoveCharacterFromString( pNewString, "," );
2654         if( IsValidRealString( pNewString ) == FALSE )
2655         {
2656                 return DISP_E_TYPEMISMATCH;
2657         }
2658
2659         /* Convert the valid string to a floating point number.
2660          */
2661         dValue = atof( pNewString );
2662
2663         /* We don't need the string anymore so free it.
2664          */
2665         HeapFree( GetProcessHeap(), 0, pNewString );
2666
2667         /* Check range of value.
2668      */
2669     dValue = round( dValue );
2670         if( dValue < I4_MIN || dValue > I4_MAX )
2671         {
2672                 return DISP_E_OVERFLOW;
2673         }
2674
2675         *plOut = (LONG) dValue;
2676
2677         return S_OK;
2678 }
2679
2680 /**********************************************************************
2681  *              VarI4FromCy [OLEAUT32.62]
2682  * Convert currency to signed long
2683  */
2684 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
2685    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2686
2687    if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
2688
2689    *plOut = (LONG)t;
2690    return S_OK;
2691 }
2692
2693 /******************************************************************************
2694  *              VarR4FromUI1            [OLEAUT32.68]
2695  */
2696 HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
2697 {
2698         TRACE("( %X, %p ), stub\n", bIn, pfltOut );
2699
2700         *pfltOut = (FLOAT) bIn;
2701
2702         return S_OK;
2703 }
2704
2705 /******************************************************************************
2706  *              VarR4FromI2             [OLEAUT32.69]
2707  */
2708 HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
2709 {
2710         TRACE("( %d, %p ), stub\n", sIn, pfltOut );
2711
2712         *pfltOut = (FLOAT) sIn;
2713
2714         return S_OK;
2715 }
2716
2717 /******************************************************************************
2718  *              VarR4FromI4             [OLEAUT32.70]
2719  */
2720 HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
2721 {
2722         TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
2723
2724         *pfltOut = (FLOAT) lIn;
2725
2726         return S_OK;
2727 }
2728
2729 /******************************************************************************
2730  *              VarR4FromR8             [OLEAUT32.71]
2731  */
2732 HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
2733 {
2734         TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
2735
2736         /* Check range of value.
2737          */
2738         if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
2739         {
2740                 return DISP_E_OVERFLOW;
2741         }
2742
2743         *pfltOut = (FLOAT) dblIn;
2744
2745         return S_OK;
2746 }
2747
2748 /******************************************************************************
2749  *              VarR4FromDate           [OLEAUT32.73]
2750  */
2751 HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
2752 {
2753         TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
2754
2755         /* Check range of value.
2756          */
2757         if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
2758         {
2759                 return DISP_E_OVERFLOW;
2760         }
2761
2762         *pfltOut = (FLOAT) dateIn;
2763
2764         return S_OK;
2765 }
2766
2767 /******************************************************************************
2768  *              VarR4FromBool           [OLEAUT32.76]
2769  */
2770 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
2771 {
2772         TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
2773
2774         *pfltOut = (FLOAT) boolIn;
2775
2776         return S_OK;
2777 }
2778
2779 /******************************************************************************
2780  *              VarR4FromI1             [OLEAUT32.213]
2781  */
2782 HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
2783 {
2784         TRACE("( %c, %p ), stub\n", cIn, pfltOut );
2785
2786         *pfltOut = (FLOAT) cIn;
2787
2788         return S_OK;
2789 }
2790
2791 /******************************************************************************
2792  *              VarR4FromUI2            [OLEAUT32.214]
2793  */
2794 HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
2795 {
2796         TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
2797
2798         *pfltOut = (FLOAT) uiIn;
2799
2800         return S_OK;
2801 }
2802
2803 /******************************************************************************
2804  *              VarR4FromUI4            [OLEAUT32.215]
2805  */
2806 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
2807 {
2808         TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
2809
2810         *pfltOut = (FLOAT) ulIn;
2811
2812         return S_OK;
2813 }
2814
2815 /******************************************************************************
2816  *              VarR4FromStr            [OLEAUT32.74]
2817  */
2818 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
2819 {
2820         double dValue = 0.0;
2821         LPSTR pNewString = NULL;
2822
2823         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
2824
2825         /* Check if we have a valid argument
2826          */
2827         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2828         RemoveCharacterFromString( pNewString, "," );
2829         if( IsValidRealString( pNewString ) == FALSE )
2830         {
2831                 return DISP_E_TYPEMISMATCH;
2832         }
2833
2834         /* Convert the valid string to a floating point number.
2835          */
2836         dValue = atof( pNewString );
2837
2838         /* We don't need the string anymore so free it.
2839          */
2840         HeapFree( GetProcessHeap(), 0, pNewString );
2841
2842         /* Check range of value.
2843          */
2844         if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
2845         {
2846                 return DISP_E_OVERFLOW;
2847         }
2848
2849         *pfltOut = (FLOAT) dValue;
2850
2851         return S_OK;
2852 }
2853
2854 /**********************************************************************
2855  *              VarR4FromCy [OLEAUT32.72]
2856  * Convert currency to float
2857  */
2858 HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
2859    *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2860
2861    return S_OK;
2862 }
2863
2864 /******************************************************************************
2865  *              VarR8FromUI1            [OLEAUT32.78]
2866  */
2867 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
2868 {
2869         TRACE("( %d, %p ), stub\n", bIn, pdblOut );
2870
2871         *pdblOut = (double) bIn;
2872
2873         return S_OK;
2874 }
2875
2876 /******************************************************************************
2877  *              VarR8FromI2             [OLEAUT32.79]
2878  */
2879 HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
2880 {
2881         TRACE("( %d, %p ), stub\n", sIn, pdblOut );
2882
2883         *pdblOut = (double) sIn;
2884
2885         return S_OK;
2886 }
2887
2888 /******************************************************************************
2889  *              VarR8FromI4             [OLEAUT32.80]
2890  */
2891 HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
2892 {
2893         TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
2894
2895         *pdblOut = (double) lIn;
2896
2897         return S_OK;
2898 }
2899
2900 /******************************************************************************
2901  *              VarR8FromR4             [OLEAUT32.81]
2902  */
2903 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
2904 {
2905         TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
2906
2907         *pdblOut = (double) fltIn;
2908
2909         return S_OK;
2910 }
2911
2912 /******************************************************************************
2913  *              VarR8FromDate           [OLEAUT32.83]
2914  */
2915 HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
2916 {
2917         TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
2918
2919         *pdblOut = (double) dateIn;
2920
2921         return S_OK;
2922 }
2923
2924 /******************************************************************************
2925  *              VarR8FromBool           [OLEAUT32.86]
2926  */
2927 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
2928 {
2929         TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
2930
2931         *pdblOut = (double) boolIn;
2932
2933         return S_OK;
2934 }
2935
2936 /******************************************************************************
2937  *              VarR8FromI1             [OLEAUT32.217]
2938  */
2939 HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
2940 {
2941         TRACE("( %c, %p ), stub\n", cIn, pdblOut );
2942
2943         *pdblOut = (double) cIn;
2944
2945         return S_OK;
2946 }
2947
2948 /******************************************************************************
2949  *              VarR8FromUI2            [OLEAUT32.218]
2950  */
2951 HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
2952 {
2953         TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
2954
2955         *pdblOut = (double) uiIn;
2956
2957         return S_OK;
2958 }
2959
2960 /******************************************************************************
2961  *              VarR8FromUI4            [OLEAUT32.219]
2962  */
2963 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
2964 {
2965         TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
2966
2967         *pdblOut = (double) ulIn;
2968
2969         return S_OK;
2970 }
2971
2972 /******************************************************************************
2973  *              VarR8FromStr            [OLEAUT32.84]
2974  */
2975 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
2976 {
2977         double dValue = 0.0;
2978         LPSTR pNewString = NULL;
2979
2980         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pdblOut );
2981
2982         /* Check if we have a valid argument
2983          */
2984         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2985         RemoveCharacterFromString( pNewString, "," );
2986         if( IsValidRealString( pNewString ) == FALSE )
2987         {
2988                 return DISP_E_TYPEMISMATCH;
2989         }
2990
2991         /* Convert the valid string to a floating point number.
2992          */
2993         dValue = atof( pNewString );
2994
2995         /* We don't need the string anymore so free it.
2996          */
2997         HeapFree( GetProcessHeap(), 0, pNewString );
2998
2999         *pdblOut = dValue;
3000
3001         return S_OK;
3002 }
3003
3004 /**********************************************************************
3005  *              VarR8FromCy [OLEAUT32.82]
3006  * Convert currency to double
3007  */
3008 HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
3009    *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3010
3011    return S_OK;
3012 }
3013
3014 /******************************************************************************
3015  *              VarDateFromUI1          [OLEAUT32.88]
3016  */
3017 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
3018 {
3019         TRACE("( %d, %p ), stub\n", bIn, pdateOut );
3020
3021         *pdateOut = (DATE) bIn;
3022
3023         return S_OK;
3024 }
3025
3026 /******************************************************************************
3027  *              VarDateFromI2           [OLEAUT32.89]
3028  */
3029 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
3030 {
3031         TRACE("( %d, %p ), stub\n", sIn, pdateOut );
3032
3033         *pdateOut = (DATE) sIn;
3034
3035         return S_OK;
3036 }
3037
3038 /******************************************************************************
3039  *              VarDateFromI4           [OLEAUT32.90]
3040  */
3041 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3042 {
3043         TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
3044
3045         if( lIn < DATE_MIN || lIn > DATE_MAX )
3046         {
3047                 return DISP_E_OVERFLOW;
3048         }
3049
3050         *pdateOut = (DATE) lIn;
3051
3052         return S_OK;
3053 }
3054
3055 /******************************************************************************
3056  *              VarDateFromR4           [OLEAUT32.91]
3057  */
3058 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3059 {
3060     TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3061
3062     if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
3063         {
3064                 return DISP_E_OVERFLOW;
3065         }
3066
3067         *pdateOut = (DATE) fltIn;
3068
3069         return S_OK;
3070 }
3071
3072 /******************************************************************************
3073  *              VarDateFromR8           [OLEAUT32.92]
3074  */
3075 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3076 {
3077     TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3078
3079         if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3080         {
3081                 return DISP_E_OVERFLOW;
3082         }
3083
3084         *pdateOut = (DATE) dblIn;
3085
3086         return S_OK;
3087 }
3088
3089 /******************************************************************************
3090  *              VarDateFromStr          [OLEAUT32.94]
3091  * The string representing the date is composed of two parts, a date and time.
3092  *
3093  * The format of the time is has follows:
3094  * hh[:mm][:ss][AM|PM]
3095  * Whitespace can be inserted anywhere between these tokens.  A whitespace consists
3096  * of space and/or tab characters, which are ignored.
3097  *
3098  * The formats for the date part are has follows:
3099  * mm/[dd/][yy]yy
3100  * [dd/]mm/[yy]yy
3101  * [yy]yy/mm/dd
3102  * January dd[,] [yy]yy
3103  * dd January [yy]yy
3104  * [yy]yy January dd
3105  * Whitespace can be inserted anywhere between these tokens.
3106  *
3107  * The formats for the date and time string are has follows.
3108  * date[whitespace][time]
3109  * [time][whitespace]date
3110  *
3111  * These are the only characters allowed in a string representing a date and time:
3112  * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3113  */
3114 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3115 {
3116     HRESULT ret = S_OK;
3117     struct tm TM;
3118
3119     memset( &TM, 0, sizeof(TM) );
3120
3121     TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3122
3123     if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
3124     {
3125         if( TmToDATE( &TM, pdateOut ) == FALSE )
3126         {
3127             ret = E_INVALIDARG;
3128         }
3129     }
3130     else
3131     {
3132         ret = DISP_E_TYPEMISMATCH;
3133     }
3134
3135
3136         return ret;
3137 }
3138
3139 /******************************************************************************
3140  *              VarDateFromI1           [OLEAUT32.221]
3141  */
3142 HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
3143 {
3144         TRACE("( %c, %p ), stub\n", cIn, pdateOut );
3145
3146         *pdateOut = (DATE) cIn;
3147
3148         return S_OK;
3149 }
3150
3151 /******************************************************************************
3152  *              VarDateFromUI2          [OLEAUT32.222]
3153  */
3154 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3155 {
3156         TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
3157
3158         if( uiIn > DATE_MAX )
3159         {
3160                 return DISP_E_OVERFLOW;
3161         }
3162
3163         *pdateOut = (DATE) uiIn;
3164
3165         return S_OK;
3166 }
3167
3168 /******************************************************************************
3169  *              VarDateFromUI4          [OLEAUT32.223]
3170  */
3171 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3172 {
3173         TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
3174
3175         if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3176         {
3177                 return DISP_E_OVERFLOW;
3178         }
3179
3180         *pdateOut = (DATE) ulIn;
3181
3182         return S_OK;
3183 }
3184
3185 /******************************************************************************
3186  *              VarDateFromBool         [OLEAUT32.96]
3187  */
3188 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3189 {
3190         TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
3191
3192         *pdateOut = (DATE) boolIn;
3193
3194         return S_OK;
3195 }
3196
3197 /**********************************************************************
3198  *              VarDateFromCy [OLEAUT32.93]
3199  * Convert currency to date
3200  */
3201 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
3202    *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3203
3204    if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3205    return S_OK;
3206 }
3207
3208 /******************************************************************************
3209  *              VarBstrFromUI1          [OLEAUT32.108]
3210  */
3211 HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3212 {
3213         TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3214         sprintf( pBuffer, "%d", bVal );
3215
3216         *pbstrOut =  StringDupAtoBstr( pBuffer );
3217
3218         return S_OK;
3219 }
3220
3221 /******************************************************************************
3222  *              VarBstrFromI2           [OLEAUT32.109]
3223  */
3224 HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3225 {
3226         TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3227         sprintf( pBuffer, "%d", iVal );
3228         *pbstrOut = StringDupAtoBstr( pBuffer );
3229
3230         return S_OK;
3231 }
3232
3233 /******************************************************************************
3234  *              VarBstrFromI4           [OLEAUT32.110]
3235  */
3236 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3237 {
3238         TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
3239
3240         sprintf( pBuffer, "%ld", lIn );
3241         *pbstrOut = StringDupAtoBstr( pBuffer );
3242
3243         return S_OK;
3244 }
3245
3246 /******************************************************************************
3247  *              VarBstrFromR4           [OLEAUT32.111]
3248  */
3249 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3250 {
3251         TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
3252
3253         sprintf( pBuffer, "%.7g", fltIn );
3254         *pbstrOut = StringDupAtoBstr( pBuffer );
3255
3256         return S_OK;
3257 }
3258
3259 /******************************************************************************
3260  *              VarBstrFromR8           [OLEAUT32.112]
3261  */
3262 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3263 {
3264         TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
3265
3266         sprintf( pBuffer, "%.15g", dblIn );
3267         *pbstrOut = StringDupAtoBstr( pBuffer );
3268
3269         return S_OK;
3270 }
3271
3272 /******************************************************************************
3273  *    VarBstrFromCy   [OLEAUT32.113]
3274  */
3275 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
3276         FIXME("([cyIn], %08lx, %08lx, %p), stub.\n", lcid, dwFlags, pbstrOut);
3277         return E_NOTIMPL;
3278 }
3279
3280
3281 /******************************************************************************
3282  *              VarBstrFromDate         [OLEAUT32.114]
3283  *
3284  * The date is implemented using an 8 byte floating-point number.
3285  * Days are represented by whole numbers increments starting with 0.00 as
3286  * being December 30 1899, midnight.
3287  * The hours are expressed as the fractional part of the number.
3288  * December 30 1899 at midnight = 0.00
3289  * January 1 1900 at midnight = 2.00
3290  * January 4 1900 at 6 AM = 5.25
3291  * January 4 1900 at noon = 5.50
3292  * December 29 1899 at midnight = -1.00
3293  * December 18 1899 at midnight = -12.00
3294  * December 18 1899 at 6AM = -12.25
3295  * December 18 1899 at 6PM = -12.75
3296  * December 19 1899 at midnight = -11.00
3297  * The tm structure is as follows:
3298  * struct tm {
3299  *                int tm_sec;      seconds after the minute - [0,59]
3300  *                int tm_min;      minutes after the hour - [0,59]
3301  *                int tm_hour;     hours since midnight - [0,23]
3302  *                int tm_mday;     day of the month - [1,31]
3303  *                int tm_mon;      months since January - [0,11]
3304  *                int tm_year;     years
3305  *                int tm_wday;     days since Sunday - [0,6]
3306  *                int tm_yday;     days since January 1 - [0,365]
3307  *                int tm_isdst;    daylight savings time flag
3308  *                };
3309  */
3310 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3311 {
3312     struct tm TM;
3313     memset( &TM, 0, sizeof(TM) );
3314
3315     TRACE("( %f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
3316
3317     if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
3318                         {
3319         return E_INVALIDARG;
3320                 }
3321
3322     if( dwFlags & VAR_DATEVALUEONLY )
3323                         strftime( pBuffer, BUFFER_MAX, "%x", &TM );
3324     else if( dwFlags & VAR_TIMEVALUEONLY )
3325                         strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3326                 else
3327         strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3328
3329                 *pbstrOut = StringDupAtoBstr( pBuffer );
3330
3331         return S_OK;
3332 }
3333
3334 /******************************************************************************
3335  *              VarBstrFromBool         [OLEAUT32.116]
3336  */
3337 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3338 {
3339         TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
3340
3341         sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
3342
3343         *pbstrOut = StringDupAtoBstr( pBuffer );
3344
3345         return S_OK;
3346 }
3347
3348 /******************************************************************************
3349  *              VarBstrFromI1           [OLEAUT32.229]
3350  */
3351 HRESULT WINAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3352 {
3353         TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3354         sprintf( pBuffer, "%d", cIn );
3355         *pbstrOut = StringDupAtoBstr( pBuffer );
3356
3357         return S_OK;
3358 }
3359
3360 /******************************************************************************
3361  *              VarBstrFromUI2          [OLEAUT32.230]
3362  */
3363 HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3364 {
3365         TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3366         sprintf( pBuffer, "%d", uiIn );
3367         *pbstrOut = StringDupAtoBstr( pBuffer );
3368
3369         return S_OK;
3370 }
3371
3372 /******************************************************************************
3373  *              VarBstrFromUI4          [OLEAUT32.231]
3374  */
3375 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3376 {
3377         TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3378         sprintf( pBuffer, "%ld", ulIn );
3379         *pbstrOut = StringDupAtoBstr( pBuffer );
3380
3381         return S_OK;
3382 }
3383
3384 /******************************************************************************
3385  *              VarBoolFromUI1          [OLEAUT32.118]
3386  */
3387 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3388 {
3389         TRACE("( %d, %p ), stub\n", bIn, pboolOut );
3390
3391         if( bIn == 0 )
3392         {
3393                 *pboolOut = VARIANT_FALSE;
3394         }
3395         else
3396         {
3397                 *pboolOut = VARIANT_TRUE;
3398         }
3399
3400         return S_OK;
3401 }
3402
3403 /******************************************************************************
3404  *              VarBoolFromI2           [OLEAUT32.119]
3405  */
3406 HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3407 {
3408         TRACE("( %d, %p ), stub\n", sIn, pboolOut );
3409
3410         *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
3411
3412         return S_OK;
3413 }
3414
3415 /******************************************************************************
3416  *              VarBoolFromI4           [OLEAUT32.120]
3417  */
3418 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3419 {
3420         TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
3421
3422         *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
3423
3424         return S_OK;
3425 }
3426
3427 /******************************************************************************
3428  *              VarBoolFromR4           [OLEAUT32.121]
3429  */
3430 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3431 {
3432         TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
3433
3434         *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3435
3436         return S_OK;
3437 }
3438
3439 /******************************************************************************
3440  *              VarBoolFromR8           [OLEAUT32.122]
3441  */
3442 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3443 {
3444         TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
3445
3446         *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3447
3448         return S_OK;
3449 }
3450
3451 /******************************************************************************
3452  *              VarBoolFromDate         [OLEAUT32.123]
3453  */
3454 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3455 {
3456         TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
3457
3458         *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3459
3460         return S_OK;
3461 }
3462
3463 /******************************************************************************
3464  *              VarBoolFromStr          [OLEAUT32.125]
3465  */
3466 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3467 {
3468         HRESULT ret = S_OK;
3469         char* pNewString = NULL;
3470
3471         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
3472
3473     pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3474
3475         if( pNewString == NULL || strlen( pNewString ) == 0 )
3476         {
3477                 ret = DISP_E_TYPEMISMATCH;
3478         }
3479
3480         if( ret == S_OK )
3481         {
3482                 if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
3483                 {
3484                         *pboolOut = VARIANT_TRUE;
3485                 }
3486                 else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
3487                 {
3488                         *pboolOut = VARIANT_FALSE;
3489                 }
3490                 else
3491                 {
3492                         /* Try converting the string to a floating point number.
3493                          */
3494                         double dValue = 0.0;
3495                         HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3496                         if( res != S_OK )
3497                         {
3498                                 ret = DISP_E_TYPEMISMATCH;
3499                         }
3500                         else
3501                                 *pboolOut = (dValue == 0.0) ?
3502                                                 VARIANT_FALSE : VARIANT_TRUE;
3503                 }
3504         }
3505
3506         HeapFree( GetProcessHeap(), 0, pNewString );
3507
3508         return ret;
3509 }
3510
3511 /******************************************************************************
3512  *              VarBoolFromI1           [OLEAUT32.233]
3513  */
3514 HRESULT WINAPI VarBoolFromI1(CHAR cIn, VARIANT_BOOL* pboolOut)
3515 {
3516         TRACE("( %c, %p ), stub\n", cIn, pboolOut );
3517
3518         *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3519
3520         return S_OK;
3521 }
3522
3523 /******************************************************************************
3524  *              VarBoolFromUI2          [OLEAUT32.234]
3525  */
3526 HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3527 {
3528         TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
3529
3530         *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3531
3532         return S_OK;
3533 }
3534
3535 /******************************************************************************
3536  *              VarBoolFromUI4          [OLEAUT32.235]
3537  */
3538 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3539 {
3540         TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
3541
3542         *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3543
3544         return S_OK;
3545 }
3546
3547 /**********************************************************************
3548  *              VarBoolFromCy [OLEAUT32.124]
3549  * Convert currency to boolean
3550  */
3551 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
3552       if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
3553       else *pboolOut = 0;
3554
3555       return S_OK;
3556 }
3557
3558 /******************************************************************************
3559  *              VarI1FromUI1            [OLEAUT32.244]
3560  */
3561 HRESULT WINAPI VarI1FromUI1(BYTE bIn, CHAR* pcOut)
3562 {
3563         TRACE("( %d, %p ), stub\n", bIn, pcOut );
3564
3565         /* Check range of value.
3566          */
3567         if( bIn > CHAR_MAX )
3568         {
3569                 return DISP_E_OVERFLOW;
3570         }
3571
3572         *pcOut = (CHAR) bIn;
3573
3574         return S_OK;
3575 }
3576
3577 /******************************************************************************
3578  *              VarI1FromI2             [OLEAUT32.245]
3579  */
3580 HRESULT WINAPI VarI1FromI2(short uiIn, CHAR* pcOut)
3581 {
3582         TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3583
3584         if( uiIn > CHAR_MAX )
3585         {
3586                 return DISP_E_OVERFLOW;
3587         }
3588
3589         *pcOut = (CHAR) uiIn;
3590
3591         return S_OK;
3592 }
3593
3594 /******************************************************************************
3595  *              VarI1FromI4             [OLEAUT32.246]
3596  */
3597 HRESULT WINAPI VarI1FromI4(LONG lIn, CHAR* pcOut)
3598 {
3599         TRACE("( %ld, %p ), stub\n", lIn, pcOut );
3600
3601         if( lIn < CHAR_MIN || lIn > CHAR_MAX )
3602         {
3603                 return DISP_E_OVERFLOW;
3604         }
3605
3606         *pcOut = (CHAR) lIn;
3607
3608         return S_OK;
3609 }
3610
3611 /******************************************************************************
3612  *              VarI1FromR4             [OLEAUT32.247]
3613  */
3614 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, CHAR* pcOut)
3615 {
3616         TRACE("( %f, %p ), stub\n", fltIn, pcOut );
3617
3618     fltIn = round( fltIn );
3619         if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
3620         {
3621                 return DISP_E_OVERFLOW;
3622         }
3623
3624         *pcOut = (CHAR) fltIn;
3625
3626         return S_OK;
3627 }
3628
3629 /******************************************************************************
3630  *              VarI1FromR8             [OLEAUT32.248]
3631  */
3632 HRESULT WINAPI VarI1FromR8(double dblIn, CHAR* pcOut)
3633 {
3634         TRACE("( %f, %p ), stub\n", dblIn, pcOut );
3635
3636     dblIn = round( dblIn );
3637     if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
3638         {
3639                 return DISP_E_OVERFLOW;
3640         }
3641
3642         *pcOut = (CHAR) dblIn;
3643
3644         return S_OK;
3645 }
3646
3647 /******************************************************************************
3648  *              VarI1FromDate           [OLEAUT32.249]
3649  */
3650 HRESULT WINAPI VarI1FromDate(DATE dateIn, CHAR* pcOut)
3651 {
3652         TRACE("( %f, %p ), stub\n", dateIn, pcOut );
3653
3654     dateIn = round( dateIn );
3655         if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
3656         {
3657                 return DISP_E_OVERFLOW;
3658         }
3659
3660         *pcOut = (CHAR) dateIn;
3661
3662         return S_OK;
3663 }
3664
3665 /******************************************************************************
3666  *              VarI1FromStr            [OLEAUT32.251]
3667  */
3668 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CHAR* pcOut)
3669 {
3670         double dValue = 0.0;
3671         LPSTR pNewString = NULL;
3672
3673         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
3674
3675         /* Check if we have a valid argument
3676          */
3677         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3678         RemoveCharacterFromString( pNewString, "," );
3679         if( IsValidRealString( pNewString ) == FALSE )
3680         {
3681                 return DISP_E_TYPEMISMATCH;
3682         }
3683
3684         /* Convert the valid string to a floating point number.
3685          */
3686         dValue = atof( pNewString );
3687
3688         /* We don't need the string anymore so free it.
3689          */
3690         HeapFree( GetProcessHeap(), 0, pNewString );
3691
3692         /* Check range of value.
3693      */
3694     dValue = round( dValue );
3695         if( dValue < CHAR_MIN || dValue > CHAR_MAX )
3696         {
3697                 return DISP_E_OVERFLOW;
3698         }
3699
3700         *pcOut = (CHAR) dValue;
3701
3702         return S_OK;
3703 }
3704
3705 /******************************************************************************
3706  *              VarI1FromBool           [OLEAUT32.253]
3707  */
3708 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
3709 {
3710         TRACE("( %d, %p ), stub\n", boolIn, pcOut );
3711
3712         *pcOut = (CHAR) boolIn;
3713
3714         return S_OK;
3715 }
3716
3717 /******************************************************************************
3718  *              VarI1FromUI2            [OLEAUT32.254]
3719  */
3720 HRESULT WINAPI VarI1FromUI2(USHORT uiIn, CHAR* pcOut)
3721 {
3722         TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3723
3724         if( uiIn > CHAR_MAX )
3725         {
3726                 return DISP_E_OVERFLOW;
3727         }
3728
3729         *pcOut = (CHAR) uiIn;
3730
3731         return S_OK;
3732 }
3733
3734 /******************************************************************************
3735  *              VarI1FromUI4            [OLEAUT32.255]
3736  */
3737 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, CHAR* pcOut)
3738 {
3739         TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
3740
3741         if( ulIn > CHAR_MAX )
3742         {
3743                 return DISP_E_OVERFLOW;
3744         }
3745
3746         *pcOut = (CHAR) ulIn;
3747
3748         return S_OK;
3749 }
3750
3751 /**********************************************************************
3752  *              VarI1FromCy [OLEAUT32.250]
3753  * Convert currency to signed char
3754  */
3755 HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
3756    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3757
3758    if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
3759
3760    *pcOut = (CHAR)t;
3761    return S_OK;
3762 }
3763
3764 /******************************************************************************
3765  *              VarUI2FromUI1           [OLEAUT32.257]
3766  */
3767 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
3768 {
3769         TRACE("( %d, %p ), stub\n", bIn, puiOut );
3770
3771         *puiOut = (USHORT) bIn;
3772
3773         return S_OK;
3774 }
3775
3776 /******************************************************************************
3777  *              VarUI2FromI2            [OLEAUT32.258]
3778  */
3779 HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
3780 {
3781         TRACE("( %d, %p ), stub\n", uiIn, puiOut );
3782
3783         if( uiIn < UI2_MIN )
3784         {
3785                 return DISP_E_OVERFLOW;
3786         }
3787
3788         *puiOut = (USHORT) uiIn;
3789
3790         return S_OK;
3791 }
3792
3793 /******************************************************************************
3794  *              VarUI2FromI4            [OLEAUT32.259]
3795  */
3796 HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
3797 {
3798         TRACE("( %ld, %p ), stub\n", lIn, puiOut );
3799
3800         if( lIn < UI2_MIN || lIn > UI2_MAX )
3801         {
3802                 return DISP_E_OVERFLOW;
3803         }
3804
3805         *puiOut = (USHORT) lIn;
3806
3807         return S_OK;
3808 }
3809
3810 /******************************************************************************
3811  *              VarUI2FromR4            [OLEAUT32.260]
3812  */
3813 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
3814 {
3815         TRACE("( %f, %p ), stub\n", fltIn, puiOut );
3816
3817     fltIn = round( fltIn );
3818         if( fltIn < UI2_MIN || fltIn > UI2_MAX )
3819         {
3820                 return DISP_E_OVERFLOW;
3821         }
3822
3823         *puiOut = (USHORT) fltIn;
3824
3825         return S_OK;
3826 }
3827
3828 /******************************************************************************
3829  *              VarUI2FromR8            [OLEAUT32.261]
3830  */
3831 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
3832 {
3833         TRACE("( %f, %p ), stub\n", dblIn, puiOut );
3834
3835     dblIn = round( dblIn );
3836     if( dblIn < UI2_MIN || dblIn > UI2_MAX )
3837         {
3838                 return DISP_E_OVERFLOW;
3839         }
3840
3841         *puiOut = (USHORT) dblIn;
3842
3843         return S_OK;
3844 }
3845
3846 /******************************************************************************
3847  *              VarUI2FromDate          [OLEAUT32.262]
3848  */
3849 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
3850 {
3851         TRACE("( %f, %p ), stub\n", dateIn, puiOut );
3852
3853     dateIn = round( dateIn );
3854         if( dateIn < UI2_MIN || dateIn > UI2_MAX )
3855         {
3856                 return DISP_E_OVERFLOW;
3857         }
3858
3859         *puiOut = (USHORT) dateIn;
3860
3861         return S_OK;
3862 }
3863
3864 /******************************************************************************
3865  *              VarUI2FromStr           [OLEAUT32.264]
3866  */
3867 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
3868 {
3869         double dValue = 0.0;
3870         LPSTR pNewString = NULL;
3871
3872         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
3873
3874         /* Check if we have a valid argument
3875          */
3876         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3877         RemoveCharacterFromString( pNewString, "," );
3878         if( IsValidRealString( pNewString ) == FALSE )
3879         {
3880                 return DISP_E_TYPEMISMATCH;
3881         }
3882
3883         /* Convert the valid string to a floating point number.
3884          */
3885         dValue = atof( pNewString );
3886
3887         /* We don't need the string anymore so free it.
3888          */
3889         HeapFree( GetProcessHeap(), 0, pNewString );
3890
3891         /* Check range of value.
3892      */
3893     dValue = round( dValue );
3894         if( dValue < UI2_MIN || dValue > UI2_MAX )
3895         {
3896                 return DISP_E_OVERFLOW;
3897         }
3898
3899         *puiOut = (USHORT) dValue;
3900
3901         return S_OK;
3902 }
3903
3904 /******************************************************************************
3905  *              VarUI2FromBool          [OLEAUT32.266]
3906  */
3907 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
3908 {
3909         TRACE("( %d, %p ), stub\n", boolIn, puiOut );
3910
3911         *puiOut = (USHORT) boolIn;
3912
3913         return S_OK;
3914 }
3915
3916 /******************************************************************************
3917  *              VarUI2FromI1            [OLEAUT32.267]
3918  */
3919 HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
3920 {
3921         TRACE("( %c, %p ), stub\n", cIn, puiOut );
3922
3923         *puiOut = (USHORT) cIn;
3924
3925         return S_OK;
3926 }
3927
3928 /******************************************************************************
3929  *              VarUI2FromUI4           [OLEAUT32.268]
3930  */
3931 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
3932 {
3933         TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
3934
3935         if( ulIn < UI2_MIN || ulIn > UI2_MAX )
3936         {
3937                 return DISP_E_OVERFLOW;
3938         }
3939
3940         *puiOut = (USHORT) ulIn;
3941
3942         return S_OK;
3943 }
3944
3945 /******************************************************************************
3946  *              VarUI4FromStr           [OLEAUT32.277]
3947  */
3948 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
3949 {
3950         double dValue = 0.0;
3951         LPSTR pNewString = NULL;
3952
3953         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
3954
3955         /* Check if we have a valid argument
3956          */
3957         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3958         RemoveCharacterFromString( pNewString, "," );
3959         if( IsValidRealString( pNewString ) == FALSE )
3960         {
3961                 return DISP_E_TYPEMISMATCH;
3962         }
3963
3964         /* Convert the valid string to a floating point number.
3965          */
3966         dValue = atof( pNewString );
3967
3968         /* We don't need the string anymore so free it.
3969          */
3970         HeapFree( GetProcessHeap(), 0, pNewString );
3971
3972         /* Check range of value.
3973      */
3974     dValue = round( dValue );
3975         if( dValue < UI4_MIN || dValue > UI4_MAX )
3976         {
3977                 return DISP_E_OVERFLOW;
3978         }
3979
3980         *pulOut = (ULONG) dValue;
3981
3982         return S_OK;
3983 }
3984
3985 /**********************************************************************
3986  *              VarUI2FromCy [OLEAUT32.263]
3987  * Convert currency to unsigned short
3988  */
3989 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
3990    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3991
3992    if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
3993
3994    *pusOut = (USHORT)t;
3995
3996    return S_OK;
3997 }
3998
3999 /******************************************************************************
4000  *              VarUI4FromUI1           [OLEAUT32.270]
4001  */
4002 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
4003 {
4004         TRACE("( %d, %p ), stub\n", bIn, pulOut );
4005
4006         *pulOut = (USHORT) bIn;
4007
4008         return S_OK;
4009 }
4010
4011 /******************************************************************************
4012  *              VarUI4FromI2            [OLEAUT32.271]
4013  */
4014 HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
4015 {
4016         TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4017
4018         if( uiIn < UI4_MIN )
4019         {
4020                 return DISP_E_OVERFLOW;
4021         }
4022
4023         *pulOut = (ULONG) uiIn;
4024
4025         return S_OK;
4026 }
4027
4028 /******************************************************************************
4029  *              VarUI4FromI4            [OLEAUT32.272]
4030  */
4031 HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
4032 {
4033         TRACE("( %ld, %p ), stub\n", lIn, pulOut );
4034
4035         if( lIn < UI4_MIN )
4036         {
4037                 return DISP_E_OVERFLOW;
4038         }
4039
4040         *pulOut = (ULONG) lIn;
4041
4042         return S_OK;
4043 }
4044
4045 /******************************************************************************
4046  *              VarUI4FromR4            [OLEAUT32.273]
4047  */
4048 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
4049 {
4050     fltIn = round( fltIn );
4051     if( fltIn < UI4_MIN || fltIn > UI4_MAX )
4052         {
4053                 return DISP_E_OVERFLOW;
4054         }
4055
4056         *pulOut = (ULONG) fltIn;
4057
4058         return S_OK;
4059 }
4060
4061 /******************************************************************************
4062  *              VarUI4FromR8            [OLEAUT32.274]
4063  */
4064 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
4065 {
4066         TRACE("( %f, %p ), stub\n", dblIn, pulOut );
4067
4068         dblIn = round( dblIn );
4069         if( dblIn < UI4_MIN || dblIn > UI4_MAX )
4070         {
4071                 return DISP_E_OVERFLOW;
4072         }
4073
4074         *pulOut = (ULONG) dblIn;
4075
4076         return S_OK;
4077 }
4078
4079 /******************************************************************************
4080  *              VarUI4FromDate          [OLEAUT32.275]
4081  */
4082 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
4083 {
4084         TRACE("( %f, %p ), stub\n", dateIn, pulOut );
4085
4086         dateIn = round( dateIn );
4087         if( dateIn < UI4_MIN || dateIn > UI4_MAX )
4088         {
4089                 return DISP_E_OVERFLOW;
4090         }
4091
4092         *pulOut = (ULONG) dateIn;
4093
4094         return S_OK;
4095 }
4096
4097 /******************************************************************************
4098  *              VarUI4FromBool          [OLEAUT32.279]
4099  */
4100 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
4101 {
4102         TRACE("( %d, %p ), stub\n", boolIn, pulOut );
4103
4104         *pulOut = (ULONG) boolIn;
4105
4106         return S_OK;
4107 }
4108
4109 /******************************************************************************
4110  *              VarUI4FromI1            [OLEAUT32.280]
4111  */
4112 HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
4113 {
4114         TRACE("( %c, %p ), stub\n", cIn, pulOut );
4115
4116         *pulOut = (ULONG) cIn;
4117
4118         return S_OK;
4119 }
4120
4121 /******************************************************************************
4122  *              VarUI4FromUI2           [OLEAUT32.281]
4123  */
4124 HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4125 {
4126         TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4127
4128         *pulOut = (ULONG) uiIn;
4129
4130         return S_OK;
4131 }
4132
4133 /**********************************************************************
4134  *              VarUI4FromCy [OLEAUT32.276]
4135  * Convert currency to unsigned long
4136  */
4137 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
4138    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4139
4140    if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4141
4142    *pulOut = (ULONG)t;
4143
4144    return S_OK;
4145 }
4146
4147 /**********************************************************************
4148  *              VarCyFromUI1 [OLEAUT32.98]
4149  * Convert unsigned char to currency
4150  */
4151 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
4152     pcyOut->s.Hi = 0;
4153     pcyOut->s.Lo = ((ULONG)bIn) * 10000;
4154
4155     return S_OK;
4156 }
4157
4158 /**********************************************************************
4159  *              VarCyFromI2 [OLEAUT32.99]
4160  * Convert signed short to currency
4161  */
4162 HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
4163     if (sIn < 0) pcyOut->s.Hi = -1;
4164     else pcyOut->s.Hi = 0;
4165     pcyOut->s.Lo = ((ULONG)sIn) * 10000;
4166
4167     return S_OK;
4168 }
4169
4170 /**********************************************************************
4171  *              VarCyFromI4 [OLEAUT32.100]
4172  * Convert signed long to currency
4173  */
4174 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4175       double t = (double)lIn * (double)10000;
4176       pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4177       pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4178       if (lIn < 0) pcyOut->s.Hi--;
4179
4180       return S_OK;
4181 }
4182
4183 /**********************************************************************
4184  *              VarCyFromR4 [OLEAUT32.101]
4185  * Convert float to currency
4186  */
4187 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
4188    double t = round((double)fltIn * (double)10000);
4189    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4190    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4191    if (fltIn < 0) pcyOut->s.Hi--;
4192
4193    return S_OK;
4194 }
4195
4196 /**********************************************************************
4197  *              VarCyFromR8 [OLEAUT32.102]
4198  * Convert double to currency
4199  */
4200 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
4201    double t = round(dblIn * (double)10000);
4202    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4203    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4204    if (dblIn < 0) pcyOut->s.Hi--;
4205
4206    return S_OK;
4207 }
4208
4209 /**********************************************************************
4210  *              VarCyFromDate [OLEAUT32.103]
4211  * Convert date to currency
4212  */
4213 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
4214    double t = round((double)dateIn * (double)10000);
4215    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4216    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4217    if (dateIn < 0) pcyOut->s.Hi--;
4218
4219    return S_OK;
4220 }
4221
4222 /**********************************************************************
4223  *              VarCyFromStr [OLEAUT32.104]
4224  */
4225 HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
4226         FIXME("(%p, %08lx, %08lx, %p), stub.\n", strIn, lcid, dwFlags, pcyOut);
4227         return E_NOTIMPL;
4228 }
4229
4230
4231 /**********************************************************************
4232  *              VarCyFromBool [OLEAUT32.106]
4233  * Convert boolean to currency
4234  */
4235 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
4236    if (boolIn < 0) pcyOut->s.Hi = -1;
4237    else pcyOut->s.Hi = 0;
4238    pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
4239
4240    return S_OK;
4241 }
4242
4243 /**********************************************************************
4244  *              VarCyFromI1 [OLEAUT32.225]
4245  * Convert signed char to currency
4246  */
4247 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
4248    if (cIn < 0) pcyOut->s.Hi = -1;
4249    else pcyOut->s.Hi = 0;
4250    pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
4251
4252    return S_OK;
4253 }
4254
4255 /**********************************************************************
4256  *              VarCyFromUI2 [OLEAUT32.226]
4257  * Convert unsigned short to currency
4258  */
4259 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
4260    pcyOut->s.Hi = 0;
4261    pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
4262
4263    return S_OK;
4264 }
4265
4266 /**********************************************************************
4267  *              VarCyFromUI4 [OLEAUT32.227]
4268  * Convert unsigned long to currency
4269  */
4270 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4271    double t = (double)ulIn * (double)10000;
4272    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4273    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4274
4275    return S_OK;
4276 }
4277
4278
4279 /**********************************************************************
4280  *              DosDateTimeToVariantTime [OLEAUT32.14]
4281  * Convert dos representation of time to the date and time representation
4282  * stored in a variant.
4283  */
4284 INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4285                                     DATE *pvtime)
4286 {
4287     struct tm t;
4288
4289     TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
4290
4291     t.tm_sec = (wDosTime & 0x001f) * 2;
4292     t.tm_min = (wDosTime & 0x07e0) >> 5;
4293     t.tm_hour = (wDosTime & 0xf800) >> 11;
4294
4295     t.tm_mday = (wDosDate & 0x001f);
4296     t.tm_mon = (wDosDate & 0x01e0) >> 5;
4297     t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
4298
4299     return TmToDATE( &t, pvtime );
4300 }
4301
4302
4303 /**********************************************************************
4304  *              VarParseNumFromStr [OLEAUT32.46]
4305  */
4306 HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
4307                                   NUMPARSE * pnumprs, BYTE * rgbDig)
4308 {
4309     int i,lastent=0;
4310     int cDig;
4311     FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
4312     FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
4313
4314     /* The other struct components are to be set by us */
4315
4316     memset(rgbDig,0,pnumprs->cDig);
4317
4318     cDig = 0;
4319     for (i=0; strIn[i] ;i++) {
4320         if ((strIn[i]>='0') && (strIn[i]<='9')) {
4321             if (pnumprs->cDig > cDig) {
4322                 *(rgbDig++)=strIn[i]-'0';
4323                 cDig++;
4324                 lastent = i;
4325             }
4326         }
4327     }
4328     pnumprs->cDig       = cDig;
4329
4330     /* FIXME: Just patching some values in */
4331     pnumprs->nPwr10     = 0;
4332     pnumprs->nBaseShift = 0;
4333     pnumprs->cchUsed    = lastent;
4334     pnumprs->dwOutFlags = NUMPRS_DECIMAL;
4335     return S_OK;
4336 }
4337
4338
4339 /**********************************************************************
4340  *              VarNumFromParseNum [OLEAUT32.47]
4341  */
4342 HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
4343                                   ULONG dwVtBits, VARIANT * pvar)
4344 {
4345     DWORD xint;
4346     int i;
4347     FIXME("(,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
4348
4349     xint = 0;
4350     for (i=0;i<pnumprs->cDig;i++)
4351         xint = xint*10 + rgbDig[i];
4352
4353     VariantInit(pvar);
4354     if (dwVtBits & VTBIT_I4) {
4355         V_VT(pvar) = VT_I4;
4356         V_UNION(pvar,intVal) = xint;
4357         return S_OK;
4358     }
4359     if (dwVtBits & VTBIT_R8) {
4360         V_VT(pvar) = VT_R8;
4361         V_UNION(pvar,dblVal) = xint;
4362         return S_OK;
4363     } else {
4364         FIXME("vtbitmask is unsupported %lx\n",dwVtBits);
4365         return E_FAIL;
4366     }
4367 }
4368
4369
4370 /**********************************************************************
4371  *              VariantTimeToDosDateTime [OLEAUT32.13]
4372  * Convert variant representation of time to the date and time representation
4373  * stored in dos.
4374  */
4375 INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
4376 {
4377     struct tm t;
4378     *wDosTime = 0;
4379     *wDosDate = 0;
4380
4381     TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate, *wDosTime, &pvtime );
4382
4383     if (DateToTm(pvtime, 0, &t) < 0) return 0;
4384
4385     *wDosTime = *wDosTime | (t.tm_sec / 2);
4386     *wDosTime = *wDosTime | (t.tm_min << 5);
4387     *wDosTime = *wDosTime | (t.tm_hour << 11);
4388
4389     *wDosDate = *wDosDate | t.tm_mday ;
4390     *wDosDate = *wDosDate | t.tm_mon << 5;
4391     *wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
4392
4393     return 1;
4394 }
4395
4396
4397 /***********************************************************************
4398  *              SystemTimeToVariantTime [OLEAUT32.184]
4399  */
4400 HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME  lpSystemTime, double *pvtime )
4401 {
4402     static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4403     static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4404
4405     struct tm t;
4406
4407     TRACE(" %d/%d/%d %d:%d:%d\n",
4408           lpSystemTime->wMonth, lpSystemTime->wDay,
4409           lpSystemTime->wYear, lpSystemTime->wHour,
4410           lpSystemTime->wMinute, lpSystemTime->wSecond);
4411
4412     if (lpSystemTime->wYear >= 1900)
4413     {
4414         t.tm_sec = lpSystemTime->wSecond;
4415         t.tm_min = lpSystemTime->wMinute;
4416         t.tm_hour = lpSystemTime->wHour;
4417
4418         t.tm_mday = lpSystemTime->wDay;
4419         t.tm_mon = lpSystemTime->wMonth;
4420         t.tm_year = lpSystemTime->wYear;
4421
4422         return TmToDATE( &t, pvtime );
4423     }
4424     else
4425     {
4426         t.tm_sec = lpSystemTime->wSecond;
4427         t.tm_min = lpSystemTime->wMinute;
4428         t.tm_hour = lpSystemTime->wHour;
4429
4430         if (isleap(lpSystemTime->wYear) )
4431             t.tm_mday = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - lpSystemTime->wDay;
4432         else
4433             t.tm_mday = Days_Per_Month[13 - lpSystemTime->wMonth] - lpSystemTime->wDay;
4434
4435         t.tm_mon = 13 - lpSystemTime->wMonth;
4436         t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
4437
4438         TmToDATE( &t, pvtime );
4439
4440         *pvtime *= -1;
4441
4442         return 1;
4443     }
4444
4445     return 0;
4446 }
4447
4448 /***********************************************************************
4449  *              VariantTimeToSystemTime [OLEAUT32.185]
4450  */
4451 HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME  lpSystemTime )
4452 {
4453     double t = 0, timeofday = 0;
4454
4455     static const BYTE Days_Per_Month[] =    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4456     static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4457
4458     /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4459     static const BYTE Month_Code[] =    {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4460     static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4461
4462     /* The Century_Code is used to find the Day of the Week */
4463     static const BYTE Century_Code[]  = {0, 6, 4, 2};
4464
4465     struct tm r;
4466
4467     TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime);
4468
4469     if (vtime >= 0)
4470     {
4471
4472         if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4473
4474         lpSystemTime->wSecond = r.tm_sec;
4475         lpSystemTime->wMinute = r.tm_min;
4476         lpSystemTime->wHour = r.tm_hour;
4477         lpSystemTime->wDay = r.tm_mday;
4478         lpSystemTime->wMonth = r.tm_mon;
4479
4480         if (lpSystemTime->wMonth == 12)
4481             lpSystemTime->wMonth = 1;
4482         else
4483             lpSystemTime->wMonth++;
4484
4485         lpSystemTime->wYear = r.tm_year;
4486     }
4487     else
4488     {
4489         vtime = -1*vtime;
4490
4491         if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4492
4493         lpSystemTime->wSecond = r.tm_sec;
4494         lpSystemTime->wMinute = r.tm_min;
4495         lpSystemTime->wHour = r.tm_hour;
4496
4497         lpSystemTime->wMonth = 13 - r.tm_mon;
4498
4499         if (lpSystemTime->wMonth == 1)
4500             lpSystemTime->wMonth = 12;
4501         else
4502             lpSystemTime->wMonth--;
4503
4504         lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
4505
4506         if (!isleap(lpSystemTime->wYear) )
4507             lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
4508         else
4509             lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
4510
4511
4512     }
4513
4514     if (!isleap(lpSystemTime->wYear))
4515     {
4516         /*
4517           (Century_Code+Month_Code+Year_Code+Day) % 7
4518
4519           The century code repeats every 400 years , so the array
4520           works out like this,
4521
4522           Century_Code[0] is for 16th/20th Centry
4523           Century_Code[1] is for 17th/21th Centry
4524           Century_Code[2] is for 18th/22th Centry
4525           Century_Code[3] is for 19th/23th Centry
4526
4527           The year code is found with the formula (year + (year / 4))
4528           the "year" must be between 0 and 99 .
4529
4530           The Month Code (Month_Code[1]) starts with January and
4531           ends with December.
4532         */
4533
4534         lpSystemTime->wDayOfWeek = (
4535             Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
4536             ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4537             Month_Code[lpSystemTime->wMonth]+
4538             lpSystemTime->wDay) % 7;
4539
4540         if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4541         else lpSystemTime->wDayOfWeek -= 1;
4542     }
4543     else
4544     {
4545         lpSystemTime->wDayOfWeek = (
4546             Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
4547             ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4548             Month_Code_LY[lpSystemTime->wMonth]+
4549             lpSystemTime->wDay) % 7;
4550
4551         if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4552         else lpSystemTime->wDayOfWeek -= 1;
4553     }
4554
4555     t = floor(vtime);
4556     timeofday = vtime - t;
4557
4558     lpSystemTime->wMilliseconds = (timeofday
4559                                    - lpSystemTime->wHour*(1/24)
4560                                    - lpSystemTime->wMinute*(1/1440)
4561                                    - lpSystemTime->wSecond*(1/86400) )*(1/5184000);
4562
4563     return 1;
4564 }
4565
4566 /***********************************************************************
4567  *              VarUdateFromDate [OLEAUT32.331]
4568  */
4569 HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
4570 {
4571     HRESULT i = 0;
4572     static const BYTE Days_Per_Month[] =    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4573     static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4574
4575     TRACE("DATE = %f\n", (double)datein);
4576     i = VariantTimeToSystemTime(datein, &(pudateout->st) );
4577
4578     if (i)
4579     {
4580         pudateout->wDayOfYear = 0;
4581
4582         if (isleap(pudateout->st.wYear))
4583         {
4584             for (i =1; i<pudateout->st.wMonth; i++)
4585                 pudateout->wDayOfYear += Days_Per_Month[i];
4586         }
4587         else
4588         {
4589             for (i =1; i<pudateout->st.wMonth; i++)
4590                 pudateout->wDayOfYear += Days_Per_Month_LY[i];
4591         }
4592
4593         pudateout->wDayOfYear += pudateout->st.wDay;
4594         dwFlags = 0; /*VAR_VALIDDATE*/
4595     }
4596     else dwFlags = 0;
4597
4598     return i;
4599 }
4600
4601 /***********************************************************************
4602  *              VarDateFromUdate [OLEAUT32.330]
4603  */
4604 HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
4605                                 ULONG dwFlags, DATE *datein)
4606 {
4607     HRESULT i;
4608     double t = 0;
4609     TRACE(" %d/%d/%d %d:%d:%d\n",
4610           pudateout->st.wMonth, pudateout->st.wDay,
4611           pudateout->st.wYear, pudateout->st.wHour,
4612           pudateout->st.wMinute, pudateout->st.wSecond);
4613
4614
4615     i = SystemTimeToVariantTime(&(pudateout->st), &t);
4616     *datein = t;
4617
4618     if (i) dwFlags = 0; /*VAR_VALIDDATE*/
4619     else dwFlags = 0;
4620
4621     return i;
4622 }
4623
4624
4625 /**********************************************************************
4626  *              VarBstrCmp [OLEAUT32.440]
4627  *
4628  * flags can be:
4629  *   NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4630  *   NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4631  *
4632  */
4633 HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
4634 {
4635     DWORD r;
4636
4637     FIXME("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
4638
4639     if((!left) || (!right))
4640         return VARCMP_NULL;
4641
4642     if(flags&NORM_IGNORECASE)
4643         r = lstrcmpiW(left,right);
4644     else
4645         r = lstrcmpW(left,right);
4646
4647     if(r<0)
4648         return VARCMP_LT;
4649     if(r>0)
4650         return VARCMP_GT;
4651
4652     return VARCMP_EQ;
4653 }
4654
4655 /**********************************************************************
4656  *              VarBstrCat [OLEAUT32.439]
4657  */
4658 HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
4659 {
4660     BSTR result;
4661
4662     TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
4663
4664     if( (!left) || (!right) || (!out) )
4665         return 0;
4666
4667     result = SysAllocStringLen(left, lstrlenW(left)+lstrlenW(right));
4668     lstrcatW(result,right);
4669
4670     *out = result;
4671
4672     return 1;
4673 }
4674
4675 /**********************************************************************
4676  *              VarCat [OLEAUT32.441]
4677  */
4678 HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
4679 {
4680     /* Should we VariantClear out? */
4681     /* Can we handle array, vector, by ref etc. */
4682     if ((V_VT(left)&VT_TYPEMASK) == VT_NULL &&
4683         (V_VT(right)&VT_TYPEMASK) == VT_NULL)
4684     {
4685         V_VT(out) = VT_NULL;
4686         return S_OK;
4687     }
4688     else if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR)
4689     {
4690         V_VT(out) = VT_BSTR;
4691         VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out));
4692         return S_OK;
4693     }
4694     else
4695         FIXME ("types not supported\n");
4696     return S_OK;
4697 }