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