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