Ignore DSR/DTR flow control in DCB. termios doesn't support it.
[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_I1 ):
1021                         res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
1022                         break;
1023                 case( VT_I2 ):
1024                         res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
1025             break;
1026         case( VT_INT ):
1027         case( VT_I4 ):
1028             res = VariantCopy( pd, ps );
1029             break;
1030                 case( VT_UI1 ):
1031                         res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
1032                         break;
1033                 case( VT_UI2 ):
1034                         res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
1035                         break;
1036                 case( VT_UINT ):
1037                 case( VT_UI4 ):
1038                         res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
1039                         break;
1040                 case( VT_R4 ):
1041                         res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
1042                         break;
1043                 case( VT_R8 ):
1044                         res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
1045                         break;
1046                 case( VT_DATE ):
1047                         res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
1048                         break;
1049                 case( VT_BOOL ):
1050                         res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
1051                         break;
1052                 case( VT_BSTR ):
1053                         res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
1054                         break;
1055                 case( VT_CY ):
1056                         res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
1057                         break;
1058                 case( VT_DISPATCH ):
1059                         /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1060                 case( VT_DECIMAL ):
1061                         /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1062                 case( VT_UNKNOWN ):
1063                 default:
1064                         res = DISP_E_TYPEMISMATCH;
1065                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1066                         break;
1067                 }
1068                 break;
1069
1070         case( VT_UI1 ):
1071                 switch( vtFrom )
1072                 {
1073                 case( VT_I1 ):
1074                         res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
1075                         break;
1076                 case( VT_I2 ):
1077                         res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
1078                         break;
1079                 case( VT_INT ):
1080                 case( VT_I4 ):
1081                         res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
1082                         break;
1083         case( VT_UI1 ):
1084             res = VariantCopy( pd, ps );
1085             break;
1086                 case( VT_UI2 ):
1087                         res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
1088                         break;
1089                 case( VT_UINT ):
1090                 case( VT_UI4 ):
1091                         res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
1092                         break;
1093                 case( VT_R4 ):
1094                         res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
1095                         break;
1096                 case( VT_R8 ):
1097                         res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
1098                         break;
1099                 case( VT_DATE ):
1100                         res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
1101                         break;
1102                 case( VT_BOOL ):
1103                         res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
1104                         break;
1105                 case( VT_BSTR ):
1106                         res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
1107                         break;
1108                 case( VT_CY ):
1109                         res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
1110                         break;
1111                 case( VT_DISPATCH ):
1112                         /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1113                 case( VT_DECIMAL ):
1114                         /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1115                 case( VT_UNKNOWN ):
1116                 default:
1117                         res = DISP_E_TYPEMISMATCH;
1118                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1119                         break;
1120                 }
1121                 break;
1122
1123         case( VT_UI2 ):
1124                 switch( vtFrom )
1125                 {
1126                 case( VT_I1 ):
1127                         res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
1128                         break;
1129                 case( VT_I2 ):
1130                         res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
1131                         break;
1132                 case( VT_INT ):
1133                 case( VT_I4 ):
1134                         res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
1135                         break;
1136                 case( VT_UI1 ):
1137                         res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
1138                         break;
1139         case( VT_UI2 ):
1140             res = VariantCopy( pd, ps );
1141             break;
1142                 case( VT_UINT ):
1143                 case( VT_UI4 ):
1144                         res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
1145                         break;
1146                 case( VT_R4 ):
1147                         res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
1148                         break;
1149                 case( VT_R8 ):
1150                         res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
1151                         break;
1152                 case( VT_DATE ):
1153                         res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
1154                         break;
1155                 case( VT_BOOL ):
1156                         res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
1157                         break;
1158                 case( VT_BSTR ):
1159                         res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
1160                         break;
1161                 case( VT_CY ):
1162                         res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
1163                         break;
1164                 case( VT_DISPATCH ):
1165                         /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1166                 case( VT_DECIMAL ):
1167                         /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1168                 case( VT_UNKNOWN ):
1169                 default:
1170                         res = DISP_E_TYPEMISMATCH;
1171                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1172                         break;
1173                 }
1174                 break;
1175
1176         case( VT_UINT ):
1177         case( VT_UI4 ):
1178                 switch( vtFrom )
1179                 {
1180                 case( VT_I1 ):
1181                         res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
1182                         break;
1183                 case( VT_I2 ):
1184                         res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
1185                         break;
1186                 case( VT_INT ):
1187                 case( VT_I4 ):
1188                         res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
1189                         break;
1190                 case( VT_UI1 ):
1191                         res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
1192                         break;
1193                 case( VT_UI2 ):
1194                         res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
1195                         break;
1196         case( VT_UI4 ):
1197             res = VariantCopy( pd, ps );
1198             break;
1199                 case( VT_R4 ):
1200                         res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
1201                         break;
1202                 case( VT_R8 ):
1203                         res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
1204                         break;
1205                 case( VT_DATE ):
1206                         res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
1207                         break;
1208                 case( VT_BOOL ):
1209                         res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
1210                         break;
1211                 case( VT_BSTR ):
1212                         res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
1213                         break;
1214                 case( VT_CY ):
1215                         res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
1216                         break;
1217                 case( VT_DISPATCH ):
1218                         /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1219                 case( VT_DECIMAL ):
1220                         /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1221                 case( VT_UNKNOWN ):
1222                 default:
1223                         res = DISP_E_TYPEMISMATCH;
1224                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1225                         break;
1226                 }
1227                 break;
1228                 
1229         case( VT_R4 ):
1230                 switch( vtFrom )
1231                 {
1232                 case( VT_I1 ):
1233                         res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
1234                         break;
1235                 case( VT_I2 ):
1236                         res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
1237                         break;
1238                 case( VT_INT ):
1239                 case( VT_I4 ):
1240                         res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
1241                         break;
1242                 case( VT_UI1 ):
1243                         res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
1244                         break;
1245                 case( VT_UI2 ):
1246                         res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
1247                         break;
1248                 case( VT_UINT ):
1249                 case( VT_UI4 ):
1250                         res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
1251                         break;
1252         case( VT_R4 ):
1253             res = VariantCopy( pd, ps );
1254             break;
1255                 case( VT_R8 ):
1256                         res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
1257                         break;
1258                 case( VT_DATE ):
1259                         res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
1260                         break;
1261                 case( VT_BOOL ):
1262                         res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
1263                         break;
1264                 case( VT_BSTR ):
1265                         res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
1266                         break;
1267                 case( VT_CY ):
1268                         res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
1269                         break;
1270                 case( VT_DISPATCH ):
1271                         /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1272                 case( VT_DECIMAL ):
1273                         /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1274                 case( VT_UNKNOWN ):
1275                 default:
1276                         res = DISP_E_TYPEMISMATCH;
1277                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1278                         break;
1279                 }
1280                 break;
1281
1282         case( VT_R8 ):
1283                 switch( vtFrom )
1284                 {
1285                 case( VT_I1 ):
1286                         res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
1287                         break;
1288                 case( VT_I2 ):
1289                         res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
1290                         break;
1291                 case( VT_INT ):
1292                 case( VT_I4 ):
1293                         res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
1294                         break;
1295                 case( VT_UI1 ):
1296                         res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
1297                         break;
1298                 case( VT_UI2 ):
1299                         res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
1300                         break;
1301                 case( VT_UINT ):
1302                 case( VT_UI4 ):
1303                         res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
1304                         break;
1305                 case( VT_R4 ):
1306                         res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
1307                         break;
1308         case( VT_R8 ):
1309             res = VariantCopy( pd, ps );
1310             break;
1311                 case( VT_DATE ):
1312                         res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
1313                         break;
1314                 case( VT_BOOL ):
1315                         res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
1316                         break;
1317                 case( VT_BSTR ):
1318                         res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
1319                         break;
1320                 case( VT_CY ):
1321                         res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
1322                         break;
1323                 case( VT_DISPATCH ):
1324                         /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1325                 case( VT_DECIMAL ):
1326                         /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1327                 case( VT_UNKNOWN ):
1328                 default:
1329                         res = DISP_E_TYPEMISMATCH;
1330                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1331                         break;
1332                 }
1333                 break;
1334
1335         case( VT_DATE ):
1336                 switch( vtFrom )
1337                 {
1338                 case( VT_I1 ):
1339                         res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
1340                         break;
1341                 case( VT_I2 ):
1342                         res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
1343                         break;
1344                 case( VT_INT ):
1345                         res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
1346                         break;
1347                 case( VT_I4 ):
1348                         res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
1349                         break;
1350                 case( VT_UI1 ):
1351                         res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
1352                         break;
1353                 case( VT_UI2 ):
1354                         res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
1355                         break;
1356                 case( VT_UINT ):
1357                         res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
1358                         break;
1359                 case( VT_UI4 ):
1360                         res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
1361                         break;
1362                 case( VT_R4 ):
1363                         res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
1364                         break;
1365                 case( VT_R8 ):
1366                         res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
1367                         break;
1368         case( VT_DATE ):
1369             res = VariantCopy( pd, ps );
1370             break;
1371                 case( VT_BOOL ):
1372                         res = VarDateFromBool( V_UNION(ps,boolVal), &V_UNION(pd,date) );
1373                         break;
1374                 case( VT_BSTR ):
1375                         res = VarDateFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,date) );
1376                         break;
1377                 case( VT_CY ):
1378                         res = VarDateFromCy( V_UNION(ps,cyVal), &V_UNION(pd,date) );
1379                         break;
1380                 case( VT_DISPATCH ):
1381                         /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1382                 case( VT_DECIMAL ):
1383                         /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1384                 case( VT_UNKNOWN ):
1385                 default:
1386                         res = DISP_E_TYPEMISMATCH;
1387                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1388                         break;
1389                 }
1390                 break;
1391
1392         case( VT_BOOL ):
1393                 switch( vtFrom )
1394                 {
1395                 case( VT_I1 ):
1396                         res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
1397                         break;
1398                 case( VT_I2 ):
1399                         res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
1400                         break;
1401                 case( VT_INT ):
1402                         res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
1403                         break;
1404                 case( VT_I4 ):
1405                         res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
1406                         break;
1407                 case( VT_UI1 ):
1408                         res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
1409                         break;
1410                 case( VT_UI2 ):
1411                         res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
1412                         break;
1413                 case( VT_UINT ):
1414                         res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
1415                         break;
1416                 case( VT_UI4 ):
1417                         res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
1418                         break;
1419                 case( VT_R4 ):
1420                         res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
1421                         break;
1422                 case( VT_R8 ):
1423                         res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
1424                         break;
1425                 case( VT_DATE ):
1426                         res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
1427                         break;
1428         case( VT_BOOL ):
1429             res = VariantCopy( pd, ps );
1430             break;
1431                 case( VT_BSTR ):
1432                         res = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
1433                         break;
1434                 case( VT_CY ):
1435                         res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
1436                         break;
1437                 case( VT_DISPATCH ):
1438                         /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1439                 case( VT_DECIMAL ):
1440                         /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1441                 case( VT_UNKNOWN ):
1442                 default:
1443                         res = DISP_E_TYPEMISMATCH;
1444                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1445                         break;
1446                 }
1447                 break;
1448
1449         case( VT_BSTR ):
1450                 switch( vtFrom )
1451                 {
1452                 case( VT_EMPTY ):
1453                         if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
1454                                 res = S_OK;
1455                         else
1456                                 res = E_OUTOFMEMORY;
1457                         break;
1458                 case( VT_I1 ):
1459                         res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
1460                         break;
1461                 case( VT_I2 ):
1462                         res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
1463                         break;
1464                 case( VT_INT ):
1465                         res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
1466                         break;
1467                 case( VT_I4 ):
1468                         res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
1469                         break;
1470                 case( VT_UI1 ):
1471                         res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
1472                         break;
1473                 case( VT_UI2 ):
1474                         res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
1475                         break;
1476                 case( VT_UINT ):
1477                         res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
1478                         break;
1479                 case( VT_UI4 ):
1480                         res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
1481                         break;
1482                 case( VT_R4 ):
1483                         res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
1484                         break;
1485                 case( VT_R8 ):
1486                         res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
1487                         break;
1488                 case( VT_DATE ):
1489                         res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
1490                         break;
1491                 case( VT_BOOL ):
1492                         res = VarBstrFromBool( V_UNION(ps,boolVal), lcid, 0, &V_UNION(pd,bstrVal) );
1493                         break;
1494                 case( VT_BSTR ):
1495                         res = VariantCopy( pd, ps );
1496                         break;
1497                 case( VT_CY ):
1498                         res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
1499                         break;
1500                 case( VT_DISPATCH ):
1501                         /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1502                 case( VT_DECIMAL ):
1503                         /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1504                 case( VT_UNKNOWN ):
1505                 default:
1506                         res = DISP_E_TYPEMISMATCH;
1507                         FIXME("Coercion from %d to %d\n", vtFrom, vt );
1508                         break;
1509                 }
1510                 break;
1511
1512      case( VT_CY ):
1513         switch( vtFrom )
1514           {
1515           case( VT_I1 ):
1516              res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
1517              break;
1518           case( VT_I2 ):
1519              res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
1520              break;
1521           case( VT_INT ):
1522              res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
1523              break;
1524           case( VT_I4 ):
1525              res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
1526              break;
1527           case( VT_UI1 ):
1528              res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
1529              break;
1530           case( VT_UI2 ):
1531              res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
1532              break;
1533           case( VT_UINT ):
1534              res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
1535              break;
1536           case( VT_UI4 ):
1537              res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
1538              break;
1539           case( VT_R4 ):
1540              res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
1541              break;
1542           case( VT_R8 ):
1543              res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
1544              break;
1545           case( VT_DATE ):
1546              res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1547              break;
1548           case( VT_BOOL ):
1549              res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1550              break;
1551           case( VT_CY ):
1552              res = VariantCopy( pd, ps );
1553              break;
1554           case( VT_BSTR ):
1555              res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
1556              break;
1557           case( VT_DISPATCH ):
1558              /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1559           case( VT_DECIMAL ):
1560              /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1561              break;
1562           case( VT_UNKNOWN ):
1563           default:
1564              res = DISP_E_TYPEMISMATCH;
1565              FIXME("Coercion from %d to %d\n", vtFrom, vt );
1566              break;
1567           }
1568         break;
1569
1570         case( VT_UNKNOWN ):
1571             if (vtFrom == VT_DISPATCH)
1572             {
1573                 res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1574             }
1575             else
1576             {
1577                 res = DISP_E_TYPEMISMATCH;
1578                 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1579             }
1580             break;
1581
1582         default:
1583                 res = DISP_E_TYPEMISMATCH;
1584                 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1585                 break;
1586         }
1587         
1588         return res;
1589 }
1590
1591 /******************************************************************************
1592  *              ValidateVtRange [INTERNAL]
1593  *
1594  * Used internally by the hi-level Variant API to determine
1595  * if the vartypes are valid.
1596  */
1597 static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
1598 {
1599     /* if by value we must make sure it is in the
1600      * range of the valid types.
1601      */
1602     if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1603     {
1604         return DISP_E_BADVARTYPE;
1605     }
1606     return S_OK;
1607 }
1608
1609
1610 /******************************************************************************
1611  *              ValidateVartype [INTERNAL]
1612  *
1613  * Used internally by the hi-level Variant API to determine
1614  * if the vartypes are valid.
1615  */
1616 static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
1617 {
1618         HRESULT res = S_OK;
1619
1620         /* check if we have a valid argument.
1621          */
1622         if( vt & VT_BYREF )
1623     {
1624         /* if by reference check that the type is in
1625          * the valid range and that it is not of empty or null type
1626          */
1627         if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1628             ( vt & VT_TYPEMASK ) == VT_NULL ||
1629                         ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1630                 {
1631                         res = E_INVALIDARG;
1632                 }
1633                         
1634     }
1635     else
1636     {
1637         res = ValidateVtRange( vt );
1638     }
1639                 
1640         return res;
1641 }
1642
1643 /******************************************************************************
1644  *              ValidateVt      [INTERNAL]
1645  *
1646  * Used internally by the hi-level Variant API to determine
1647  * if the vartypes are valid.
1648  */
1649 static HRESULT WINAPI ValidateVt( VARTYPE vt )
1650 {
1651         HRESULT res = S_OK;
1652
1653         /* check if we have a valid argument.
1654          */
1655         if( vt & VT_BYREF )
1656     {
1657         /* if by reference check that the type is in
1658          * the valid range and that it is not of empty or null type
1659          */
1660         if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1661             ( vt & VT_TYPEMASK ) == VT_NULL ||
1662                         ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1663                 {
1664                         res = DISP_E_BADVARTYPE;
1665                 }
1666                         
1667     }
1668     else
1669     {
1670         res = ValidateVtRange( vt );
1671     }
1672                 
1673         return res;
1674 }
1675
1676
1677
1678
1679
1680 /******************************************************************************
1681  *              VariantInit     [OLEAUT32.8]
1682  *
1683  * Initializes the Variant.  Unlike VariantClear it does not interpret
1684  * the current contents of the Variant.
1685  */
1686 void WINAPI VariantInit(VARIANTARG* pvarg)
1687 {
1688   TRACE("(%p)\n",pvarg);
1689
1690   memset(pvarg, 0, sizeof (VARIANTARG));
1691   V_VT(pvarg) = VT_EMPTY;
1692
1693   return;
1694 }
1695
1696 /******************************************************************************
1697  *              VariantClear    [OLEAUT32.9]
1698  *
1699  * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1700  * sets the wReservedX field to 0.      The current contents of the VARIANT are
1701  * freed.  If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1702  * released. If VT_ARRAY the array is freed.
1703  */
1704 HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
1705 {
1706   HRESULT res = S_OK;
1707   TRACE("(%p)\n",pvarg);
1708
1709   res = ValidateVariantType( V_VT(pvarg) );
1710   if( res == S_OK )
1711   {
1712     if( !( V_VT(pvarg) & VT_BYREF ) )
1713     {
1714       /*
1715        * The VT_ARRAY flag is a special case of a safe array.
1716        */
1717       if ( (V_VT(pvarg) & VT_ARRAY) != 0)
1718       {
1719         SafeArrayDestroy(V_UNION(pvarg,parray));
1720       }
1721       else
1722       {
1723         switch( V_VT(pvarg) & VT_TYPEMASK )
1724         {
1725           case( VT_BSTR ):
1726             SysFreeString( V_UNION(pvarg,bstrVal) );
1727             break;
1728           case( VT_DISPATCH ):
1729             if(V_UNION(pvarg,pdispVal)!=NULL)
1730               ICOM_CALL(Release,V_UNION(pvarg,pdispVal));
1731             break;
1732           case( VT_VARIANT ):
1733             VariantClear(V_UNION(pvarg,pvarVal));
1734             break;
1735           case( VT_UNKNOWN ):
1736             if(V_UNION(pvarg,punkVal)!=NULL)
1737               ICOM_CALL(Release,V_UNION(pvarg,punkVal));
1738             break;
1739           case( VT_SAFEARRAY ):
1740             SafeArrayDestroy(V_UNION(pvarg,parray));
1741             break;
1742           default:
1743             break;
1744         }
1745       }
1746     }
1747         
1748     /*
1749      * Empty all the fields and mark the type as empty.
1750      */
1751     memset(pvarg, 0, sizeof (VARIANTARG));
1752     V_VT(pvarg) = VT_EMPTY;
1753   }
1754
1755   return res;
1756 }
1757
1758 /******************************************************************************
1759  *              VariantCopy     [OLEAUT32.10]
1760  *
1761  * Frees up the designation variant and makes a copy of the source.
1762  */
1763 HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
1764 {
1765   HRESULT res = S_OK;
1766
1767   TRACE("(%p, %p), vt=%d\n", pvargDest, pvargSrc, V_VT(pvargSrc));
1768
1769   res = ValidateVariantType( V_VT(pvargSrc) );
1770
1771   /* If the pointer are to the same variant we don't need
1772    * to do anything.
1773    */
1774   if( pvargDest != pvargSrc && res == S_OK )
1775   {
1776     res = VariantClear( pvargDest );
1777                 
1778     if( res == S_OK )
1779     {
1780       if( V_VT(pvargSrc) & VT_BYREF )
1781       {
1782         /* In the case of byreference we only need
1783          * to copy the pointer.
1784          */
1785         pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1786         V_VT(pvargDest) = V_VT(pvargSrc);
1787       }
1788       else
1789       {
1790         /*
1791          * The VT_ARRAY flag is another way to designate a safe array.
1792          */
1793         if (V_VT(pvargSrc) & VT_ARRAY)
1794         {
1795           SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1796         }
1797         else
1798         {
1799           /* In the case of by value we need to
1800            * copy the actual value. In the case of
1801            * VT_BSTR a copy of the string is made,
1802            * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1803            * called to increment the object's reference count.
1804            */
1805           switch( V_VT(pvargSrc) & VT_TYPEMASK )
1806           {
1807             case( VT_BSTR ):
1808               V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
1809               break;
1810             case( VT_DISPATCH ):
1811               V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
1812               if (V_UNION(pvargDest,pdispVal)!=NULL)
1813                 ICOM_CALL(AddRef,V_UNION(pvargDest,pdispVal));
1814               break;
1815             case( VT_VARIANT ):
1816               VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
1817               break;
1818             case( VT_UNKNOWN ):
1819               V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
1820               if (V_UNION(pvargDest,pdispVal)!=NULL)
1821                 ICOM_CALL(AddRef,V_UNION(pvargDest,punkVal));
1822               break;
1823             case( VT_SAFEARRAY ):
1824               SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1825               break;
1826             default:
1827               pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1828               break;
1829           }
1830         }
1831         
1832         V_VT(pvargDest) = V_VT(pvargSrc);
1833       }      
1834     }
1835   }
1836
1837   return res;
1838 }
1839
1840
1841 /******************************************************************************
1842  *              VariantCopyInd  [OLEAUT32.11]
1843  *
1844  * Frees up the destination variant and makes a copy of the source.  If
1845  * the source is of type VT_BYREF it performs the necessary indirections.
1846  */
1847 HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
1848 {
1849   HRESULT res = S_OK;
1850
1851   TRACE("(%p, %p)\n", pvargDest, pvargSrc);
1852
1853   res = ValidateVariantType( V_VT(pvargSrc) );
1854
1855   if( res != S_OK )
1856     return res;
1857   
1858   if( V_VT(pvargSrc) & VT_BYREF )
1859   {
1860     VARIANTARG varg;
1861     VariantInit( &varg );
1862
1863     /* handle the in place copy.
1864      */
1865     if( pvargDest == pvargSrc )
1866     {
1867       /* we will use a copy of the source instead.
1868        */
1869       res = VariantCopy( &varg, pvargSrc );
1870       pvargSrc = &varg;
1871     }
1872
1873     if( res == S_OK )
1874     {
1875       res = VariantClear( pvargDest );
1876
1877       if( res == S_OK )
1878       {
1879         /*
1880          * The VT_ARRAY flag is another way to designate a safearray variant.
1881          */
1882         if ( V_VT(pvargSrc) & VT_ARRAY)
1883         {
1884           SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
1885         }
1886         else
1887         {
1888           /* In the case of by reference we need
1889            * to copy the date pointed to by the variant.
1890            */
1891
1892           /* Get the variant type.
1893            */
1894           switch( V_VT(pvargSrc) & VT_TYPEMASK )
1895           {
1896             case( VT_BSTR ):
1897               V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
1898               break;
1899             case( VT_DISPATCH ):
1900               break;
1901             case( VT_VARIANT ):
1902               {
1903                 /* Prevent from cycling.  According to tests on
1904                  * VariantCopyInd in Windows and the documentation
1905                  * this API dereferences the inner Variants to only one depth.
1906                  * If the inner Variant itself contains an
1907                  * other inner variant the E_INVALIDARG error is
1908                  * returned. 
1909                  */
1910                 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
1911                 {
1912                   /* If we get here we are attempting to deference
1913                    * an inner variant that that is itself contained
1914                    * in an inner variant so report E_INVALIDARG error.
1915                    */
1916                   res = E_INVALIDARG;
1917                 }
1918                 else
1919                 {
1920                   /* Set the processing inner variant flag.
1921                    * We will set this flag in the inner variant
1922                    * that will be passed to the VariantCopyInd function.
1923                    */
1924                   (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
1925                   
1926                   /* Dereference the inner variant.
1927                    */
1928                   res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
1929                   /* We must also copy its type, I think.
1930                    */
1931                   V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
1932                 }
1933               }
1934               break;
1935             case( VT_UNKNOWN ):
1936               break;
1937             case( VT_SAFEARRAY ):
1938               SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
1939               break;
1940             default:
1941               /* This is a by reference Variant which means that the union
1942                * part of the Variant contains a pointer to some data of
1943                * type "V_VT(pvargSrc) & VT_TYPEMASK".
1944                * We will deference this data in a generic fashion using
1945                * the void pointer "Variant.u.byref".
1946                * We will copy this data into the union of the destination
1947                * Variant.
1948                */
1949               memcpy( &pvargDest->n1.n2, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
1950               break;
1951           }
1952         }
1953         
1954         V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
1955       }
1956     }
1957
1958     /* this should not fail.
1959      */
1960     VariantClear( &varg );
1961   }
1962   else
1963   {
1964     res = VariantCopy( pvargDest, pvargSrc );
1965   }
1966
1967   return res;
1968 }
1969
1970 /******************************************************************************
1971  *              VariantChangeType       [OLEAUT32.12]
1972  */
1973 HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
1974                                                         USHORT wFlags, VARTYPE vt)
1975 {
1976         return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
1977 }
1978
1979 /******************************************************************************
1980  *              VariantChangeTypeEx     [OLEAUT32.147]
1981  */
1982 HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
1983                                                           LCID lcid, USHORT wFlags, VARTYPE vt)
1984 {
1985         HRESULT res = S_OK;
1986         VARIANTARG varg;
1987         VariantInit( &varg );
1988         
1989         TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
1990
1991         /* validate our source argument.
1992          */
1993         res = ValidateVariantType( V_VT(pvargSrc) );
1994
1995         /* validate the vartype.
1996          */
1997         if( res == S_OK )
1998         {
1999                 res = ValidateVt( vt );
2000         }
2001
2002         /* if we are doing an in-place conversion make a copy of the source.
2003          */
2004         if( res == S_OK && pvargDest == pvargSrc )
2005         {
2006                 res = VariantCopy( &varg, pvargSrc );
2007                 pvargSrc = &varg;
2008         }
2009
2010         if( res == S_OK )
2011         {
2012                 /* free up the destination variant.
2013                  */
2014                 res = VariantClear( pvargDest );
2015         }
2016
2017         if( res == S_OK )
2018         {
2019                 if( V_VT(pvargSrc) & VT_BYREF )
2020                 {
2021                         /* Convert the source variant to a "byvalue" variant.
2022                          */
2023                         VARIANTARG Variant;
2024                         VariantInit( &Variant );
2025                         res = VariantCopyInd( &Variant, pvargSrc );
2026                         if( res == S_OK )
2027                         {
2028                                 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2029                                 /* this should not fail.
2030                                  */
2031                                 VariantClear( &Variant );
2032                         }
2033         
2034                 }
2035                 else
2036                 {
2037                         /* Use the current "byvalue" source variant.
2038                          */
2039                         res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2040                 }
2041         }
2042         /* this should not fail.
2043          */
2044         VariantClear( &varg );
2045         
2046         /* set the type of the destination
2047          */
2048         if ( res == S_OK )
2049                 V_VT(pvargDest) = vt;
2050
2051         return res;
2052 }
2053
2054
2055
2056
2057 /******************************************************************************
2058  *              VarUI1FromI2            [OLEAUT32.130]
2059  */
2060 HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2061 {
2062         TRACE("( %d, %p ), stub\n", sIn, pbOut );
2063
2064         /* Check range of value.
2065          */
2066         if( sIn < UI1_MIN || sIn > UI1_MAX )
2067         {
2068                 return DISP_E_OVERFLOW;
2069         }
2070
2071         *pbOut = (BYTE) sIn;
2072         
2073         return S_OK;
2074 }
2075
2076 /******************************************************************************
2077  *              VarUI1FromI4            [OLEAUT32.131]
2078  */
2079 HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2080 {
2081         TRACE("( %ld, %p ), stub\n", lIn, pbOut );
2082
2083         /* Check range of value.
2084          */
2085         if( lIn < UI1_MIN || lIn > UI1_MAX )
2086         {
2087                 return DISP_E_OVERFLOW;
2088         }
2089
2090         *pbOut = (BYTE) lIn;
2091         
2092         return S_OK;
2093 }
2094
2095
2096 /******************************************************************************
2097  *              VarUI1FromR4            [OLEAUT32.132]
2098  */
2099 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2100 {
2101         TRACE("( %f, %p ), stub\n", fltIn, pbOut );
2102
2103         /* Check range of value.
2104      */
2105     fltIn = round( fltIn );
2106         if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2107         {
2108                 return DISP_E_OVERFLOW;
2109         }
2110
2111         *pbOut = (BYTE) fltIn;
2112         
2113         return S_OK;
2114 }
2115
2116 /******************************************************************************
2117  *              VarUI1FromR8            [OLEAUT32.133]
2118  */
2119 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2120 {
2121         TRACE("( %f, %p ), stub\n", dblIn, pbOut );
2122
2123         /* Check range of value.
2124      */
2125     dblIn = round( dblIn );
2126         if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2127         {
2128                 return DISP_E_OVERFLOW;
2129         }
2130
2131         *pbOut = (BYTE) dblIn;
2132
2133         return S_OK;
2134 }
2135
2136 /******************************************************************************
2137  *              VarUI1FromDate          [OLEAUT32.135]
2138  */
2139 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2140 {
2141         TRACE("( %f, %p ), stub\n", dateIn, pbOut );
2142
2143         /* Check range of value.
2144      */
2145     dateIn = round( dateIn );
2146         if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2147         {
2148                 return DISP_E_OVERFLOW;
2149         }
2150
2151         *pbOut = (BYTE) dateIn;
2152
2153         return S_OK;
2154 }
2155
2156 /******************************************************************************
2157  *              VarUI1FromBool          [OLEAUT32.138]
2158  */
2159 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2160 {
2161         TRACE("( %d, %p ), stub\n", boolIn, pbOut );
2162
2163         *pbOut = (BYTE) boolIn;
2164
2165         return S_OK;
2166 }
2167
2168 /******************************************************************************
2169  *              VarUI1FromI1            [OLEAUT32.237]
2170  */
2171 HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
2172 {
2173         TRACE("( %c, %p ), stub\n", cIn, pbOut );
2174
2175         *pbOut = cIn;
2176
2177         return S_OK;
2178 }
2179
2180 /******************************************************************************
2181  *              VarUI1FromUI2           [OLEAUT32.238]
2182  */
2183 HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2184 {
2185         TRACE("( %d, %p ), stub\n", uiIn, pbOut );
2186
2187         /* Check range of value.
2188          */
2189         if( uiIn > UI1_MAX )
2190         {
2191                 return DISP_E_OVERFLOW;
2192         }
2193
2194         *pbOut = (BYTE) uiIn;
2195
2196         return S_OK;
2197 }
2198
2199 /******************************************************************************
2200  *              VarUI1FromUI4           [OLEAUT32.239]
2201  */
2202 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2203 {
2204         TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
2205
2206         /* Check range of value.
2207          */
2208         if( ulIn > UI1_MAX )
2209         {
2210                 return DISP_E_OVERFLOW;
2211         }
2212
2213         *pbOut = (BYTE) ulIn;
2214
2215         return S_OK;
2216 }
2217
2218
2219 /******************************************************************************
2220  *              VarUI1FromStr           [OLEAUT32.136]
2221  */
2222 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2223 {
2224         double dValue = 0.0;
2225         LPSTR pNewString = NULL;
2226
2227         TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
2228
2229         /* Check if we have a valid argument
2230          */
2231         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2232         RemoveCharacterFromString( pNewString, "," );
2233         if( IsValidRealString( pNewString ) == FALSE )
2234         {
2235                 return DISP_E_TYPEMISMATCH;
2236         }
2237
2238         /* Convert the valid string to a floating point number.
2239          */
2240         dValue = atof( pNewString );
2241         
2242         /* We don't need the string anymore so free it.
2243          */
2244         HeapFree( GetProcessHeap(), 0 , pNewString );
2245
2246         /* Check range of value.
2247      */
2248     dValue = round( dValue );
2249         if( dValue < UI1_MIN || dValue > UI1_MAX )
2250         {
2251                 return DISP_E_OVERFLOW;
2252         }
2253
2254         *pbOut = (BYTE) dValue;
2255
2256         return S_OK;
2257 }
2258
2259 /**********************************************************************
2260  *              VarUI1FromCy [OLEAUT32.134]
2261  * Convert currency to unsigned char
2262  */
2263 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
2264    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2265    
2266    if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
2267    
2268    *pbOut = (BYTE)t;
2269    return S_OK;
2270 }
2271
2272 /******************************************************************************
2273  *              VarI2FromUI1            [OLEAUT32.48]
2274  */
2275 HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2276 {
2277         TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
2278
2279         *psOut = (short) bIn;
2280         
2281         return S_OK;
2282 }
2283
2284 /******************************************************************************
2285  *              VarI2FromI4             [OLEAUT32.49]
2286  */
2287 HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2288 {
2289         TRACE("( %lx, %p ), stub\n", lIn, psOut );
2290
2291         /* Check range of value.
2292          */
2293         if( lIn < I2_MIN || lIn > I2_MAX )
2294         {
2295                 return DISP_E_OVERFLOW;
2296         }
2297
2298         *psOut = (short) lIn;
2299         
2300         return S_OK;
2301 }
2302
2303 /******************************************************************************
2304  *              VarI2FromR4             [OLEAUT32.50]
2305  */
2306 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2307 {
2308         TRACE("( %f, %p ), stub\n", fltIn, psOut );
2309
2310         /* Check range of value.
2311      */
2312     fltIn = round( fltIn );
2313         if( fltIn < I2_MIN || fltIn > I2_MAX )
2314         {
2315                 return DISP_E_OVERFLOW;
2316         }
2317
2318         *psOut = (short) fltIn;
2319
2320         return S_OK;
2321 }
2322
2323 /******************************************************************************
2324  *              VarI2FromR8             [OLEAUT32.51]
2325  */
2326 HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2327 {
2328         TRACE("( %f, %p ), stub\n", dblIn, psOut );
2329
2330         /* Check range of value.
2331      */
2332     dblIn = round( dblIn );
2333         if( dblIn < I2_MIN || dblIn > I2_MAX )
2334         {
2335                 return DISP_E_OVERFLOW;
2336         }
2337
2338         *psOut = (short) dblIn;
2339
2340         return S_OK;
2341 }
2342
2343 /******************************************************************************
2344  *              VarI2FromDate           [OLEAUT32.53]
2345  */
2346 HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2347 {
2348         TRACE("( %f, %p ), stub\n", dateIn, psOut );
2349
2350         /* Check range of value.
2351      */
2352     dateIn = round( dateIn );
2353         if( dateIn < I2_MIN || dateIn > I2_MAX )
2354         {
2355                 return DISP_E_OVERFLOW;
2356         }
2357
2358         *psOut = (short) dateIn;
2359
2360         return S_OK;
2361 }
2362
2363 /******************************************************************************
2364  *              VarI2FromBool           [OLEAUT32.56]
2365  */
2366 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2367 {
2368         TRACE("( %d, %p ), stub\n", boolIn, psOut );
2369
2370         *psOut = (short) boolIn;
2371
2372         return S_OK;
2373 }
2374
2375 /******************************************************************************
2376  *              VarI2FromI1             [OLEAUT32.205]
2377  */
2378 HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
2379 {
2380         TRACE("( %c, %p ), stub\n", cIn, psOut );
2381
2382         *psOut = (short) cIn;
2383
2384         return S_OK;
2385 }
2386
2387 /******************************************************************************
2388  *              VarI2FromUI2            [OLEAUT32.206]
2389  */
2390 HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2391 {
2392         TRACE("( %d, %p ), stub\n", uiIn, psOut );
2393
2394         /* Check range of value.
2395          */
2396         if( uiIn > I2_MAX )
2397         {
2398                 return DISP_E_OVERFLOW;
2399         }
2400
2401         *psOut = (short) uiIn;
2402
2403         return S_OK;
2404 }
2405
2406 /******************************************************************************
2407  *              VarI2FromUI4            [OLEAUT32.207]
2408  */
2409 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2410 {
2411         TRACE("( %lx, %p ), stub\n", ulIn, psOut );
2412
2413         /* Check range of value.
2414          */
2415         if( ulIn < I2_MIN || ulIn > I2_MAX )
2416         {
2417                 return DISP_E_OVERFLOW;
2418         }
2419
2420         *psOut = (short) ulIn;
2421
2422         return S_OK;
2423 }
2424
2425 /******************************************************************************
2426  *              VarI2FromStr            [OLEAUT32.54]
2427  */
2428 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2429 {
2430         double dValue = 0.0;
2431         LPSTR pNewString = NULL;
2432
2433         TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, psOut );
2434
2435         /* Check if we have a valid argument
2436          */
2437         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2438         RemoveCharacterFromString( pNewString, "," );
2439         if( IsValidRealString( pNewString ) == FALSE )
2440         {
2441                 return DISP_E_TYPEMISMATCH;
2442         }
2443
2444         /* Convert the valid string to a floating point number.
2445          */
2446         dValue = atof( pNewString );
2447         
2448         /* We don't need the string anymore so free it.
2449          */
2450         HeapFree( GetProcessHeap(), 0, pNewString );
2451
2452         /* Check range of value.
2453      */
2454     dValue = round( dValue );
2455         if( dValue < I2_MIN || dValue > I2_MAX )
2456         {
2457                 return DISP_E_OVERFLOW;
2458         }
2459
2460         *psOut = (short)  dValue;
2461
2462         return S_OK;
2463 }
2464
2465 /**********************************************************************
2466  *              VarI2FromCy [OLEAUT32.52]
2467  * Convert currency to signed short
2468  */
2469 HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
2470    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2471    
2472    if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
2473    
2474    *psOut = (SHORT)t;
2475    return S_OK;
2476 }
2477
2478 /******************************************************************************
2479  *              VarI4FromUI1            [OLEAUT32.58]
2480  */
2481 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2482 {
2483         TRACE("( %X, %p ), stub\n", bIn, plOut );
2484
2485         *plOut = (LONG) bIn;
2486
2487         return S_OK;
2488 }
2489
2490
2491 /******************************************************************************
2492  *              VarI4FromR4             [OLEAUT32.60]
2493  */
2494 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2495 {
2496         TRACE("( %f, %p ), stub\n", fltIn, plOut );
2497
2498         /* Check range of value.
2499      */
2500     fltIn = round( fltIn );
2501         if( fltIn < I4_MIN || fltIn > I4_MAX )
2502         {
2503                 return DISP_E_OVERFLOW;
2504         }
2505
2506         *plOut = (LONG) fltIn;
2507
2508         return S_OK;
2509 }
2510
2511 /******************************************************************************
2512  *              VarI4FromR8             [OLEAUT32.61]
2513  */
2514 HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2515 {
2516         TRACE("( %f, %p ), stub\n", dblIn, plOut );
2517
2518         /* Check range of value.
2519      */
2520     dblIn = round( dblIn );
2521         if( dblIn < I4_MIN || dblIn > I4_MAX )
2522         {
2523                 return DISP_E_OVERFLOW;
2524         }
2525
2526         *plOut = (LONG) dblIn;
2527
2528         return S_OK;
2529 }
2530
2531 /******************************************************************************
2532  *              VarI4FromDate           [OLEAUT32.63]
2533  */
2534 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2535 {
2536         TRACE("( %f, %p ), stub\n", dateIn, plOut );
2537
2538         /* Check range of value.
2539      */
2540     dateIn = round( dateIn );
2541         if( dateIn < I4_MIN || dateIn > I4_MAX )
2542         {
2543                 return DISP_E_OVERFLOW;
2544         }
2545
2546         *plOut = (LONG) dateIn;
2547
2548         return S_OK;
2549 }
2550
2551 /******************************************************************************
2552  *              VarI4FromBool           [OLEAUT32.66]
2553  */
2554 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2555 {
2556         TRACE("( %d, %p ), stub\n", boolIn, plOut );
2557
2558         *plOut = (LONG) boolIn;
2559
2560         return S_OK;
2561 }
2562
2563 /******************************************************************************
2564  *              VarI4FromI1             [OLEAUT32.209]
2565  */
2566 HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
2567 {
2568         TRACE("( %c, %p ), stub\n", cIn, plOut );
2569
2570         *plOut = (LONG) cIn;
2571
2572         return S_OK;
2573 }
2574
2575 /******************************************************************************
2576  *              VarI4FromUI2            [OLEAUT32.210]
2577  */
2578 HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2579 {
2580         TRACE("( %d, %p ), stub\n", uiIn, plOut );
2581
2582         *plOut = (LONG) uiIn;
2583
2584         return S_OK;
2585 }
2586
2587 /******************************************************************************
2588  *              VarI4FromUI4            [OLEAUT32.211]
2589  */
2590 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2591 {
2592         TRACE("( %lx, %p ), stub\n", ulIn, plOut );
2593
2594         /* Check range of value.
2595          */
2596         if( ulIn < I4_MIN || ulIn > I4_MAX )
2597         {
2598                 return DISP_E_OVERFLOW;
2599         }
2600
2601         *plOut = (LONG) ulIn;
2602
2603         return S_OK;
2604 }
2605
2606 /******************************************************************************
2607  *              VarI4FromI2             [OLEAUT32.59]
2608  */
2609 HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2610 {
2611         TRACE("( %d, %p ), stub\n", sIn, plOut );
2612
2613         *plOut = (LONG) sIn;
2614
2615         return S_OK;
2616 }
2617
2618 /******************************************************************************
2619  *              VarI4FromStr            [OLEAUT32.64]
2620  */
2621 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2622 {
2623         double dValue = 0.0;
2624         LPSTR pNewString = NULL;
2625
2626         TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
2627
2628         /* Check if we have a valid argument
2629          */
2630         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2631         RemoveCharacterFromString( pNewString, "," );
2632         if( IsValidRealString( pNewString ) == FALSE )
2633         {
2634                 return DISP_E_TYPEMISMATCH;
2635         }
2636
2637         /* Convert the valid string to a floating point number.
2638          */
2639         dValue = atof( pNewString );
2640         
2641         /* We don't need the string anymore so free it.
2642          */
2643         HeapFree( GetProcessHeap(), 0, pNewString );
2644
2645         /* Check range of value.
2646      */
2647     dValue = round( dValue );
2648         if( dValue < I4_MIN || dValue > I4_MAX )
2649         {
2650                 return DISP_E_OVERFLOW;
2651         }
2652
2653         *plOut = (LONG) dValue;
2654
2655         return S_OK;
2656 }
2657
2658 /**********************************************************************
2659  *              VarI4FromCy [OLEAUT32.62]
2660  * Convert currency to signed long
2661  */
2662 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
2663    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2664    
2665    if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
2666    
2667    *plOut = (LONG)t;
2668    return S_OK;
2669 }
2670
2671 /******************************************************************************
2672  *              VarR4FromUI1            [OLEAUT32.68]
2673  */
2674 HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
2675 {
2676         TRACE("( %X, %p ), stub\n", bIn, pfltOut );
2677
2678         *pfltOut = (FLOAT) bIn;
2679
2680         return S_OK;
2681 }
2682
2683 /******************************************************************************
2684  *              VarR4FromI2             [OLEAUT32.69]
2685  */
2686 HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
2687 {
2688         TRACE("( %d, %p ), stub\n", sIn, pfltOut );
2689
2690         *pfltOut = (FLOAT) sIn;
2691
2692         return S_OK;
2693 }
2694
2695 /******************************************************************************
2696  *              VarR4FromI4             [OLEAUT32.70]
2697  */
2698 HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
2699 {
2700         TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
2701
2702         *pfltOut = (FLOAT) lIn;
2703
2704         return S_OK;
2705 }
2706
2707 /******************************************************************************
2708  *              VarR4FromR8             [OLEAUT32.71]
2709  */
2710 HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
2711 {
2712         TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
2713
2714         /* Check range of value.
2715          */
2716         if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
2717         {
2718                 return DISP_E_OVERFLOW;
2719         }
2720
2721         *pfltOut = (FLOAT) dblIn;
2722
2723         return S_OK;
2724 }
2725
2726 /******************************************************************************
2727  *              VarR4FromDate           [OLEAUT32.73]
2728  */
2729 HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
2730 {
2731         TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
2732
2733         /* Check range of value.
2734          */
2735         if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
2736         {
2737                 return DISP_E_OVERFLOW;
2738         }
2739
2740         *pfltOut = (FLOAT) dateIn;
2741
2742         return S_OK;
2743 }
2744
2745 /******************************************************************************
2746  *              VarR4FromBool           [OLEAUT32.76]
2747  */
2748 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
2749 {
2750         TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
2751
2752         *pfltOut = (FLOAT) boolIn;
2753
2754         return S_OK;
2755 }
2756
2757 /******************************************************************************
2758  *              VarR4FromI1             [OLEAUT32.213]
2759  */
2760 HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
2761 {
2762         TRACE("( %c, %p ), stub\n", cIn, pfltOut );
2763
2764         *pfltOut = (FLOAT) cIn;
2765
2766         return S_OK;
2767 }
2768
2769 /******************************************************************************
2770  *              VarR4FromUI2            [OLEAUT32.214]
2771  */
2772 HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
2773 {
2774         TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
2775
2776         *pfltOut = (FLOAT) uiIn;
2777
2778         return S_OK;
2779 }
2780
2781 /******************************************************************************
2782  *              VarR4FromUI4            [OLEAUT32.215]
2783  */
2784 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
2785 {
2786         TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
2787
2788         *pfltOut = (FLOAT) ulIn;
2789
2790         return S_OK;
2791 }
2792
2793 /******************************************************************************
2794  *              VarR4FromStr            [OLEAUT32.74]
2795  */
2796 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
2797 {
2798         double dValue = 0.0;
2799         LPSTR pNewString = NULL;
2800
2801         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
2802
2803         /* Check if we have a valid argument
2804          */
2805         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2806         RemoveCharacterFromString( pNewString, "," );
2807         if( IsValidRealString( pNewString ) == FALSE )
2808         {
2809                 return DISP_E_TYPEMISMATCH;
2810         }
2811
2812         /* Convert the valid string to a floating point number.
2813          */
2814         dValue = atof( pNewString );
2815         
2816         /* We don't need the string anymore so free it.
2817          */
2818         HeapFree( GetProcessHeap(), 0, pNewString );
2819
2820         /* Check range of value.
2821          */
2822         if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
2823         {
2824                 return DISP_E_OVERFLOW;
2825         }
2826
2827         *pfltOut = (FLOAT) dValue;
2828
2829         return S_OK;
2830 }
2831
2832 /**********************************************************************
2833  *              VarR4FromCy [OLEAUT32.72]
2834  * Convert currency to float
2835  */
2836 HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
2837    *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2838    
2839    return S_OK;
2840 }
2841
2842 /******************************************************************************
2843  *              VarR8FromUI1            [OLEAUT32.78]
2844  */
2845 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
2846 {
2847         TRACE("( %d, %p ), stub\n", bIn, pdblOut );
2848
2849         *pdblOut = (double) bIn;
2850
2851         return S_OK;
2852 }
2853
2854 /******************************************************************************
2855  *              VarR8FromI2             [OLEAUT32.79]
2856  */
2857 HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
2858 {
2859         TRACE("( %d, %p ), stub\n", sIn, pdblOut );
2860
2861         *pdblOut = (double) sIn;
2862
2863         return S_OK;
2864 }
2865
2866 /******************************************************************************
2867  *              VarR8FromI4             [OLEAUT32.80]
2868  */
2869 HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
2870 {
2871         TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
2872
2873         *pdblOut = (double) lIn;
2874
2875         return S_OK;
2876 }
2877
2878 /******************************************************************************
2879  *              VarR8FromR4             [OLEAUT32.81]
2880  */
2881 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
2882 {
2883         TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
2884
2885         *pdblOut = (double) fltIn;
2886
2887         return S_OK;
2888 }
2889
2890 /******************************************************************************
2891  *              VarR8FromDate           [OLEAUT32.83]
2892  */
2893 HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
2894 {
2895         TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
2896
2897         *pdblOut = (double) dateIn;
2898
2899         return S_OK;
2900 }
2901
2902 /******************************************************************************
2903  *              VarR8FromBool           [OLEAUT32.86]
2904  */
2905 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
2906 {
2907         TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
2908
2909         *pdblOut = (double) boolIn;
2910
2911         return S_OK;
2912 }
2913
2914 /******************************************************************************
2915  *              VarR8FromI1             [OLEAUT32.217]
2916  */
2917 HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
2918 {
2919         TRACE("( %c, %p ), stub\n", cIn, pdblOut );
2920
2921         *pdblOut = (double) cIn;
2922
2923         return S_OK;
2924 }
2925
2926 /******************************************************************************
2927  *              VarR8FromUI2            [OLEAUT32.218]
2928  */
2929 HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
2930 {
2931         TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
2932
2933         *pdblOut = (double) uiIn;
2934
2935         return S_OK;
2936 }
2937
2938 /******************************************************************************
2939  *              VarR8FromUI4            [OLEAUT32.219]
2940  */
2941 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
2942 {
2943         TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
2944
2945         *pdblOut = (double) ulIn;
2946
2947         return S_OK;
2948 }
2949
2950 /******************************************************************************
2951  *              VarR8FromStr            [OLEAUT32.84]
2952  */
2953 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
2954 {
2955         double dValue = 0.0;
2956         LPSTR pNewString = NULL;
2957
2958         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pdblOut );
2959
2960         /* Check if we have a valid argument
2961          */
2962         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2963         RemoveCharacterFromString( pNewString, "," );
2964         if( IsValidRealString( pNewString ) == FALSE )
2965         {
2966                 return DISP_E_TYPEMISMATCH;
2967         }
2968
2969         /* Convert the valid string to a floating point number.
2970          */
2971         dValue = atof( pNewString );
2972         
2973         /* We don't need the string anymore so free it.
2974          */
2975         HeapFree( GetProcessHeap(), 0, pNewString );
2976
2977         *pdblOut = dValue;
2978
2979         return S_OK;
2980 }
2981
2982 /**********************************************************************
2983  *              VarR8FromCy [OLEAUT32.82]
2984  * Convert currency to double
2985  */
2986 HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
2987    *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2988    
2989    return S_OK;
2990 }
2991
2992 /******************************************************************************
2993  *              VarDateFromUI1          [OLEAUT32.88]
2994  */
2995 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
2996 {
2997         TRACE("( %d, %p ), stub\n", bIn, pdateOut );
2998
2999         *pdateOut = (DATE) bIn;
3000
3001         return S_OK;
3002 }
3003
3004 /******************************************************************************
3005  *              VarDateFromI2           [OLEAUT32.89]
3006  */
3007 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
3008 {
3009         TRACE("( %d, %p ), stub\n", sIn, pdateOut );
3010
3011         *pdateOut = (DATE) sIn;
3012
3013         return S_OK;
3014 }
3015
3016 /******************************************************************************
3017  *              VarDateFromI4           [OLEAUT32.90]
3018  */
3019 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3020 {
3021         TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
3022
3023         if( lIn < DATE_MIN || lIn > DATE_MAX )
3024         {
3025                 return DISP_E_OVERFLOW;
3026         }
3027
3028         *pdateOut = (DATE) lIn;
3029
3030         return S_OK;
3031 }
3032
3033 /******************************************************************************
3034  *              VarDateFromR4           [OLEAUT32.91]
3035  */
3036 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3037 {
3038     TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3039
3040     if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
3041         {
3042                 return DISP_E_OVERFLOW;
3043         }
3044
3045         *pdateOut = (DATE) fltIn;
3046
3047         return S_OK;
3048 }
3049
3050 /******************************************************************************
3051  *              VarDateFromR8           [OLEAUT32.92]
3052  */
3053 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3054 {
3055     TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3056
3057         if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3058         {
3059                 return DISP_E_OVERFLOW;
3060         }
3061
3062         *pdateOut = (DATE) dblIn;
3063
3064         return S_OK;
3065 }
3066
3067 /******************************************************************************
3068  *              VarDateFromStr          [OLEAUT32.94]
3069  * The string representing the date is composed of two parts, a date and time.
3070  *
3071  * The format of the time is has follows:
3072  * hh[:mm][:ss][AM|PM]
3073  * Whitespace can be inserted anywhere between these tokens.  A whitespace consists
3074  * of space and/or tab characters, which are ignored.
3075  *
3076  * The formats for the date part are has follows:
3077  * mm/[dd/][yy]yy 
3078  * [dd/]mm/[yy]yy
3079  * [yy]yy/mm/dd 
3080  * January dd[,] [yy]yy
3081  * dd January [yy]yy
3082  * [yy]yy January dd
3083  * Whitespace can be inserted anywhere between these tokens.
3084  *
3085  * The formats for the date and time string are has follows.
3086  * date[whitespace][time] 
3087  * [time][whitespace]date
3088  *
3089  * These are the only characters allowed in a string representing a date and time:
3090  * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3091  */
3092 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3093 {
3094     HRESULT ret = S_OK;
3095     struct tm TM;
3096
3097     memset( &TM, 0, sizeof(TM) );
3098
3099     TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3100
3101     if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
3102     {
3103         if( TmToDATE( &TM, pdateOut ) == FALSE )
3104         {
3105             ret = E_INVALIDARG;
3106         }
3107     }
3108     else
3109     {
3110         ret = DISP_E_TYPEMISMATCH;
3111     }
3112
3113
3114         return ret;
3115 }
3116
3117 /******************************************************************************
3118  *              VarDateFromI1           [OLEAUT32.221]
3119  */
3120 HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
3121 {
3122         TRACE("( %c, %p ), stub\n", cIn, pdateOut );
3123
3124         *pdateOut = (DATE) cIn;
3125
3126         return S_OK;
3127 }
3128
3129 /******************************************************************************
3130  *              VarDateFromUI2          [OLEAUT32.222]
3131  */
3132 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3133 {
3134         TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
3135
3136         if( uiIn > DATE_MAX )
3137         {
3138                 return DISP_E_OVERFLOW;
3139         }
3140
3141         *pdateOut = (DATE) uiIn;
3142
3143         return S_OK;
3144 }
3145
3146 /******************************************************************************
3147  *              VarDateFromUI4          [OLEAUT32.223]
3148  */
3149 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3150 {
3151         TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
3152
3153         if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3154         {
3155                 return DISP_E_OVERFLOW;
3156         }
3157
3158         *pdateOut = (DATE) ulIn;
3159
3160         return S_OK;
3161 }
3162
3163 /******************************************************************************
3164  *              VarDateFromBool         [OLEAUT32.96]
3165  */
3166 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3167 {
3168         TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
3169
3170         *pdateOut = (DATE) boolIn;
3171
3172         return S_OK;
3173 }
3174
3175 /**********************************************************************
3176  *              VarDateFromCy [OLEAUT32.93]
3177  * Convert currency to date
3178  */
3179 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
3180    *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3181
3182    if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3183    return S_OK;
3184 }
3185
3186 /******************************************************************************
3187  *              VarBstrFromUI1          [OLEAUT32.108]
3188  */
3189 HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3190 {
3191         TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3192         sprintf( pBuffer, "%d", bVal );
3193
3194         *pbstrOut =  StringDupAtoBstr( pBuffer );
3195         
3196         return S_OK;
3197 }
3198
3199 /******************************************************************************
3200  *              VarBstrFromI2           [OLEAUT32.109]
3201  */
3202 HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3203 {
3204         TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3205         sprintf( pBuffer, "%d", iVal );
3206         *pbstrOut = StringDupAtoBstr( pBuffer );
3207
3208         return S_OK;
3209 }
3210
3211 /******************************************************************************
3212  *              VarBstrFromI4           [OLEAUT32.110]
3213  */
3214 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3215 {
3216         TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
3217
3218         sprintf( pBuffer, "%ld", lIn );
3219         *pbstrOut = StringDupAtoBstr( pBuffer );
3220
3221         return S_OK;
3222 }
3223
3224 /******************************************************************************
3225  *              VarBstrFromR4           [OLEAUT32.111]
3226  */
3227 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3228 {
3229         TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
3230
3231         sprintf( pBuffer, "%.7g", fltIn );
3232         *pbstrOut = StringDupAtoBstr( pBuffer );
3233
3234         return S_OK;
3235 }
3236
3237 /******************************************************************************
3238  *              VarBstrFromR8           [OLEAUT32.112]
3239  */
3240 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3241 {
3242         TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
3243
3244         sprintf( pBuffer, "%.15g", dblIn );
3245         *pbstrOut = StringDupAtoBstr( pBuffer );
3246
3247         return S_OK;
3248 }
3249
3250 /******************************************************************************
3251  *    VarBstrFromCy   [OLEAUT32.113]
3252  */
3253 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
3254         FIXME("([cyIn], %08lx, %08lx, %p), stub.\n", lcid, dwFlags, pbstrOut);
3255         return E_NOTIMPL;
3256 }
3257
3258  
3259 /******************************************************************************
3260  *              VarBstrFromDate         [OLEAUT32.114]
3261  *
3262  * The date is implemented using an 8 byte floating-point number.
3263  * Days are represented by whole numbers increments starting with 0.00 as
3264  * being December 30 1899, midnight.
3265  * The hours are expressed as the fractional part of the number.
3266  * December 30 1899 at midnight = 0.00
3267  * January 1 1900 at midnight = 2.00
3268  * January 4 1900 at 6 AM = 5.25
3269  * January 4 1900 at noon = 5.50
3270  * December 29 1899 at midnight = -1.00
3271  * December 18 1899 at midnight = -12.00
3272  * December 18 1899 at 6AM = -12.25
3273  * December 18 1899 at 6PM = -12.75
3274  * December 19 1899 at midnight = -11.00
3275  * The tm structure is as follows:
3276  * struct tm {
3277  *                int tm_sec;      seconds after the minute - [0,59]
3278  *                int tm_min;      minutes after the hour - [0,59]
3279  *                int tm_hour;     hours since midnight - [0,23]
3280  *                int tm_mday;     day of the month - [1,31]
3281  *                int tm_mon;      months since January - [0,11]
3282  *                int tm_year;     years
3283  *                int tm_wday;     days since Sunday - [0,6]
3284  *                int tm_yday;     days since January 1 - [0,365]
3285  *                int tm_isdst;    daylight savings time flag
3286  *                };
3287  */
3288 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3289 {
3290     struct tm TM;
3291     memset( &TM, 0, sizeof(TM) );
3292
3293     TRACE("( %f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
3294
3295     if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
3296                         {
3297         return E_INVALIDARG;
3298                 }
3299
3300     if( dwFlags & VAR_DATEVALUEONLY )
3301                         strftime( pBuffer, BUFFER_MAX, "%x", &TM );
3302     else if( dwFlags & VAR_TIMEVALUEONLY )
3303                         strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3304                 else
3305         strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3306
3307                 *pbstrOut = StringDupAtoBstr( pBuffer );
3308
3309         return S_OK;
3310 }
3311
3312 /******************************************************************************
3313  *              VarBstrFromBool         [OLEAUT32.116]
3314  */
3315 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3316 {
3317         TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
3318
3319         sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
3320
3321         *pbstrOut = StringDupAtoBstr( pBuffer );
3322
3323         return S_OK;
3324 }
3325
3326 /******************************************************************************
3327  *              VarBstrFromI1           [OLEAUT32.229]
3328  */
3329 HRESULT WINAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3330 {
3331         TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3332         sprintf( pBuffer, "%d", cIn );
3333         *pbstrOut = StringDupAtoBstr( pBuffer );
3334
3335         return S_OK;
3336 }
3337
3338 /******************************************************************************
3339  *              VarBstrFromUI2          [OLEAUT32.230]
3340  */
3341 HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3342 {
3343         TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3344         sprintf( pBuffer, "%d", uiIn );
3345         *pbstrOut = StringDupAtoBstr( pBuffer );
3346
3347         return S_OK;
3348 }
3349
3350 /******************************************************************************
3351  *              VarBstrFromUI4          [OLEAUT32.231]
3352  */
3353 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3354 {
3355         TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3356         sprintf( pBuffer, "%ld", ulIn );
3357         *pbstrOut = StringDupAtoBstr( pBuffer );
3358
3359         return S_OK;
3360 }
3361
3362 /******************************************************************************
3363  *              VarBoolFromUI1          [OLEAUT32.118]
3364  */
3365 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3366 {
3367         TRACE("( %d, %p ), stub\n", bIn, pboolOut );
3368
3369         if( bIn == 0 )
3370         {
3371                 *pboolOut = VARIANT_FALSE;
3372         }
3373         else
3374         {
3375                 *pboolOut = VARIANT_TRUE;
3376         }
3377
3378         return S_OK;
3379 }
3380
3381 /******************************************************************************
3382  *              VarBoolFromI2           [OLEAUT32.119]
3383  */
3384 HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3385 {
3386         TRACE("( %d, %p ), stub\n", sIn, pboolOut );
3387
3388         *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
3389
3390         return S_OK;
3391 }
3392
3393 /******************************************************************************
3394  *              VarBoolFromI4           [OLEAUT32.120]
3395  */
3396 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3397 {
3398         TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
3399
3400         *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
3401
3402         return S_OK;
3403 }
3404
3405 /******************************************************************************
3406  *              VarBoolFromR4           [OLEAUT32.121]
3407  */
3408 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3409 {
3410         TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
3411
3412         *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3413
3414         return S_OK;
3415 }
3416
3417 /******************************************************************************
3418  *              VarBoolFromR8           [OLEAUT32.122]
3419  */
3420 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3421 {
3422         TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
3423
3424         *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3425
3426         return S_OK;
3427 }
3428
3429 /******************************************************************************
3430  *              VarBoolFromDate         [OLEAUT32.123]
3431  */
3432 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3433 {
3434         TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
3435
3436         *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3437
3438         return S_OK;
3439 }
3440
3441 /******************************************************************************
3442  *              VarBoolFromStr          [OLEAUT32.125]
3443  */
3444 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3445 {
3446         HRESULT ret = S_OK;
3447         char* pNewString = NULL;
3448
3449         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
3450
3451     pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3452
3453         if( pNewString == NULL || strlen( pNewString ) == 0 )
3454         {
3455                 ret = DISP_E_TYPEMISMATCH;
3456         }
3457
3458         if( ret == S_OK )
3459         {
3460                 if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
3461                 {
3462                         *pboolOut = VARIANT_TRUE;
3463                 }
3464                 else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
3465                 {
3466                         *pboolOut = VARIANT_FALSE;
3467                 }
3468                 else
3469                 {
3470                         /* Try converting the string to a floating point number.
3471                          */
3472                         double dValue = 0.0;
3473                         HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3474                         if( res != S_OK )
3475                         {
3476                                 ret = DISP_E_TYPEMISMATCH;
3477                         }
3478                         else
3479                                 *pboolOut = (dValue == 0.0) ?
3480                                                 VARIANT_FALSE : VARIANT_TRUE;
3481                 }
3482         }
3483
3484         HeapFree( GetProcessHeap(), 0, pNewString );
3485         
3486         return ret;
3487 }
3488
3489 /******************************************************************************
3490  *              VarBoolFromI1           [OLEAUT32.233]
3491  */
3492 HRESULT WINAPI VarBoolFromI1(CHAR cIn, VARIANT_BOOL* pboolOut)
3493 {
3494         TRACE("( %c, %p ), stub\n", cIn, pboolOut );
3495
3496         *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3497
3498         return S_OK;
3499 }
3500
3501 /******************************************************************************
3502  *              VarBoolFromUI2          [OLEAUT32.234]
3503  */
3504 HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3505 {
3506         TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
3507
3508         *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3509
3510         return S_OK;
3511 }
3512
3513 /******************************************************************************
3514  *              VarBoolFromUI4          [OLEAUT32.235]
3515  */
3516 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3517 {
3518         TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
3519
3520         *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3521
3522         return S_OK;
3523 }
3524
3525 /**********************************************************************
3526  *              VarBoolFromCy [OLEAUT32.124]
3527  * Convert currency to boolean
3528  */
3529 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
3530       if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
3531       else *pboolOut = 0;
3532       
3533       return S_OK;
3534 }
3535
3536 /******************************************************************************
3537  *              VarI1FromUI1            [OLEAUT32.244]
3538  */
3539 HRESULT WINAPI VarI1FromUI1(BYTE bIn, CHAR* pcOut)
3540 {
3541         TRACE("( %d, %p ), stub\n", bIn, pcOut );
3542
3543         /* Check range of value.
3544          */
3545         if( bIn > CHAR_MAX )
3546         {
3547                 return DISP_E_OVERFLOW;
3548         }
3549
3550         *pcOut = (CHAR) bIn;
3551
3552         return S_OK;
3553 }
3554
3555 /******************************************************************************
3556  *              VarI1FromI2             [OLEAUT32.245]
3557  */
3558 HRESULT WINAPI VarI1FromI2(short uiIn, CHAR* pcOut)
3559 {
3560         TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3561
3562         if( uiIn > CHAR_MAX )
3563         {
3564                 return DISP_E_OVERFLOW;
3565         }
3566
3567         *pcOut = (CHAR) uiIn;
3568
3569         return S_OK;
3570 }
3571
3572 /******************************************************************************
3573  *              VarI1FromI4             [OLEAUT32.246]
3574  */
3575 HRESULT WINAPI VarI1FromI4(LONG lIn, CHAR* pcOut)
3576 {
3577         TRACE("( %ld, %p ), stub\n", lIn, pcOut );
3578
3579         if( lIn < CHAR_MIN || lIn > CHAR_MAX )
3580         {
3581                 return DISP_E_OVERFLOW;
3582         }
3583
3584         *pcOut = (CHAR) lIn;
3585
3586         return S_OK;
3587 }
3588
3589 /******************************************************************************
3590  *              VarI1FromR4             [OLEAUT32.247]
3591  */
3592 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, CHAR* pcOut)
3593 {
3594         TRACE("( %f, %p ), stub\n", fltIn, pcOut );
3595
3596     fltIn = round( fltIn );
3597         if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
3598         {
3599                 return DISP_E_OVERFLOW;
3600         }
3601
3602         *pcOut = (CHAR) fltIn;
3603
3604         return S_OK;
3605 }
3606
3607 /******************************************************************************
3608  *              VarI1FromR8             [OLEAUT32.248]
3609  */
3610 HRESULT WINAPI VarI1FromR8(double dblIn, CHAR* pcOut)
3611 {
3612         TRACE("( %f, %p ), stub\n", dblIn, pcOut );
3613
3614     dblIn = round( dblIn );
3615     if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
3616         {
3617                 return DISP_E_OVERFLOW;
3618         }
3619
3620         *pcOut = (CHAR) dblIn;
3621
3622         return S_OK;
3623 }
3624
3625 /******************************************************************************
3626  *              VarI1FromDate           [OLEAUT32.249]
3627  */
3628 HRESULT WINAPI VarI1FromDate(DATE dateIn, CHAR* pcOut)
3629 {
3630         TRACE("( %f, %p ), stub\n", dateIn, pcOut );
3631
3632     dateIn = round( dateIn );
3633         if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
3634         {
3635                 return DISP_E_OVERFLOW;
3636         }
3637
3638         *pcOut = (CHAR) dateIn;
3639
3640         return S_OK;
3641 }
3642
3643 /******************************************************************************
3644  *              VarI1FromStr            [OLEAUT32.251]
3645  */
3646 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CHAR* pcOut)
3647 {
3648         double dValue = 0.0;
3649         LPSTR pNewString = NULL;
3650
3651         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
3652
3653         /* Check if we have a valid argument
3654          */
3655         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3656         RemoveCharacterFromString( pNewString, "," );
3657         if( IsValidRealString( pNewString ) == FALSE )
3658         {
3659                 return DISP_E_TYPEMISMATCH;
3660         }
3661
3662         /* Convert the valid string to a floating point number.
3663          */
3664         dValue = atof( pNewString );
3665   
3666         /* We don't need the string anymore so free it.
3667          */
3668         HeapFree( GetProcessHeap(), 0, pNewString );
3669
3670         /* Check range of value.
3671      */
3672     dValue = round( dValue );
3673         if( dValue < CHAR_MIN || dValue > CHAR_MAX )
3674         {
3675                 return DISP_E_OVERFLOW;
3676         }
3677
3678         *pcOut = (CHAR) dValue;
3679
3680         return S_OK;
3681 }
3682
3683 /******************************************************************************
3684  *              VarI1FromBool           [OLEAUT32.253]
3685  */
3686 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
3687 {
3688         TRACE("( %d, %p ), stub\n", boolIn, pcOut );
3689
3690         *pcOut = (CHAR) boolIn;
3691
3692         return S_OK;
3693 }
3694
3695 /******************************************************************************
3696  *              VarI1FromUI2            [OLEAUT32.254]
3697  */
3698 HRESULT WINAPI VarI1FromUI2(USHORT uiIn, CHAR* pcOut)
3699 {
3700         TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3701
3702         if( uiIn > CHAR_MAX )
3703         {
3704                 return DISP_E_OVERFLOW;
3705         }
3706
3707         *pcOut = (CHAR) uiIn;
3708
3709         return S_OK;
3710 }
3711
3712 /******************************************************************************
3713  *              VarI1FromUI4            [OLEAUT32.255]
3714  */
3715 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, CHAR* pcOut)
3716 {
3717         TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
3718
3719         if( ulIn > CHAR_MAX )
3720         {
3721                 return DISP_E_OVERFLOW;
3722         }
3723
3724         *pcOut = (CHAR) ulIn;
3725
3726         return S_OK;
3727 }
3728
3729 /**********************************************************************
3730  *              VarI1FromCy [OLEAUT32.250]
3731  * Convert currency to signed char
3732  */
3733 HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
3734    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3735    
3736    if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
3737    
3738    *pcOut = (CHAR)t;
3739    return S_OK;
3740 }
3741
3742 /******************************************************************************
3743  *              VarUI2FromUI1           [OLEAUT32.257]
3744  */
3745 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
3746 {
3747         TRACE("( %d, %p ), stub\n", bIn, puiOut );
3748
3749         *puiOut = (USHORT) bIn;
3750
3751         return S_OK;
3752 }
3753
3754 /******************************************************************************
3755  *              VarUI2FromI2            [OLEAUT32.258]
3756  */
3757 HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
3758 {
3759         TRACE("( %d, %p ), stub\n", uiIn, puiOut );
3760
3761         if( uiIn < UI2_MIN )
3762         {
3763                 return DISP_E_OVERFLOW;
3764         }
3765
3766         *puiOut = (USHORT) uiIn;
3767
3768         return S_OK;
3769 }
3770
3771 /******************************************************************************
3772  *              VarUI2FromI4            [OLEAUT32.259]
3773  */
3774 HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
3775 {
3776         TRACE("( %ld, %p ), stub\n", lIn, puiOut );
3777
3778         if( lIn < UI2_MIN || lIn > UI2_MAX )
3779         {
3780                 return DISP_E_OVERFLOW;
3781         }
3782
3783         *puiOut = (USHORT) lIn;
3784
3785         return S_OK;
3786 }
3787
3788 /******************************************************************************
3789  *              VarUI2FromR4            [OLEAUT32.260]
3790  */
3791 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
3792 {
3793         TRACE("( %f, %p ), stub\n", fltIn, puiOut );
3794
3795     fltIn = round( fltIn );
3796         if( fltIn < UI2_MIN || fltIn > UI2_MAX )
3797         {
3798                 return DISP_E_OVERFLOW;
3799         }
3800
3801         *puiOut = (USHORT) fltIn;
3802
3803         return S_OK;
3804 }
3805
3806 /******************************************************************************
3807  *              VarUI2FromR8            [OLEAUT32.261]
3808  */
3809 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
3810 {
3811         TRACE("( %f, %p ), stub\n", dblIn, puiOut );
3812
3813     dblIn = round( dblIn );
3814     if( dblIn < UI2_MIN || dblIn > UI2_MAX )
3815         {
3816                 return DISP_E_OVERFLOW;
3817         }
3818
3819         *puiOut = (USHORT) dblIn;
3820
3821         return S_OK;
3822 }
3823
3824 /******************************************************************************
3825  *              VarUI2FromDate          [OLEAUT32.262]
3826  */
3827 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
3828 {
3829         TRACE("( %f, %p ), stub\n", dateIn, puiOut );
3830
3831     dateIn = round( dateIn );
3832         if( dateIn < UI2_MIN || dateIn > UI2_MAX )
3833         {
3834                 return DISP_E_OVERFLOW;
3835         }
3836
3837         *puiOut = (USHORT) dateIn;
3838
3839         return S_OK;
3840 }
3841
3842 /******************************************************************************
3843  *              VarUI2FromStr           [OLEAUT32.264]
3844  */
3845 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
3846 {
3847         double dValue = 0.0;
3848         LPSTR pNewString = NULL;
3849
3850         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
3851
3852         /* Check if we have a valid argument
3853          */
3854         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3855         RemoveCharacterFromString( pNewString, "," );
3856         if( IsValidRealString( pNewString ) == FALSE )
3857         {
3858                 return DISP_E_TYPEMISMATCH;
3859         }
3860
3861         /* Convert the valid string to a floating point number.
3862          */
3863         dValue = atof( pNewString );
3864   
3865         /* We don't need the string anymore so free it.
3866          */
3867         HeapFree( GetProcessHeap(), 0, pNewString );
3868
3869         /* Check range of value.
3870      */
3871     dValue = round( dValue );
3872         if( dValue < UI2_MIN || dValue > UI2_MAX )
3873         {
3874                 return DISP_E_OVERFLOW;
3875         }
3876
3877         *puiOut = (USHORT) dValue;
3878
3879         return S_OK;
3880 }
3881
3882 /******************************************************************************
3883  *              VarUI2FromBool          [OLEAUT32.266]
3884  */
3885 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
3886 {
3887         TRACE("( %d, %p ), stub\n", boolIn, puiOut );
3888
3889         *puiOut = (USHORT) boolIn;
3890
3891         return S_OK;
3892 }
3893
3894 /******************************************************************************
3895  *              VarUI2FromI1            [OLEAUT32.267]
3896  */
3897 HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
3898 {
3899         TRACE("( %c, %p ), stub\n", cIn, puiOut );
3900
3901         *puiOut = (USHORT) cIn;
3902
3903         return S_OK;
3904 }
3905
3906 /******************************************************************************
3907  *              VarUI2FromUI4           [OLEAUT32.268]
3908  */
3909 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
3910 {
3911         TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
3912
3913         if( ulIn < UI2_MIN || ulIn > UI2_MAX )
3914         {
3915                 return DISP_E_OVERFLOW;
3916         }
3917
3918         *puiOut = (USHORT) ulIn;
3919
3920         return S_OK;
3921 }
3922
3923 /******************************************************************************
3924  *              VarUI4FromStr           [OLEAUT32.277]
3925  */
3926 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
3927 {
3928         double dValue = 0.0;
3929         LPSTR pNewString = NULL;
3930
3931         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
3932
3933         /* Check if we have a valid argument
3934          */
3935         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3936         RemoveCharacterFromString( pNewString, "," );
3937         if( IsValidRealString( pNewString ) == FALSE )
3938         {
3939                 return DISP_E_TYPEMISMATCH;
3940         }
3941
3942         /* Convert the valid string to a floating point number.
3943          */
3944         dValue = atof( pNewString );
3945   
3946         /* We don't need the string anymore so free it.
3947          */
3948         HeapFree( GetProcessHeap(), 0, pNewString );
3949
3950         /* Check range of value.
3951      */
3952     dValue = round( dValue );
3953         if( dValue < UI4_MIN || dValue > UI4_MAX )
3954         {
3955                 return DISP_E_OVERFLOW;
3956         }
3957
3958         *pulOut = (ULONG) dValue;
3959
3960         return S_OK;
3961 }
3962
3963 /**********************************************************************
3964  *              VarUI2FromCy [OLEAUT32.263]
3965  * Convert currency to unsigned short
3966  */
3967 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
3968    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3969    
3970    if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
3971       
3972    *pusOut = (USHORT)t;
3973    
3974    return S_OK;
3975 }
3976
3977 /******************************************************************************
3978  *              VarUI4FromUI1           [OLEAUT32.270]
3979  */
3980 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
3981 {
3982         TRACE("( %d, %p ), stub\n", bIn, pulOut );
3983
3984         *pulOut = (USHORT) bIn;
3985
3986         return S_OK;
3987 }
3988
3989 /******************************************************************************
3990  *              VarUI4FromI2            [OLEAUT32.271]
3991  */
3992 HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
3993 {
3994         TRACE("( %d, %p ), stub\n", uiIn, pulOut );
3995
3996         if( uiIn < UI4_MIN )
3997         {
3998                 return DISP_E_OVERFLOW;
3999         }
4000
4001         *pulOut = (ULONG) uiIn;
4002
4003         return S_OK;
4004 }
4005
4006 /******************************************************************************
4007  *              VarUI4FromI4            [OLEAUT32.272]
4008  */
4009 HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
4010 {
4011         TRACE("( %ld, %p ), stub\n", lIn, pulOut );
4012
4013         if( lIn < UI4_MIN )
4014         {
4015                 return DISP_E_OVERFLOW;
4016         }
4017
4018         *pulOut = (ULONG) lIn;
4019
4020         return S_OK;
4021 }
4022
4023 /******************************************************************************
4024  *              VarUI4FromR4            [OLEAUT32.273]
4025  */
4026 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
4027 {
4028     fltIn = round( fltIn );
4029     if( fltIn < UI4_MIN || fltIn > UI4_MAX )
4030         {
4031                 return DISP_E_OVERFLOW;
4032         }
4033
4034         *pulOut = (ULONG) fltIn;
4035
4036         return S_OK;
4037 }
4038
4039 /******************************************************************************
4040  *              VarUI4FromR8            [OLEAUT32.274]
4041  */
4042 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
4043 {
4044         TRACE("( %f, %p ), stub\n", dblIn, pulOut );
4045
4046         dblIn = round( dblIn );
4047         if( dblIn < UI4_MIN || dblIn > UI4_MAX )
4048         {
4049                 return DISP_E_OVERFLOW;
4050         }
4051
4052         *pulOut = (ULONG) dblIn;
4053
4054         return S_OK;
4055 }
4056
4057 /******************************************************************************
4058  *              VarUI4FromDate          [OLEAUT32.275]
4059  */
4060 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
4061 {
4062         TRACE("( %f, %p ), stub\n", dateIn, pulOut );
4063
4064         dateIn = round( dateIn );
4065         if( dateIn < UI4_MIN || dateIn > UI4_MAX )
4066         {
4067                 return DISP_E_OVERFLOW;
4068         }
4069
4070         *pulOut = (ULONG) dateIn;
4071
4072         return S_OK;
4073 }
4074
4075 /******************************************************************************
4076  *              VarUI4FromBool          [OLEAUT32.279]
4077  */
4078 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
4079 {
4080         TRACE("( %d, %p ), stub\n", boolIn, pulOut );
4081
4082         *pulOut = (ULONG) boolIn;
4083
4084         return S_OK;
4085 }
4086
4087 /******************************************************************************
4088  *              VarUI4FromI1            [OLEAUT32.280]
4089  */
4090 HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
4091 {
4092         TRACE("( %c, %p ), stub\n", cIn, pulOut );
4093
4094         *pulOut = (ULONG) cIn;
4095
4096         return S_OK;
4097 }
4098
4099 /******************************************************************************
4100  *              VarUI4FromUI2           [OLEAUT32.281]
4101  */
4102 HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4103 {
4104         TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4105
4106         *pulOut = (ULONG) uiIn;
4107
4108         return S_OK;
4109 }
4110
4111 /**********************************************************************
4112  *              VarUI4FromCy [OLEAUT32.276]
4113  * Convert currency to unsigned long
4114  */
4115 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
4116    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4117    
4118    if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4119
4120    *pulOut = (ULONG)t;
4121
4122    return S_OK;
4123 }
4124
4125 /**********************************************************************
4126  *              VarCyFromUI1 [OLEAUT32.98]
4127  * Convert unsigned char to currency
4128  */
4129 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
4130     pcyOut->s.Hi = 0;
4131     pcyOut->s.Lo = ((ULONG)bIn) * 10000;
4132
4133     return S_OK;
4134 }
4135
4136 /**********************************************************************
4137  *              VarCyFromI2 [OLEAUT32.99]
4138  * Convert signed short to currency
4139  */
4140 HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
4141     if (sIn < 0) pcyOut->s.Hi = -1;
4142     else pcyOut->s.Hi = 0;
4143     pcyOut->s.Lo = ((ULONG)sIn) * 10000;
4144
4145     return S_OK;
4146 }
4147
4148 /**********************************************************************
4149  *              VarCyFromI4 [OLEAUT32.100]
4150  * Convert signed long to currency
4151  */
4152 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4153       double t = (double)lIn * (double)10000;
4154       pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4155       pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4156       if (lIn < 0) pcyOut->s.Hi--;
4157    
4158       return S_OK;
4159 }
4160
4161 /**********************************************************************
4162  *              VarCyFromR4 [OLEAUT32.101]
4163  * Convert float to currency
4164  */
4165 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
4166    double t = round((double)fltIn * (double)10000);
4167    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4168    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4169    if (fltIn < 0) pcyOut->s.Hi--;
4170    
4171    return S_OK;
4172 }
4173
4174 /**********************************************************************
4175  *              VarCyFromR8 [OLEAUT32.102]
4176  * Convert double to currency
4177  */
4178 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
4179    double t = round(dblIn * (double)10000);
4180    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4181    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4182    if (dblIn < 0) pcyOut->s.Hi--;
4183
4184    return S_OK;
4185 }
4186
4187 /**********************************************************************
4188  *              VarCyFromDate [OLEAUT32.103]
4189  * Convert date to currency
4190  */
4191 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
4192    double t = round((double)dateIn * (double)10000);
4193    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4194    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4195    if (dateIn < 0) pcyOut->s.Hi--;
4196
4197    return S_OK;
4198 }
4199
4200 /**********************************************************************
4201  *              VarCyFromStr [OLEAUT32.104]
4202  */
4203 HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
4204         FIXME("(%p, %08lx, %08lx, %p), stub.\n", strIn, lcid, dwFlags, pcyOut);
4205         return E_NOTIMPL;
4206 }
4207
4208  
4209 /**********************************************************************
4210  *              VarCyFromBool [OLEAUT32.106]
4211  * Convert boolean to currency
4212  */
4213 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
4214    if (boolIn < 0) pcyOut->s.Hi = -1;
4215    else pcyOut->s.Hi = 0;
4216    pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
4217    
4218    return S_OK;
4219 }
4220
4221 /**********************************************************************
4222  *              VarCyFromI1 [OLEAUT32.225]
4223  * Convert signed char to currency
4224  */
4225 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
4226    if (cIn < 0) pcyOut->s.Hi = -1;
4227    else pcyOut->s.Hi = 0;
4228    pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
4229    
4230    return S_OK;
4231 }
4232
4233 /**********************************************************************
4234  *              VarCyFromUI2 [OLEAUT32.226]
4235  * Convert unsigned short to currency
4236  */
4237 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
4238    pcyOut->s.Hi = 0;
4239    pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
4240    
4241    return S_OK;
4242 }
4243
4244 /**********************************************************************
4245  *              VarCyFromUI4 [OLEAUT32.227]
4246  * Convert unsigned long to currency
4247  */
4248 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4249    double t = (double)ulIn * (double)10000;
4250    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4251    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4252       
4253    return S_OK;
4254 }
4255
4256
4257 /**********************************************************************
4258  *              DosDateTimeToVariantTime [OLEAUT32.14]
4259  * Convert dos representation of time to the date and time representation
4260  * stored in a variant.
4261  */
4262 INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4263                                     DATE *pvtime)
4264 {
4265     struct tm t;
4266
4267     TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
4268     
4269     t.tm_sec = (wDosTime & 0x001f) * 2;
4270     t.tm_min = (wDosTime & 0x07e0) >> 5;
4271     t.tm_hour = (wDosTime & 0xf800) >> 11;
4272     
4273     t.tm_mday = (wDosDate & 0x001f);
4274     t.tm_mon = (wDosDate & 0x01e0) >> 5;
4275     t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
4276
4277     return TmToDATE( &t, pvtime );
4278 }
4279
4280
4281 /**********************************************************************
4282  *              VarParseNumFromStr [OLEAUT32.46]
4283  */
4284 HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
4285                                   NUMPARSE * pnumprs, BYTE * rgbDig)
4286 {
4287     int i,lastent=0;
4288     int cDig;
4289     FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
4290     FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
4291
4292     /* The other struct components are to be set by us */
4293
4294     memset(rgbDig,0,pnumprs->cDig);
4295
4296     cDig = 0;
4297     for (i=0; strIn[i] ;i++) {
4298         if ((strIn[i]>='0') && (strIn[i]<='9')) {
4299             if (pnumprs->cDig > cDig) {
4300                 *(rgbDig++)=strIn[i]-'0';
4301                 cDig++;
4302                 lastent = i;
4303             }
4304         }
4305     }
4306     pnumprs->cDig       = cDig;
4307
4308     /* FIXME: Just patching some values in */
4309     pnumprs->nPwr10     = 0;
4310     pnumprs->nBaseShift = 0;
4311     pnumprs->cchUsed    = lastent;
4312     pnumprs->dwOutFlags = NUMPRS_DECIMAL;
4313     return S_OK;
4314 }
4315
4316
4317 /**********************************************************************
4318  *              VarNumFromParseNum [OLEAUT32.47]
4319  */
4320 HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
4321                                   ULONG dwVtBits, VARIANT * pvar)
4322 {
4323     DWORD xint;
4324     int i;
4325     FIXME("(,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
4326
4327     xint = 0;
4328     for (i=0;i<pnumprs->cDig;i++)
4329         xint = xint*10 + rgbDig[i];
4330
4331     VariantInit(pvar);
4332     if (dwVtBits & VTBIT_I4) {
4333         V_VT(pvar) = VT_I4;
4334         V_UNION(pvar,intVal) = xint;
4335         return S_OK;
4336     }
4337     if (dwVtBits & VTBIT_R8) {
4338         V_VT(pvar) = VT_R8;
4339         V_UNION(pvar,dblVal) = xint;
4340         return S_OK;
4341     } else {
4342         FIXME("vtbitmask is unsupported %lx\n",dwVtBits);
4343         return E_FAIL;
4344     }
4345 }
4346
4347
4348 /**********************************************************************
4349  *              VariantTimeToDosDateTime [OLEAUT32.13]
4350  * Convert variant representation of time to the date and time representation
4351  * stored in dos.
4352  */
4353 INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
4354 {
4355     struct tm t;
4356     wDosTime = 0;
4357     wDosDate = 0;
4358
4359     TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate, *wDosTime, &pvtime );
4360
4361     if (DateToTm(pvtime, 0, &t) < 0) return 0;
4362
4363     *wDosTime = *wDosTime | (t.tm_sec / 2);
4364     *wDosTime = *wDosTime | (t.tm_min << 5);
4365     *wDosTime = *wDosTime | (t.tm_hour << 11);
4366
4367     *wDosDate = *wDosDate | t.tm_mday ;
4368     *wDosDate = *wDosDate | t.tm_mon << 5;
4369     *wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
4370
4371     return 1;
4372 }
4373
4374
4375 /***********************************************************************
4376  *              SystemTimeToVariantTime [OLEAUT32.184]
4377  */
4378 HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME  lpSystemTime, double *pvtime )
4379 {
4380     static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4381     static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4382
4383     struct tm t;
4384
4385     TRACE(" %d/%d/%d %d:%d:%d\n",
4386           lpSystemTime->wMonth, lpSystemTime->wDay,
4387           lpSystemTime->wYear, lpSystemTime->wHour,
4388           lpSystemTime->wMinute, lpSystemTime->wSecond);
4389
4390     if (lpSystemTime->wYear >= 1900)
4391     {
4392         t.tm_sec = lpSystemTime->wSecond;
4393         t.tm_min = lpSystemTime->wMinute;
4394         t.tm_hour = lpSystemTime->wHour;
4395
4396         t.tm_mday = lpSystemTime->wDay;
4397         t.tm_mon = lpSystemTime->wMonth;
4398         t.tm_year = lpSystemTime->wYear;
4399
4400         return TmToDATE( &t, pvtime );
4401     }
4402     else
4403     {
4404         t.tm_sec = lpSystemTime->wSecond;
4405         t.tm_min = lpSystemTime->wMinute;
4406         t.tm_hour = lpSystemTime->wHour;
4407
4408         if (isleap(lpSystemTime->wYear) )
4409             t.tm_mday = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - lpSystemTime->wDay;
4410         else
4411             t.tm_mday = Days_Per_Month[13 - lpSystemTime->wMonth] - lpSystemTime->wDay;
4412
4413         t.tm_mon = 13 - lpSystemTime->wMonth;
4414         t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
4415
4416         TmToDATE( &t, pvtime );
4417
4418         *pvtime *= -1;
4419
4420         return 1;
4421     }
4422
4423     return 0;
4424 }
4425
4426 /***********************************************************************
4427  *              VariantTimeToSystemTime [OLEAUT32.185]
4428  */
4429 HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME  lpSystemTime )
4430 {
4431     double t = 0, timeofday = 0;
4432
4433     static const BYTE Days_Per_Month[] =    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4434     static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4435
4436     /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4437     static const BYTE Month_Code[] =    {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4438     static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4439
4440     /* The Century_Code is used to find the Day of the Week */
4441     static const BYTE Century_Code[]  = {0, 6, 4, 2};
4442
4443     struct tm r;
4444
4445     TRACE(" Variant = %f SYSTEMTIME ptr %p", vtime, lpSystemTime);
4446
4447     if (vtime >= 0)
4448     {
4449
4450         if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4451
4452         lpSystemTime->wSecond = r.tm_sec;
4453         lpSystemTime->wMinute = r.tm_min;
4454         lpSystemTime->wHour = r.tm_hour;
4455         lpSystemTime->wDay = r.tm_mday;
4456         lpSystemTime->wMonth = r.tm_mon;
4457
4458         if (lpSystemTime->wMonth == 12)
4459             lpSystemTime->wMonth = 1;
4460         else
4461             lpSystemTime->wMonth++;
4462
4463         lpSystemTime->wYear = r.tm_year;
4464     }
4465     else
4466     {
4467         vtime = -1*vtime;
4468
4469         if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4470
4471         lpSystemTime->wSecond = r.tm_sec;
4472         lpSystemTime->wMinute = r.tm_min;
4473         lpSystemTime->wHour = r.tm_hour;
4474
4475         lpSystemTime->wMonth = 13 - r.tm_mon;
4476
4477         if (lpSystemTime->wMonth == 1)
4478             lpSystemTime->wMonth = 12;
4479         else
4480             lpSystemTime->wMonth--;
4481
4482         lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
4483
4484         if (!isleap(lpSystemTime->wYear) )
4485             lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
4486         else
4487             lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
4488
4489
4490     }
4491
4492     if (!isleap(lpSystemTime->wYear))
4493     {
4494         /*
4495           (Century_Code+Month_Code+Year_Code+Day) % 7
4496
4497           The century code repeats every 400 years , so the array
4498           works out like this,
4499
4500           Century_Code[0] is for 16th/20th Centry
4501           Century_Code[1] is for 17th/21th Centry
4502           Century_Code[2] is for 18th/22th Centry
4503           Century_Code[3] is for 19th/23th Centry
4504
4505           The year code is found with the formula (year + (year / 4))
4506           the "year" must be between 0 and 99 .
4507
4508           The Month Code (Month_Code[1]) starts with January and
4509           ends with December.
4510         */
4511
4512         lpSystemTime->wDayOfWeek = (
4513             Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
4514             ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4515             Month_Code[lpSystemTime->wMonth]+
4516             lpSystemTime->wDay) % 7;
4517
4518         if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4519         else lpSystemTime->wDayOfWeek -= 1;
4520     }
4521     else
4522     {
4523         lpSystemTime->wDayOfWeek = (
4524             Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
4525             ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4526             Month_Code_LY[lpSystemTime->wMonth]+
4527             lpSystemTime->wDay) % 7;
4528
4529         if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4530         else lpSystemTime->wDayOfWeek -= 1;
4531     }
4532
4533     t = floor(vtime);
4534     timeofday = vtime - t;
4535
4536     lpSystemTime->wMilliseconds = (timeofday
4537                                    - lpSystemTime->wHour*(1/24)
4538                                    - lpSystemTime->wMinute*(1/1440)
4539                                    - lpSystemTime->wSecond*(1/86400) )*(1/5184000);
4540
4541     return 1;
4542 }
4543
4544 /***********************************************************************
4545  *              VarUdateFromDate [OLEAUT32.331]
4546  */
4547 HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
4548 {
4549     HRESULT i = 0;
4550     static const BYTE Days_Per_Month[] =    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4551     static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4552
4553     TRACE("DATE = %f\n", (double)datein);
4554     i = VariantTimeToSystemTime(datein, &(pudateout->st) );
4555
4556     if (i)
4557     {
4558         pudateout->wDayOfYear = 0;
4559
4560         if (isleap(pudateout->st.wYear))
4561         {
4562             for (i =1; i<pudateout->st.wMonth; i++)
4563                 pudateout->wDayOfYear += Days_Per_Month[i];
4564         }
4565         else
4566         {
4567             for (i =1; i<pudateout->st.wMonth; i++)
4568                 pudateout->wDayOfYear += Days_Per_Month_LY[i];
4569         }
4570
4571         pudateout->wDayOfYear += pudateout->st.wDay;
4572         dwFlags = 0; /*VAR_VALIDDATE*/
4573     }
4574     else dwFlags = 0;
4575
4576     return i;
4577 }
4578
4579 /***********************************************************************
4580  *              VarDateFromUdate [OLEAUT32.330]
4581  */
4582 HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
4583                                 ULONG dwFlags, DATE *datein)
4584 {
4585     HRESULT i;
4586     double t = 0;
4587     TRACE(" %d/%d/%d %d:%d:%d\n",
4588           pudateout->st.wMonth, pudateout->st.wDay,
4589           pudateout->st.wYear, pudateout->st.wHour,
4590           pudateout->st.wMinute, pudateout->st.wSecond);
4591
4592
4593     i = SystemTimeToVariantTime(&(pudateout->st), &t);
4594     *datein = t;
4595
4596     if (i) dwFlags = 0; /*VAR_VALIDDATE*/
4597     else dwFlags = 0;
4598
4599     return i;
4600 }
4601
4602
4603 /**********************************************************************
4604  *              VarBstrCmp [OLEAUT32.440]
4605  *
4606  * flags can be: 
4607  *   NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4608  *   NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4609  *
4610  */
4611 HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
4612 {
4613     DWORD r;
4614
4615     FIXME("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
4616
4617     if((!left) || (!right))
4618         return VARCMP_NULL;
4619
4620     if(flags&NORM_IGNORECASE)
4621         r = lstrcmpiW(left,right);
4622     else
4623         r = lstrcmpW(left,right);
4624
4625     if(r<0)
4626         return VARCMP_LT;
4627     if(r>0)
4628         return VARCMP_GT;
4629
4630     return VARCMP_EQ;
4631 }
4632
4633 /**********************************************************************
4634  *              VarBstrCat [OLEAUT32.439]
4635  */
4636 HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
4637 {
4638     BSTR result;
4639
4640     TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
4641
4642     if( (!left) || (!right) || (!out) )
4643         return 0;
4644
4645     result = SysAllocStringLen(left, lstrlenW(left)+lstrlenW(right));
4646     lstrcatW(result,right);
4647
4648     *out = result;
4649
4650     return 1;
4651 }
4652