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