VarAdd: set 'rc' correctly from BSTR addition.
[wine] / dlls / oleaut32 / variant.c
1 /*
2  * VARIANT
3  *
4  * Copyright 1998 Jean-Claude Cote
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * NOTES
21  *   This implements the low-level and hi-level APIs for manipulating VARIANTs.
22  *   The low-level APIs are used to do data coercion between different data types.
23  *   The hi-level APIs are built on top of these low-level APIs and handle
24  *   initialization, copying, destroying and changing the type of VARIANTs.
25  *
26  * TODO:
27  *   - The Variant APIs do not support international languages, currency
28  *     types, number formating and calendar.  They only support U.S. English format.
29  *   - The Variant APIs do not the following types: IUknown, IDispatch, DECIMAL and SafeArray.
30  *     The prototypes for these are commented out in the oleauto.h file.  They need
31  *     to be implemented and cases need to be added to the switches of the  existing APIs.
32  *   - The parsing of date for the VarDateFromStr is not complete.
33  *   - The date manipulations do not support dates prior to 1900.
34  *   - The parsing does not accept as many formats as the Windows implementation.
35  */
36
37 #include "config.h"
38
39 #include <string.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <math.h>
43 #include <time.h>
44
45 #ifdef HAVE_FLOAT_H
46 # include <float.h>
47 #endif
48
49 #define NONAMELESSUNION
50 #define NONAMELESSSTRUCT
51 #include "windef.h"
52 #include "oleauto.h"
53 #include "heap.h"
54 #include "wine/debug.h"
55 #include "winerror.h"
56 #include "parsedt.h"
57 #include "typelib.h"
58 #include "winternl.h"
59
60 WINE_DEFAULT_DEBUG_CHANNEL(ole);
61
62 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
63
64 #ifndef FLT_MAX
65 # ifdef MAXFLOAT
66 #  define FLT_MAX MAXFLOAT
67 # else
68 #  error "Can't find #define for MAXFLOAT/FLT_MAX"
69 # endif
70 #endif
71
72 #undef CHAR_MAX
73 #undef CHAR_MIN
74 static const char CHAR_MAX = 127;
75 static const char CHAR_MIN = -128;
76 static const BYTE UI1_MAX = 255;
77 static const BYTE UI1_MIN = 0;
78 static const unsigned short UI2_MAX = 65535;
79 static const unsigned short UI2_MIN = 0;
80 static const short I2_MAX = 32767;
81 static const short I2_MIN =  -32768;
82 static const unsigned long UI4_MAX = 4294967295U;
83 static const unsigned long UI4_MIN = 0;
84 static const long I4_MAX = 2147483647;
85 static const long I4_MIN = -(2147483648U);
86 static const DATE DATE_MIN = -657434;
87 static const DATE DATE_MAX = 2958465;
88
89 /* the largest valid type
90  */
91 #define VT_MAXVALIDTYPE VT_CLSID
92
93 /* This mask is used to set a flag in wReserved1 of
94  * the VARIANTARG structure. The flag indicates if
95  * the API function is using an inner variant or not.
96  */
97 #define PROCESSING_INNER_VARIANT 0x0001
98
99 /* General use buffer.
100  */
101 #define BUFFER_MAX 1024
102 static char pBuffer[BUFFER_MAX];
103
104 /*
105  * Note a leap year is one that is a multiple of 4
106  * but not of a 100.  Except if it is a multiple of
107  * 400 then it is a leap year.
108  */
109
110 /*
111  * Use 365 days/year and a manual calculation for leap year days
112  * to keep arithmetic simple
113  */
114 static const double DAYS_IN_ONE_YEAR = 365.0;
115
116 /*
117  * Token definitions for Varient Formatting
118  * Worked out by experimentation on a w2k machine. Doesnt appear to be
119  *   documented anywhere obviously so keeping definitions internally
120  *
121  */
122 /* Pre defined tokens */
123 #define TOK_COPY 0x00
124 #define TOK_END  0x02
125 #define LARGEST_TOKENID 6
126
127 /* Mapping of token name to id put into the tokenized form
128    Note testing on W2K shows aaaa and oooo are not parsed??!! */
129 #define TOK_COLON  0x03
130 #define TOK_SLASH  0x04
131 #define TOK_c      0x05
132 #define TOK_d      0x08
133 #define TOK_dd     0x09
134 #define TOK_ddd    0x0a
135 #define TOK_dddd   0x0b
136 #define TOK_ddddd  0x0c
137 #define TOK_dddddd 0x0d
138 #define TOK_w      0x0f
139 #define TOK_ww     0x10
140 #define TOK_m      0x11
141 #define TOK_mm     0x12
142 #define TOK_mmm    0x13
143 #define TOK_mmmm   0x14
144 #define TOK_q      0x06
145 #define TOK_y      0x15
146 #define TOK_yy     0x16
147 #define TOK_yyyy   0x18
148 #define TOK_h      0x1e
149 #define TOK_Hh     0x1f
150 #define TOK_N      0x1a
151 #define TOK_Nn     0x1b
152 #define TOK_S      0x1c
153 #define TOK_Ss     0x1d
154 #define TOK_ttttt  0x07
155 #define TOK_AMsPM  0x2f
156 #define TOK_amspm  0x32
157 #define TOK_AsP    0x30
158 #define TOK_asp    0x33
159 #define TOK_AMPM   0x2e
160
161 typedef struct tagFORMATTOKEN {
162     char  *str;
163     BYTE   tokenSize;
164     BYTE   tokenId;
165     int    varTypeRequired;
166 } FORMATTOKEN;
167
168 typedef struct tagFORMATHDR {
169     BYTE   len;
170     BYTE   hex3;
171     BYTE   hex6;
172     BYTE   reserved[8];
173 } FORMATHDR;
174
175 FORMATTOKEN formatTokens[] = {           /* FIXME: Only date formats so far */
176     {":"     ,   1,  TOK_COLON  , 0},
177     {"/"     ,   1,  TOK_SLASH  , 0},
178     {"c"     ,   1,  TOK_c      , VT_DATE},
179     {"dddddd",   6,  TOK_dddddd , VT_DATE},
180     {"ddddd" ,   5,  TOK_ddddd  , VT_DATE},
181     {"dddd"  ,   4,  TOK_dddd   , VT_DATE},
182     {"ddd"   ,   3,  TOK_ddd    , VT_DATE},
183     {"dd"    ,   2,  TOK_dd     , VT_DATE},
184     {"d"     ,   1,  TOK_d      , VT_DATE},
185     {"ww"    ,   2,  TOK_ww     , VT_DATE},
186     {"w"     ,   1,  TOK_w      , VT_DATE},
187     {"mmmm"  ,   4,  TOK_mmmm   , VT_DATE},
188     {"mmm"   ,   3,  TOK_mmm    , VT_DATE},
189     {"mm"    ,   2,  TOK_mm     , VT_DATE},
190     {"m"     ,   1,  TOK_m      , VT_DATE},
191     {"q"     ,   1,  TOK_q      , VT_DATE},
192     {"yyyy"  ,   4,  TOK_yyyy   , VT_DATE},
193     {"yy"    ,   2,  TOK_yy     , VT_DATE},
194     {"y"     ,   1,  TOK_y      , VT_DATE},
195     {"h"     ,   1,  TOK_h      , VT_DATE},
196     {"Hh"    ,   2,  TOK_Hh     , VT_DATE},
197     {"Nn"    ,   2,  TOK_Nn     , VT_DATE},
198     {"N"     ,   1,  TOK_N      , VT_DATE},
199     {"S"     ,   1,  TOK_S      , VT_DATE},
200     {"Ss"    ,   2,  TOK_Ss     , VT_DATE},
201     {"ttttt" ,   5,  TOK_ttttt  , VT_DATE},
202     {"AM/PM" ,   5,  TOK_AMsPM  , VT_DATE},
203     {"am/pm" ,   5,  TOK_amspm  , VT_DATE},
204     {"A/P"   ,   3,  TOK_AsP    , VT_DATE},
205     {"a/p"   ,   3,  TOK_asp    , VT_DATE},
206     {"AMPM"  ,   4,  TOK_AMPM   , VT_DATE},
207     {0x00    ,   0,  0          , VT_NULL}
208 };
209
210 /******************************************************************************
211  *         DateTimeStringToTm   [INTERNAL]
212  *
213  * Converts a string representation of a date and/or time to a tm structure.
214  *
215  * Note this function uses the postgresql date parsing functions found
216  * in the parsedt.c file.
217  *
218  * Returns TRUE if successful.
219  *
220  * Note: This function does not parse the day of the week,
221  * daylight savings time. It will only fill the followin fields in
222  * the tm struct, tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
223  *
224  ******************************************************************************/
225 static BOOL DateTimeStringToTm( OLECHAR* strIn, DWORD dwFlags, struct tm* pTm )
226 {
227         BOOL res = FALSE;
228         double          fsec;
229         int             tzp;
230         int             dtype;
231         int             nf;
232         char       *field[MAXDATEFIELDS];
233         int             ftype[MAXDATEFIELDS];
234         char            lowstr[MAXDATELEN + 1];
235         char* strDateTime = NULL;
236
237         /* Convert the string to ASCII since this is the only format
238          * postgesql can handle.
239          */
240         strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
241
242         if( strDateTime != NULL )
243         {
244                 /* Make sure we don't go over the maximum length
245                  * accepted by postgesql.
246                  */
247                 if( strlen( strDateTime ) <= MAXDATELEN )
248                 {
249                         if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
250                         {
251                                 if( dwFlags & VAR_DATEVALUEONLY )
252                                 {
253                                         /* Get the date information.
254                                          * It returns 0 if date information was
255                                          * present and 1 if only time information was present.
256                                          * -1 if an error occures.
257                                          */
258                                         if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
259                                         {
260                                                 /* Eliminate the time information since we
261                                                  * were asked to get date information only.
262                                                  */
263                                                 pTm->tm_sec = 0;
264                                                 pTm->tm_min = 0;
265                                                 pTm->tm_hour = 0;
266                                                 res = TRUE;
267                                         }
268                                 }
269                                 if( dwFlags & VAR_TIMEVALUEONLY )
270                                 {
271                                         /* Get time information only.
272                                          */
273                                         if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
274                                         {
275                                                 res = TRUE;
276                                         }
277                                 }
278                                 else
279                                 {
280                                         /* Get both date and time information.
281                                          * It returns 0 if date information was
282                                          * present and 1 if only time information was present.
283                                          * -1 if an error occures.
284                                          */
285                                         if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
286                                         {
287                                                 res = TRUE;
288                                         }
289                                 }
290                         }
291                 }
292                 HeapFree( GetProcessHeap(), 0, strDateTime );
293         }
294
295         return res;
296 }
297
298
299
300
301
302
303 /******************************************************************************
304  *         TmToDATE     [INTERNAL]
305  *
306  * The date is implemented using an 8 byte floating-point number.
307  * Days are represented by whole numbers increments starting with 0.00 has
308  * being December 30 1899, midnight.
309  * The hours are expressed as the fractional part of the number.
310  * December 30 1899 at midnight = 0.00
311  * January 1 1900 at midnight = 2.00
312  * January 4 1900 at 6 AM = 5.25
313  * January 4 1900 at noon = 5.50
314  * December 29 1899 at midnight = -1.00
315  * December 18 1899 at midnight = -12.00
316  * December 18 1899 at 6AM = -12.25
317  * December 18 1899 at 6PM = -12.75
318  * December 19 1899 at midnight = -11.00
319  * The tm structure is as follows:
320  * struct tm {
321  *                int tm_sec;      seconds after the minute - [0,59]
322  *                int tm_min;      minutes after the hour - [0,59]
323  *                int tm_hour;     hours since midnight - [0,23]
324  *                int tm_mday;     day of the month - [1,31]
325  *                int tm_mon;      months since January - [0,11]
326  *                int tm_year;     years
327  *                int tm_wday;     days since Sunday - [0,6]
328  *                int tm_yday;     days since January 1 - [0,365]
329  *                int tm_isdst;    daylight savings time flag
330  *                };
331  *
332  * Note: This function does not use the tm_wday, tm_yday, tm_wday,
333  * and tm_isdst fields of the tm structure. And only converts years
334  * after 1900.
335  *
336  * Returns TRUE if successful.
337  */
338 static BOOL TmToDATE( struct tm* pTm, DATE *pDateOut )
339 {
340     int leapYear = 0;
341
342     /* Hmmm... An uninitialized Date in VB is December 30 1899 so
343        Start at 0. This is the way DATE is defined. */
344
345     /* Start at 1. This is the way DATE is defined.
346      * January 1, 1900 at Midnight is 1.00.
347      * January 1, 1900 at 6AM is 1.25.
348      * and so on.
349      */
350     *pDateOut = 1;
351
352     if( (pTm->tm_year - 1900) >= 0 ) {
353
354         /* Add the number of days corresponding to
355          * tm_year.
356          */
357         *pDateOut += (pTm->tm_year - 1900) * 365;
358
359         /* Add the leap days in the previous years between now and 1900.
360          * Note a leap year is one that is a multiple of 4
361          * but not of a 100.  Except if it is a multiple of
362          * 400 then it is a leap year.
363          * Copied + reversed functionality into TmToDate
364          */
365         *pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
366         *pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
367         *pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
368
369         /* Set the leap year flag if the
370          * current year specified by tm_year is a
371          * leap year. This will be used to add a day
372          * to the day count.
373          */
374         if( isleap( pTm->tm_year ) )
375             leapYear = 1;
376
377         /* Add the number of days corresponding to
378          * the month. (remember tm_mon is 0..11)
379          */
380         switch( pTm->tm_mon )
381         {
382         case 1:
383             *pDateOut += 31;
384             break;
385         case 2:
386             *pDateOut += ( 59 + leapYear );
387             break;
388         case 3:
389             *pDateOut += ( 90 + leapYear );
390             break;
391         case 4:
392             *pDateOut += ( 120 + leapYear );
393             break;
394         case 5:
395             *pDateOut += ( 151 + leapYear );
396             break;
397         case 6:
398             *pDateOut += ( 181 + leapYear );
399             break;
400         case 7:
401             *pDateOut += ( 212 + leapYear );
402             break;
403         case 8:
404             *pDateOut += ( 243 + leapYear );
405             break;
406         case 9:
407             *pDateOut += ( 273 + leapYear );
408             break;
409         case 10:
410             *pDateOut += ( 304 + leapYear );
411             break;
412         case 11:
413             *pDateOut += ( 334 + leapYear );
414             break;
415         }
416         /* Add the number of days in this month.
417          */
418         *pDateOut += pTm->tm_mday;
419
420         /* Add the number of seconds, minutes, and hours
421          * to the DATE. Note these are the fracionnal part
422          * of the DATE so seconds / number of seconds in a day.
423          */
424     } else {
425         *pDateOut = 0;
426     }
427
428     *pDateOut += pTm->tm_hour / 24.0;
429     *pDateOut += pTm->tm_min / 1440.0;
430     *pDateOut += pTm->tm_sec / 86400.0;
431     return TRUE;
432 }
433
434 /******************************************************************************
435  *         DateToTm     [INTERNAL]
436  *
437  * This function converts a windows DATE to a tm structure.
438  *
439  * It does not fill all the fields of the tm structure.
440  * Here is a list of the fields that are filled:
441  * tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
442  *
443  * Note this function does not support dates before the January 1, 1900
444  * or ( dateIn < 2.0 ).
445  *
446  * Returns TRUE if successful.
447  */
448 BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )
449 {
450     double decimalPart = 0.0;
451     double wholePart = 0.0;
452
453     memset(pTm,0,sizeof(*pTm));
454
455     /* Because of the nature of DATE format which
456      * associates 2.0 to January 1, 1900. We will
457      * remove 1.0 from the whole part of the DATE
458      * so that in the following code 1.0
459      * will correspond to January 1, 1900.
460      * This simplifies the processing of the DATE value.
461      */
462     decimalPart = fmod( dateIn, 1.0 ); /* Do this before the -1, otherwise 0.xx goes negative */
463     dateIn -= 1.0;
464     wholePart = (double) floor( dateIn );
465
466     if( !(dwFlags & VAR_TIMEVALUEONLY) )
467     {
468         unsigned int nDay = 0;
469         int leapYear = 0;
470         double yearsSince1900 = 0;
471
472         /* Hard code dates smaller than January 1, 1900. */
473         if( dateIn < 2.0 ) {
474             pTm->tm_year = 1899;
475             pTm->tm_mon  = 11; /* December as tm_mon is 0..11 */
476             if( dateIn < 1.0 ) {
477                 pTm->tm_mday  = 30;
478                 dateIn = dateIn * -1.0; /* Ensure +ve for time calculation */
479                 decimalPart = decimalPart * -1.0; /* Ensure +ve for time calculation */
480             } else {
481                 pTm->tm_mday  = 31;
482             }
483
484         } else {
485
486             /* Start at 1900, this is where the DATE time 0.0 starts.
487              */
488             pTm->tm_year = 1900;
489             /* find in what year the day in the "wholePart" falls into.
490              * add the value to the year field.
491              */
492             yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 );
493             pTm->tm_year += yearsSince1900;
494             /* determine if this is a leap year.
495              */
496             if( isleap( pTm->tm_year ) )
497             {
498                 leapYear = 1;
499                 wholePart++;
500             }
501
502             /* find what day of that year the "wholePart" corresponds to.
503              * Note: nDay is in [1-366] format
504              */
505             nDay = (((unsigned int) wholePart) - ((pTm->tm_year-1900) * DAYS_IN_ONE_YEAR ));
506
507             /* Remove the leap days in the previous years between now and 1900.
508              * Note a leap year is one that is a multiple of 4
509              * but not of a 100.  Except if it is a multiple of
510              * 400 then it is a leap year.
511              * Copied + reversed functionality from TmToDate
512              */
513             nDay -= ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
514             nDay += ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
515             nDay -= ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
516
517             /* Set the tm_yday value.
518              * Note: The day must be converted from [1-366] to [0-365]
519              */
520             /*pTm->tm_yday = nDay - 1;*/
521             /* find which month this day corresponds to.
522              */
523             if( nDay <= 31 )
524             {
525                 pTm->tm_mday = nDay;
526                 pTm->tm_mon = 0;
527             }
528             else if( nDay <= ( 59 + leapYear ) )
529             {
530                 pTm->tm_mday = nDay - 31;
531                 pTm->tm_mon = 1;
532             }
533             else if( nDay <= ( 90 + leapYear ) )
534             {
535                 pTm->tm_mday = nDay - ( 59 + leapYear );
536                 pTm->tm_mon = 2;
537             }
538             else if( nDay <= ( 120 + leapYear ) )
539             {
540                 pTm->tm_mday = nDay - ( 90 + leapYear );
541                 pTm->tm_mon = 3;
542             }
543             else if( nDay <= ( 151 + leapYear ) )
544             {
545                 pTm->tm_mday = nDay - ( 120 + leapYear );
546                 pTm->tm_mon = 4;
547             }
548             else if( nDay <= ( 181 + leapYear ) )
549             {
550                 pTm->tm_mday = nDay - ( 151 + leapYear );
551                 pTm->tm_mon = 5;
552             }
553             else if( nDay <= ( 212 + leapYear ) )
554             {
555                 pTm->tm_mday = nDay - ( 181 + leapYear );
556                 pTm->tm_mon = 6;
557             }
558             else if( nDay <= ( 243 + leapYear ) )
559             {
560                 pTm->tm_mday = nDay - ( 212 + leapYear );
561                 pTm->tm_mon = 7;
562             }
563             else if( nDay <= ( 273 + leapYear ) )
564             {
565                 pTm->tm_mday = nDay - ( 243 + leapYear );
566                 pTm->tm_mon = 8;
567             }
568             else if( nDay <= ( 304 + leapYear ) )
569             {
570                 pTm->tm_mday = nDay - ( 273 + leapYear );
571                 pTm->tm_mon = 9;
572             }
573             else if( nDay <= ( 334 + leapYear ) )
574             {
575                 pTm->tm_mday = nDay - ( 304 + leapYear );
576                 pTm->tm_mon = 10;
577             }
578             else if( nDay <= ( 365 + leapYear ) )
579             {
580                 pTm->tm_mday = nDay - ( 334 + leapYear );
581                 pTm->tm_mon = 11;
582             }
583         }
584     }
585     if( !(dwFlags & VAR_DATEVALUEONLY) )
586     {
587         /* find the number of seconds in this day.
588          * fractional part times, hours, minutes, seconds.
589          * Note: 0.1 is hack to ensure figures come out in whole numbers
590          *   due to floating point inaccuracies
591          */
592         pTm->tm_hour = (int) ( decimalPart * 24 );
593         pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
594         /* Note: 0.1 is hack to ensure seconds come out in whole numbers
595              due to floating point inaccuracies */
596         pTm->tm_sec = (int) (( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 ) + 0.1);
597     }
598     return TRUE;
599 }
600
601
602
603 /******************************************************************************
604  *         SizeOfVariantData    [INTERNAL]
605  *
606  * This function finds the size of the data referenced by a Variant based
607  * the type "vt" of the Variant.
608  */
609 static int SizeOfVariantData( VARIANT* parg )
610 {
611     int size = 0;
612     switch( V_VT(parg) & VT_TYPEMASK )
613     {
614     case( VT_I2 ):
615         size = sizeof(short);
616         break;
617     case( VT_INT ):
618         size = sizeof(int);
619         break;
620     case( VT_I4 ):
621         size = sizeof(long);
622         break;
623     case( VT_UI1 ):
624         size = sizeof(BYTE);
625         break;
626     case( VT_UI2 ):
627         size = sizeof(unsigned short);
628         break;
629     case( VT_UINT ):
630         size = sizeof(unsigned int);
631         break;
632     case( VT_UI4 ):
633         size = sizeof(unsigned long);
634         break;
635     case( VT_R4 ):
636         size = sizeof(float);
637         break;
638     case( VT_R8 ):
639         size = sizeof(double);
640         break;
641     case( VT_DATE ):
642         size = sizeof(DATE);
643         break;
644     case( VT_BOOL ):
645         size = sizeof(VARIANT_BOOL);
646         break;
647     case( VT_BSTR ):
648     case( VT_DISPATCH ):
649     case( VT_UNKNOWN ):
650         size = sizeof(void*);
651         break;
652     case( VT_CY ):
653         size = sizeof(CY);
654         break;
655     case( VT_DECIMAL ):         /* hmm, tricky, DECIMAL is only VT_BYREF */
656     default:
657         FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK );
658         break;
659     }
660
661     return size;
662 }
663 /******************************************************************************
664  *         StringDupAtoBstr             [INTERNAL]
665  *
666  */
667 static BSTR StringDupAtoBstr( char* strIn )
668 {
669         BSTR bstr = NULL;
670         OLECHAR* pNewString = NULL;
671         UNICODE_STRING usBuffer;
672         
673         RtlCreateUnicodeStringFromAsciiz( &usBuffer, strIn );
674         pNewString = usBuffer.Buffer;
675         
676         bstr = SysAllocString( pNewString );
677         RtlFreeUnicodeString( &usBuffer );
678         return bstr;
679 }
680
681 /******************************************************************************
682  *              round           [INTERNAL]
683  *
684  * Round the double value to the nearest integer value.
685  */
686 static double round( double d )
687 {
688    double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
689     BOOL bEvenNumber = FALSE;
690     int nSign = 0;
691
692     /* Save the sign of the number
693      */
694    nSign = (d >= 0.0) ? 1 : -1;
695     d = fabs( d );
696
697         /* Remove the decimals.
698          */
699    integerValue = floor( d );
700
701     /* Set the Even flag.  This is used to round the number when
702      * the decimals are exactly 1/2.  If the integer part is
703      * odd the number is rounded up. If the integer part
704      * is even the number is rounded down.  Using this method
705      * numbers are rounded up|down half the time.
706      */
707    bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
708
709     /* Remove the integral part of the number.
710      */
711     decimals = d - integerValue;
712
713         /* Note: Ceil returns the smallest integer that is greater that x.
714          * and floor returns the largest integer that is less than or equal to x.
715          */
716     if( decimals > 0.5 )
717     {
718         /* If the decimal part is greater than 1/2
719          */
720         roundedValue = ceil( d );
721     }
722     else if( decimals < 0.5 )
723     {
724         /* If the decimal part is smaller than 1/2
725          */
726         roundedValue = floor( d );
727     }
728     else
729     {
730         /* the decimals are exactly 1/2 so round according to
731          * the bEvenNumber flag.
732          */
733         if( bEvenNumber )
734         {
735             roundedValue = floor( d );
736         }
737         else
738         {
739             roundedValue = ceil( d );
740         }
741     }
742
743         return roundedValue * nSign;
744 }
745
746 /******************************************************************************
747  *              RemoveCharacterFromString               [INTERNAL]
748  *
749  * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
750  */
751 static void RemoveCharacterFromString( LPSTR str, LPSTR strOfCharToRemove )
752 {
753         LPSTR pNewString = NULL;
754         LPSTR strToken = NULL;
755
756         /* Check if we have a valid argument
757          */
758         if( str != NULL )
759         {
760                 pNewString = strdup( str );
761                 str[0] = '\0';
762                 strToken = strtok( pNewString, strOfCharToRemove );
763                 while( strToken != NULL ) {
764                         strcat( str, strToken );
765                         strToken = strtok( NULL, strOfCharToRemove );
766                 }
767                 free( pNewString );
768         }
769         return;
770 }
771
772 /******************************************************************************
773  *              GetValidRealString              [INTERNAL]
774  *
775  * Checks if the string is of proper format to be converted to a real value.
776  */
777 static BOOL IsValidRealString( LPSTR strRealString )
778 {
779         /* Real values that have a decimal point are required to either have
780          * digits before or after the decimal point.  We will assume that
781          * we do not have any digits at either position. If we do encounter
782          * some we will disable this flag.
783          */
784         BOOL bDigitsRequired = TRUE;
785         /* Processed fields in the string representation of the real number.
786          */
787         BOOL bWhiteSpaceProcessed = FALSE;
788         BOOL bFirstSignProcessed = FALSE;
789         BOOL bFirstDigitsProcessed = FALSE;
790         BOOL bDecimalPointProcessed = FALSE;
791         BOOL bSecondDigitsProcessed = FALSE;
792         BOOL bExponentProcessed = FALSE;
793         BOOL bSecondSignProcessed = FALSE;
794         BOOL bThirdDigitsProcessed = FALSE;
795         /* Assume string parameter "strRealString" is valid and try to disprove it.
796          */
797         BOOL bValidRealString = TRUE;
798
799         /* Used to count the number of tokens in the "strRealString".
800          */
801         LPSTR strToken = NULL;
802         int nTokens = 0;
803         LPSTR pChar = NULL;
804
805         /* Check if we have a valid argument
806          */
807         if( strRealString == NULL )
808         {
809                 bValidRealString = FALSE;
810         }
811
812         if( bValidRealString == TRUE )
813         {
814                 /* Make sure we only have ONE token in the string.
815                  */
816                 strToken = strtok( strRealString, " " );
817                 while( strToken != NULL ) {
818                         nTokens++;
819                         strToken = strtok( NULL, " " );
820                 }
821
822                 if( nTokens != 1 )
823                 {
824                         bValidRealString = FALSE;
825                 }
826         }
827
828
829         /* Make sure this token contains only valid characters.
830          * The string argument to atof has the following form:
831          * [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
832          * Whitespace consists of space and|or <TAB> characters, which are ignored.
833      * Sign is either plus '+' or minus '-'.
834      * Digits are one or more decimal digits.
835      * Note: If no digits appear before the decimal point, at least one must
836      * appear after the decimal point.
837      * The decimal digits may be followed by an exponent.
838      * An Exponent consists of an introductory letter ( D, d, E, or e) and
839          * an optionally signed decimal integer.
840          */
841         pChar = strRealString;
842         while( bValidRealString == TRUE && *pChar != '\0' )
843         {
844                 switch( *pChar )
845                 {
846                 /* If whitespace...
847                  */
848                 case ' ':
849                 case '\t':
850                         if( bWhiteSpaceProcessed ||
851                                 bFirstSignProcessed ||
852                                 bFirstDigitsProcessed ||
853                                 bDecimalPointProcessed ||
854                                 bSecondDigitsProcessed ||
855                                 bExponentProcessed ||
856                                 bSecondSignProcessed ||
857                                 bThirdDigitsProcessed )
858                         {
859                                 bValidRealString = FALSE;
860                         }
861                         break;
862                 /* If sign...
863                  */
864                 case '+':
865                 case '-':
866                         if( bFirstSignProcessed == FALSE )
867                         {
868                                 if( bFirstDigitsProcessed ||
869                                         bDecimalPointProcessed ||
870                                         bSecondDigitsProcessed ||
871                                         bExponentProcessed ||
872                                         bSecondSignProcessed ||
873                                         bThirdDigitsProcessed )
874                                 {
875                                         bValidRealString = FALSE;
876                                 }
877                                 bWhiteSpaceProcessed = TRUE;
878                                 bFirstSignProcessed = TRUE;
879                         }
880                         else if( bSecondSignProcessed == FALSE )
881                         {
882                 /* Note: The exponent must be present in
883                                  * order to accept the second sign...
884                                  */
885                                 if( bExponentProcessed == FALSE ||
886                                         bThirdDigitsProcessed ||
887                                         bDigitsRequired )
888                                 {
889                                         bValidRealString = FALSE;
890                                 }
891                                 bFirstSignProcessed = TRUE;
892                                 bWhiteSpaceProcessed = TRUE;
893                                 bFirstDigitsProcessed = TRUE;
894                                 bDecimalPointProcessed = TRUE;
895                                 bSecondDigitsProcessed = TRUE;
896                                 bSecondSignProcessed = TRUE;
897                         }
898                         break;
899
900                 /* If decimals...
901                  */
902                 case '0':
903                 case '1':
904                 case '2':
905                 case '3':
906                 case '4':
907                 case '5':
908                 case '6':
909                 case '7':
910                 case '8':
911                 case '9':
912                         if( bFirstDigitsProcessed == FALSE )
913                         {
914                                 if( bDecimalPointProcessed ||
915                                         bSecondDigitsProcessed ||
916                                         bExponentProcessed ||
917                                         bSecondSignProcessed ||
918                                         bThirdDigitsProcessed )
919                                 {
920                                         bValidRealString = FALSE;
921                                 }
922                                 bFirstSignProcessed = TRUE;
923                                 bWhiteSpaceProcessed = TRUE;
924                                 /* We have found some digits before the decimal point
925                                  * so disable the "Digits required" flag.
926                                  */
927                                 bDigitsRequired = FALSE;
928                         }
929                         else if( bSecondDigitsProcessed == FALSE )
930                         {
931                                 if( bExponentProcessed ||
932                                         bSecondSignProcessed ||
933                                         bThirdDigitsProcessed )
934                                 {
935                                         bValidRealString = FALSE;
936                                 }
937                                 bFirstSignProcessed = TRUE;
938                                 bWhiteSpaceProcessed = TRUE;
939                                 bFirstDigitsProcessed = TRUE;
940                                 bDecimalPointProcessed = TRUE;
941                                 /* We have found some digits after the decimal point
942                                  * so disable the "Digits required" flag.
943                                  */
944                                 bDigitsRequired = FALSE;
945                         }
946                         else if( bThirdDigitsProcessed == FALSE )
947                         {
948                                 /* Getting here means everything else should be processed.
949                  * If we get anything else than a decimal following this
950                  * digit it will be flagged by the other cases, so
951                                  * we do not really need to do anything in here.
952                                  */
953                         }
954                         break;
955                 /* If DecimalPoint...
956                  */
957                 case '.':
958                         if( bDecimalPointProcessed ||
959                                 bSecondDigitsProcessed ||
960                                 bExponentProcessed ||
961                                 bSecondSignProcessed ||
962                                 bThirdDigitsProcessed )
963                         {
964                                 bValidRealString = FALSE;
965                         }
966                         bFirstSignProcessed = TRUE;
967                         bWhiteSpaceProcessed = TRUE;
968                         bFirstDigitsProcessed = TRUE;
969                         bDecimalPointProcessed = TRUE;
970                         break;
971                 /* If Exponent...
972                  */
973                 case 'e':
974                 case 'E':
975                 case 'd':
976                 case 'D':
977                         if( bExponentProcessed ||
978                                 bSecondSignProcessed ||
979                                 bThirdDigitsProcessed ||
980                                 bDigitsRequired )
981                         {
982                                 bValidRealString = FALSE;
983                         }
984                         bFirstSignProcessed = TRUE;
985                         bWhiteSpaceProcessed = TRUE;
986                         bFirstDigitsProcessed = TRUE;
987                         bDecimalPointProcessed = TRUE;
988                         bSecondDigitsProcessed = TRUE;
989                         bExponentProcessed = TRUE;
990                         break;
991                 default:
992                         bValidRealString = FALSE;
993                         break;
994                 }
995                 /* Process next character.
996                  */
997                 pChar++;
998         }
999
1000         /* If the required digits were not present we have an invalid
1001          * string representation of a real number.
1002          */
1003         if( bDigitsRequired == TRUE )
1004         {
1005                 bValidRealString = FALSE;
1006         }
1007
1008         return bValidRealString;
1009 }
1010
1011
1012 /******************************************************************************
1013  *              Coerce  [INTERNAL]
1014  *
1015  * This function dispatches execution to the proper conversion API
1016  * to do the necessary coercion.
1017  *
1018  * FIXME: Passing down dwFlags to the conversion functions is wrong, this
1019  *        is a different flagmask. Check MSDN.
1020  */
1021 static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
1022 {
1023         HRESULT res = S_OK;
1024         unsigned short vtFrom = 0;
1025         vtFrom = V_VT(ps) & VT_TYPEMASK;
1026
1027
1028         /* Note: Since "long" and "int" values both have 4 bytes and are
1029          * both signed integers "int" will be treated as "long" in the
1030          * following code.
1031          * The same goes for their unsigned versions.
1032          */
1033
1034         /* Trivial Case: If the coercion is from two types that are
1035          * identical then we can blindly copy from one argument to another.*/
1036         if ((vt==vtFrom))
1037            return VariantCopy(pd,ps);
1038
1039         /* Cases requiring thought*/
1040         switch( vt )
1041         {
1042
1043     case( VT_EMPTY ):
1044         res = VariantClear( pd );
1045         break;
1046     case( VT_NULL ):
1047         res = VariantClear( pd );
1048         if( res == S_OK )
1049         {
1050             V_VT(pd) = VT_NULL;
1051         }
1052         break;
1053         case( VT_I1 ):
1054                 switch( vtFrom )
1055         {
1056                 case( VT_I2 ):
1057                         res = VarI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,cVal) );
1058                         break;
1059                 case( VT_INT ):
1060                 case( VT_I4 ):
1061                         res = VarI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,cVal) );
1062                         break;
1063                 case( VT_UI1 ):
1064                         res = VarI1FromUI1( V_UNION(ps,bVal), &V_UNION(pd,cVal) );
1065                         break;
1066                 case( VT_UI2 ):
1067                         res = VarI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cVal) );
1068                         break;
1069                 case( VT_UINT ):
1070                 case( VT_UI4 ):
1071                         res = VarI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cVal) );
1072                         break;
1073                 case( VT_R4 ):
1074                         res = VarI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,cVal) );
1075                         break;
1076                 case( VT_R8 ):
1077                         res = VarI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,cVal) );
1078                         break;
1079                 case( VT_DATE ):
1080                         res = VarI1FromDate( V_UNION(ps,date), &V_UNION(pd,cVal) );
1081                         break;
1082                 case( VT_BOOL ):
1083                         res = VarI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,cVal) );
1084                         break;
1085                 case( VT_BSTR ):
1086                         res = VarI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cVal) );
1087                         break;
1088                 case( VT_CY ):
1089                         res = VarI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,cVal) );
1090                         break;
1091                 case( VT_DISPATCH ):
1092                         /*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
1093                 case( VT_DECIMAL ):
1094                         /*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
1095                 case( VT_UNKNOWN ):
1096                 default:
1097                         res = DISP_E_TYPEMISMATCH;
1098                         FIXME("Coercion from %d to VT_I1\n", vtFrom );
1099                         break;
1100                 }
1101                 break;
1102
1103         case( VT_I2 ):
1104                 switch( vtFrom )
1105                 {
1106                 case( VT_I1 ):
1107                         res = VarI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,iVal) );
1108                         break;
1109                 case( VT_INT ):
1110                 case( VT_I4 ):
1111                         res = VarI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,iVal) );
1112                         break;
1113                 case( VT_UI1 ):
1114                         res = VarI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,iVal) );
1115                         break;
1116                 case( VT_UI2 ):
1117                         res = VarI2FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,iVal) );
1118                         break;
1119                 case( VT_UINT ):
1120                 case( VT_UI4 ):
1121                         res = VarI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,iVal) );
1122                         break;
1123                 case( VT_R4 ):
1124                         res = VarI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,iVal) );
1125                         break;
1126                 case( VT_R8 ):
1127                         res = VarI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,iVal) );
1128                         break;
1129                 case( VT_DATE ):
1130                         res = VarI2FromDate( V_UNION(ps,date), &V_UNION(pd,iVal) );
1131                         break;
1132                 case( VT_BOOL ):
1133                         res = VarI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,iVal) );
1134                         break;
1135                 case( VT_BSTR ):
1136                         res = VarI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,iVal) );
1137                         break;
1138                 case( VT_CY ):
1139                         res = VarI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,iVal) );
1140                         break;
1141                 case( VT_DISPATCH ):
1142                         /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
1143                 case( VT_DECIMAL ):
1144                         /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
1145                 case( VT_UNKNOWN ):
1146                 default:
1147                         res = DISP_E_TYPEMISMATCH;
1148                         FIXME("Coercion from %d to VT_I2\n", vtFrom);
1149                         break;
1150                 }
1151                 break;
1152
1153         case( VT_INT ):
1154         case( VT_I4 ):
1155                 switch( vtFrom )
1156                 {
1157                 case( VT_EMPTY ):
1158                         V_UNION(pd,lVal) = 0;
1159                         res = S_OK;
1160                         break;
1161                 case( VT_I1 ):
1162                         res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
1163                         break;
1164                 case( VT_I2 ):
1165                         res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
1166
1167                         break;
1168                 case( VT_ERROR ):
1169                         V_UNION(pd,lVal) = V_UNION(pd,scode);
1170                         res = S_OK;
1171                         break;
1172         case( VT_INT ):
1173         case( VT_I4 ):
1174             res = VariantCopy( pd, ps );
1175             break;
1176                 case( VT_UI1 ):
1177                         res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
1178                         break;
1179                 case( VT_UI2 ):
1180                         res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
1181                         break;
1182                 case( VT_UINT ):
1183                 case( VT_UI4 ):
1184                         res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
1185                         break;
1186                 case( VT_R4 ):
1187                         res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
1188                         break;
1189                 case( VT_R8 ):
1190                         res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
1191                         break;
1192                 case( VT_DATE ):
1193                         res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
1194                         break;
1195                 case( VT_BOOL ):
1196                         res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
1197                         break;
1198                 case( VT_BSTR ):
1199                         res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
1200                         break;
1201                 case( VT_CY ):
1202                         res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
1203                         break;
1204                 case( VT_DISPATCH ):
1205                         /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1206                 case( VT_DECIMAL ):
1207                         /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1208                 case( VT_UNKNOWN ):
1209                 default:
1210                         res = DISP_E_TYPEMISMATCH;
1211                         FIXME("Coercion from %d to VT_INT/VT_I4\n", vtFrom);
1212                         break;
1213                 }
1214                 break;
1215
1216         case( VT_UI1 ):
1217                 switch( vtFrom )
1218                 {
1219                 case( VT_I1 ):
1220                         res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
1221                         break;
1222                 case( VT_I2 ):
1223                         res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
1224                         break;
1225                 case( VT_INT ):
1226                 case( VT_I4 ):
1227                         res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
1228                         break;
1229         case( VT_UI1 ):
1230             res = VariantCopy( pd, ps );
1231             break;
1232                 case( VT_UI2 ):
1233                         res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
1234                         break;
1235                 case( VT_UINT ):
1236                 case( VT_UI4 ):
1237                         res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
1238                         break;
1239                 case( VT_R4 ):
1240                         res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
1241                         break;
1242                 case( VT_R8 ):
1243                         res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
1244                         break;
1245                 case( VT_DATE ):
1246                         res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
1247                         break;
1248                 case( VT_BOOL ):
1249                         res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
1250                         break;
1251                 case( VT_BSTR ):
1252                         res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
1253                         break;
1254                 case( VT_CY ):
1255                         res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
1256                         break;
1257                 case( VT_DISPATCH ):
1258                         /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1259                 case( VT_DECIMAL ):
1260                         /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1261                 case( VT_UNKNOWN ):
1262                 default:
1263                         res = DISP_E_TYPEMISMATCH;
1264                         FIXME("Coercion from %d to VT_UI1\n", vtFrom);
1265                         break;
1266                 }
1267                 break;
1268
1269         case( VT_UI2 ):
1270                 switch( vtFrom )
1271                 {
1272                 case( VT_I1 ):
1273                         res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
1274                         break;
1275                 case( VT_I2 ):
1276                         res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
1277                         break;
1278                 case( VT_INT ):
1279                 case( VT_I4 ):
1280                         res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
1281                         break;
1282                 case( VT_UI1 ):
1283                         res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
1284                         break;
1285         case( VT_UI2 ):
1286             res = VariantCopy( pd, ps );
1287             break;
1288                 case( VT_UINT ):
1289                 case( VT_UI4 ):
1290                         res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
1291                         break;
1292                 case( VT_R4 ):
1293                         res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
1294                         break;
1295                 case( VT_R8 ):
1296                         res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
1297                         break;
1298                 case( VT_DATE ):
1299                         res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
1300                         break;
1301                 case( VT_BOOL ):
1302                         res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
1303                         break;
1304                 case( VT_BSTR ):
1305                         res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
1306                         break;
1307                 case( VT_CY ):
1308                         res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
1309                         break;
1310                 case( VT_DISPATCH ):
1311                         /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1312                 case( VT_DECIMAL ):
1313                         /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1314                 case( VT_UNKNOWN ):
1315                 default:
1316                         res = DISP_E_TYPEMISMATCH;
1317                         FIXME("Coercion from %d to VT_UI2\n", vtFrom);
1318                         break;
1319                 }
1320                 break;
1321
1322         case( VT_UINT ):
1323         case( VT_UI4 ):
1324                 switch( vtFrom )
1325                 {
1326                 case( VT_I1 ):
1327                         res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
1328                         break;
1329                 case( VT_I2 ):
1330                         res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
1331                         break;
1332                 case( VT_INT ):
1333                 case( VT_I4 ):
1334                         res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
1335                         break;
1336                 case( VT_UI1 ):
1337                         res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
1338                         break;
1339                 case( VT_UI2 ):
1340                         res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
1341                         break;
1342         case( VT_UI4 ):
1343             res = VariantCopy( pd, ps );
1344             break;
1345                 case( VT_R4 ):
1346                         res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
1347                         break;
1348                 case( VT_R8 ):
1349                         res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
1350                         break;
1351                 case( VT_DATE ):
1352                         res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
1353                         break;
1354                 case( VT_BOOL ):
1355                         res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
1356                         break;
1357                 case( VT_BSTR ):
1358                         res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
1359                         break;
1360                 case( VT_CY ):
1361                         res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
1362                         break;
1363                 case( VT_DISPATCH ):
1364                         /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1365                 case( VT_DECIMAL ):
1366                         /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1367                 case( VT_UNKNOWN ):
1368                 default:
1369                         res = DISP_E_TYPEMISMATCH;
1370                         FIXME("Coercion from %d to VT_UINT/VT_UI4\n", vtFrom);
1371                         break;
1372                 }
1373                 break;
1374
1375         case( VT_R4 ):
1376                 switch( vtFrom )
1377                 {
1378                 case( VT_I1 ):
1379                         res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
1380                         break;
1381                 case( VT_I2 ):
1382                         res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
1383                         break;
1384                 case( VT_INT ):
1385                 case( VT_I4 ):
1386                         res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
1387                         break;
1388                 case( VT_UI1 ):
1389                         res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
1390                         break;
1391                 case( VT_UI2 ):
1392                         res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
1393                         break;
1394                 case( VT_UINT ):
1395                 case( VT_UI4 ):
1396                         res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
1397                         break;
1398                 case( VT_R4 ):
1399                     res = VariantCopy( pd, ps );
1400                     break;
1401                 case( VT_R8 ):
1402                         res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
1403                         break;
1404                 case( VT_DATE ):
1405                         res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
1406                         break;
1407                 case( VT_BOOL ):
1408                         res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
1409                         break;
1410                 case( VT_BSTR ):
1411                         res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
1412                         break;
1413                 case( VT_CY ):
1414                         res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
1415                         break;
1416                 case( VT_ERROR ):
1417                         V_UNION(pd,fltVal) = V_UNION(ps,scode);
1418                         res = S_OK;
1419                         break;
1420                 case( VT_DISPATCH ):
1421                         /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1422                 case( VT_DECIMAL ):
1423                         /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1424                 case( VT_UNKNOWN ):
1425                 default:
1426                         res = DISP_E_TYPEMISMATCH;
1427                         FIXME("Coercion from %d to VT_R4\n", vtFrom);
1428                         break;
1429                 }
1430                 break;
1431
1432         case( VT_R8 ):
1433                 switch( vtFrom )
1434                 {
1435                 case( VT_I1 ):
1436                         res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
1437                         break;
1438                 case( VT_I2 ):
1439                         res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
1440                         break;
1441                 case( VT_INT ):
1442                 case( VT_I4 ):
1443                         res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
1444                         break;
1445                 case( VT_UI1 ):
1446                         res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
1447                         break;
1448                 case( VT_UI2 ):
1449                         res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
1450                         break;
1451                 case( VT_UINT ):
1452                 case( VT_UI4 ):
1453                         res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
1454                         break;
1455                 case( VT_R4 ):
1456                         res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
1457                         break;
1458         case( VT_R8 ):
1459             res = VariantCopy( pd, ps );
1460             break;
1461                 case( VT_DATE ):
1462                         res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
1463                         break;
1464                 case( VT_BOOL ):
1465                         res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
1466                         break;
1467                 case( VT_BSTR ):
1468                         res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
1469                         break;
1470                 case( VT_CY ):
1471                         res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
1472                         break;
1473                 case( VT_DISPATCH ):
1474                         /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1475                 case( VT_DECIMAL ):
1476                         /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1477                 case( VT_UNKNOWN ):
1478                 default:
1479                         res = DISP_E_TYPEMISMATCH;
1480                         FIXME("Coercion from %d to VT_R8\n", vtFrom);
1481                         break;
1482                 }
1483                 break;
1484
1485         case( VT_DATE ):
1486                 switch( vtFrom )
1487                 {
1488                 case( VT_I1 ):
1489                         res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
1490                         break;
1491                 case( VT_I2 ):
1492                         res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
1493                         break;
1494                 case( VT_INT ):
1495                         res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
1496                         break;
1497                 case( VT_I4 ):
1498                         res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
1499                         break;
1500                 case( VT_UI1 ):
1501                         res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
1502                         break;
1503                 case( VT_UI2 ):
1504                         res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
1505                         break;
1506                 case( VT_UINT ):
1507                         res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
1508                         break;
1509                 case( VT_UI4 ):
1510                         res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
1511                         break;
1512                 case( VT_R4 ):
1513                         res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
1514                         break;
1515                 case( VT_R8 ):
1516                         res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
1517                         break;
1518                 case( VT_BOOL ):
1519                         res = VarDateFromBool( V_UNION(ps,boolVal), &V_UNION(pd,date) );
1520                         break;
1521                 case( VT_BSTR ):
1522                         res = VarDateFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,date) );
1523                         break;
1524                 case( VT_CY ):
1525                         res = VarDateFromCy( V_UNION(ps,cyVal), &V_UNION(pd,date) );
1526                         break;
1527                 case( VT_DISPATCH ):
1528                         /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1529                 case( VT_DECIMAL ):
1530                         /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1531                 case( VT_UNKNOWN ):
1532                 default:
1533                         res = DISP_E_TYPEMISMATCH;
1534                         FIXME("Coercion from %d to VT_DATE\n", vtFrom);
1535                         break;
1536                 }
1537                 break;
1538
1539         case( VT_BOOL ):
1540                 switch( vtFrom )
1541                 {
1542                 case( VT_EMPTY ):
1543                         res = S_OK;
1544                         V_UNION(pd,boolVal) = VARIANT_FALSE;
1545                         break;
1546                 case( VT_I1 ):
1547                         res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
1548                         break;
1549                 case( VT_I2 ):
1550                         res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
1551                         break;
1552                 case( VT_INT ):
1553                         res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
1554                         break;
1555                 case( VT_I4 ):
1556                         res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
1557                         break;
1558                 case( VT_UI1 ):
1559                         res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
1560                         break;
1561                 case( VT_UI2 ):
1562                         res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
1563                         break;
1564                 case( VT_UINT ):
1565                         res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
1566                         break;
1567                 case( VT_UI4 ):
1568                         res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
1569                         break;
1570                 case( VT_R4 ):
1571                         res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
1572                         break;
1573                 case( VT_R8 ):
1574                         res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
1575                         break;
1576                 case( VT_DATE ):
1577                         res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
1578                         break;
1579                 case( VT_BSTR ):
1580                         res = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
1581                         break;
1582                 case( VT_CY ):
1583                         res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
1584                         break;
1585                 case( VT_DISPATCH ):
1586                         /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1587                 case( VT_DECIMAL ):
1588                         /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1589                 case( VT_UNKNOWN ):
1590                 default:
1591                         res = DISP_E_TYPEMISMATCH;
1592                         FIXME("Coercion from %d to VT_BOOL\n", vtFrom);
1593                         break;
1594                 }
1595                 break;
1596
1597         case( VT_BSTR ):
1598                 switch( vtFrom )
1599                 {
1600                 case( VT_EMPTY ):
1601                         if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
1602                                 res = S_OK;
1603                         else
1604                                 res = E_OUTOFMEMORY;
1605                         break;
1606                 case( VT_I1 ):
1607                         res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
1608                         break;
1609                 case( VT_I2 ):
1610                         res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
1611                         break;
1612                 case( VT_INT ):
1613                         res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
1614                         break;
1615                 case( VT_I4 ):
1616                         res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
1617                         break;
1618                 case( VT_UI1 ):
1619                         res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
1620                         break;
1621                 case( VT_UI2 ):
1622                         res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
1623                         break;
1624                 case( VT_UINT ):
1625                         res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
1626                         break;
1627                 case( VT_UI4 ):
1628                         res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
1629                         break;
1630                 case( VT_R4 ):
1631                         res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
1632                         break;
1633                 case( VT_R8 ):
1634                         res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
1635                         break;
1636                 case( VT_DATE ):
1637                         res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
1638                         break;
1639                 case( VT_BOOL ):
1640                         res = VarBstrFromBool( V_UNION(ps,boolVal), lcid, 0, &V_UNION(pd,bstrVal) );
1641                         break;
1642                 case( VT_BSTR ):
1643                         res = VariantCopy( pd, ps );
1644                         break;
1645                 case( VT_CY ):
1646                         res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
1647                         break;
1648                 case( VT_DISPATCH ):
1649                         /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1650                 case( VT_DECIMAL ):
1651                         /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1652                 case( VT_UNKNOWN ):
1653                 default:
1654                         res = DISP_E_TYPEMISMATCH;
1655                         FIXME("Coercion from %d to VT_BSTR\n", vtFrom);
1656                         break;
1657                 }
1658                 break;
1659
1660      case( VT_CY ):
1661         switch( vtFrom )
1662           {
1663           case( VT_I1 ):
1664              res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
1665              break;
1666           case( VT_I2 ):
1667              res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
1668              break;
1669           case( VT_INT ):
1670              res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
1671              break;
1672           case( VT_I4 ):
1673              res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
1674              break;
1675           case( VT_UI1 ):
1676              res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
1677              break;
1678           case( VT_UI2 ):
1679              res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
1680              break;
1681           case( VT_UINT ):
1682              res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
1683              break;
1684           case( VT_UI4 ):
1685              res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
1686              break;
1687           case( VT_R4 ):
1688              res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
1689              break;
1690           case( VT_R8 ):
1691              res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
1692              break;
1693           case( VT_DATE ):
1694              res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1695              break;
1696           case( VT_BOOL ):
1697              res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1698              break;
1699           case( VT_CY ):
1700              res = VariantCopy( pd, ps );
1701              break;
1702           case( VT_BSTR ):
1703              res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
1704              break;
1705           case( VT_DISPATCH ):
1706              /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1707           case( VT_DECIMAL ):
1708              /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1709              break;
1710           case( VT_UNKNOWN ):
1711           default:
1712              res = DISP_E_TYPEMISMATCH;
1713              FIXME("Coercion from %d to VT_CY\n", vtFrom);
1714              break;
1715           }
1716         break;
1717
1718         case( VT_UNKNOWN ):
1719             switch (vtFrom) {
1720             case VT_DISPATCH:
1721                 if (V_DISPATCH(ps) == NULL) {
1722                         V_UNKNOWN(pd) = NULL;
1723                 } else {
1724                         res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1725                 }
1726                 break;
1727             case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4:
1728             case VT_R4: case VT_R8: case VT_CY: case VT_DATE:
1729             case VT_BSTR: case VT_ERROR: case VT_BOOL:
1730             case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1:
1731             case VT_UI2: case VT_UI4: case VT_I8: case VT_UI8: case VT_INT:
1732             case VT_UINT: case VT_VOID: case VT_HRESULT: case VT_PTR:
1733             case VT_SAFEARRAY: case VT_CARRAY: case VT_USERDEFINED:
1734             case VT_LPSTR: case VT_LPWSTR: case VT_RECORD: case VT_FILETIME:
1735             case VT_BLOB: case VT_STREAM: case VT_STORAGE:
1736             case VT_STREAMED_OBJECT: case VT_STORED_OBJECT: case VT_BLOB_OBJECT:
1737             case VT_CF: case VT_CLSID:
1738                 res = DISP_E_TYPEMISMATCH;
1739                 break;
1740             default:
1741                 FIXME("Coercion from %d to VT_UNKNOWN unhandled.\n", vtFrom);
1742                 res = DISP_E_BADVARTYPE;
1743                 break;
1744             }
1745             break;
1746
1747         case( VT_DISPATCH ):
1748             switch (vtFrom) {
1749             case VT_UNKNOWN:
1750                 if (V_UNION(ps,punkVal) == NULL) {
1751                         V_UNION(pd,pdispVal) = NULL;
1752                 } else {
1753                         res = IUnknown_QueryInterface(V_UNION(ps,punkVal), &IID_IDispatch, (LPVOID*)&V_UNION(pd,pdispVal));
1754                 }
1755                 break;
1756             case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4:
1757             case VT_R4: case VT_R8: case VT_CY: case VT_DATE:
1758             case VT_BSTR: case VT_ERROR: case VT_BOOL:
1759             case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1:
1760             case VT_UI2: case VT_UI4: case VT_I8: case VT_UI8: case VT_INT:
1761             case VT_UINT: case VT_VOID: case VT_HRESULT: case VT_PTR:
1762             case VT_SAFEARRAY: case VT_CARRAY: case VT_USERDEFINED:
1763             case VT_LPSTR: case VT_LPWSTR: case VT_RECORD: case VT_FILETIME:
1764             case VT_BLOB: case VT_STREAM: case VT_STORAGE:
1765             case VT_STREAMED_OBJECT: case VT_STORED_OBJECT: case VT_BLOB_OBJECT:
1766             case VT_CF: case VT_CLSID:
1767                 res = DISP_E_TYPEMISMATCH;
1768                 break;
1769             default:
1770                 FIXME("Coercion from %d to VT_DISPATCH unhandled.\n", vtFrom);
1771                 res = DISP_E_BADVARTYPE;
1772                 break;
1773             }
1774             break;
1775
1776         default:
1777                 res = DISP_E_TYPEMISMATCH;
1778                 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1779                 break;
1780         }
1781
1782         return res;
1783 }
1784
1785 /******************************************************************************
1786  *              ValidateVtRange [INTERNAL]
1787  *
1788  * Used internally by the hi-level Variant API to determine
1789  * if the vartypes are valid.
1790  */
1791 static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
1792 {
1793     /* if by value we must make sure it is in the
1794      * range of the valid types.
1795      */
1796     if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1797     {
1798         return DISP_E_BADVARTYPE;
1799     }
1800     return S_OK;
1801 }
1802
1803
1804 /******************************************************************************
1805  *              ValidateVartype [INTERNAL]
1806  *
1807  * Used internally by the hi-level Variant API to determine
1808  * if the vartypes are valid.
1809  */
1810 static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
1811 {
1812         HRESULT res = S_OK;
1813
1814         /* check if we have a valid argument.
1815          */
1816         if( vt & VT_BYREF )
1817     {
1818         /* if by reference check that the type is in
1819          * the valid range and that it is not of empty or null type
1820          */
1821         if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1822             ( vt & VT_TYPEMASK ) == VT_NULL ||
1823                         ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1824                 {
1825                         res = DISP_E_BADVARTYPE;
1826                 }
1827
1828     }
1829     else
1830     {
1831         res = ValidateVtRange( vt );
1832     }
1833
1834         return res;
1835 }
1836
1837 /******************************************************************************
1838  *              ValidateVt      [INTERNAL]
1839  *
1840  * Used internally by the hi-level Variant API to determine
1841  * if the vartypes are valid.
1842  */
1843 static HRESULT WINAPI ValidateVt( VARTYPE vt )
1844 {
1845         HRESULT res = S_OK;
1846
1847         /* check if we have a valid argument.
1848          */
1849         if( vt & VT_BYREF )
1850     {
1851         /* if by reference check that the type is in
1852          * the valid range and that it is not of empty or null type
1853          */
1854         if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1855             ( vt & VT_TYPEMASK ) == VT_NULL ||
1856                         ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1857                 {
1858                         res = DISP_E_BADVARTYPE;
1859                 }
1860
1861     }
1862     else
1863     {
1864         res = ValidateVtRange( vt );
1865     }
1866
1867         return res;
1868 }
1869
1870
1871
1872
1873
1874 /******************************************************************************
1875  *              VariantInit     [OLEAUT32.8]
1876  *
1877  * Initializes the Variant.  Unlike VariantClear it does not interpret
1878  * the current contents of the Variant.
1879  */
1880 void WINAPI VariantInit(VARIANTARG* pvarg)
1881 {
1882   TRACE("(%p)\n",pvarg);
1883
1884   memset(pvarg, 0, sizeof (VARIANTARG));
1885   V_VT(pvarg) = VT_EMPTY;
1886
1887   return;
1888 }
1889
1890 /******************************************************************************
1891  *              VariantClear    [OLEAUT32.9]
1892  *
1893  * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1894  * sets the wReservedX field to 0.      The current contents of the VARIANT are
1895  * freed.  If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1896  * released. If VT_ARRAY the array is freed.
1897  */
1898 HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
1899 {
1900   HRESULT res = S_OK;
1901   TRACE("(%p)\n",pvarg);
1902
1903   res = ValidateVariantType( V_VT(pvarg) );
1904   if( res == S_OK )
1905   {
1906     if( !( V_VT(pvarg) & VT_BYREF ) )
1907     {
1908       /*
1909        * The VT_ARRAY flag is a special case of a safe array.
1910        */
1911       if ( (V_VT(pvarg) & VT_ARRAY) != 0)
1912       {
1913         SafeArrayDestroy(V_UNION(pvarg,parray));
1914       }
1915       else
1916       {
1917         switch( V_VT(pvarg) & VT_TYPEMASK )
1918         {
1919           case( VT_BSTR ):
1920             SysFreeString( V_UNION(pvarg,bstrVal) );
1921             break;
1922           case( VT_DISPATCH ):
1923             if(V_UNION(pvarg,pdispVal)!=NULL)
1924               IDispatch_Release(V_UNION(pvarg,pdispVal));
1925             break;
1926           case( VT_VARIANT ):
1927             VariantClear(V_UNION(pvarg,pvarVal));
1928             break;
1929           case( VT_UNKNOWN ):
1930             if(V_UNION(pvarg,punkVal)!=NULL)
1931               IUnknown_Release(V_UNION(pvarg,punkVal));
1932             break;
1933           case( VT_SAFEARRAY ):
1934             SafeArrayDestroy(V_UNION(pvarg,parray));
1935             break;
1936           default:
1937             break;
1938         }
1939       }
1940     }
1941
1942     /*
1943      * Empty all the fields and mark the type as empty.
1944      */
1945     memset(pvarg, 0, sizeof (VARIANTARG));
1946     V_VT(pvarg) = VT_EMPTY;
1947   }
1948
1949   return res;
1950 }
1951
1952 /******************************************************************************
1953  *              VariantCopy     [OLEAUT32.10]
1954  *
1955  * Frees up the designation variant and makes a copy of the source.
1956  */
1957 HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
1958 {
1959   HRESULT res = S_OK;
1960
1961   TRACE("(%p, %p), vt=%d\n", pvargDest, pvargSrc, V_VT(pvargSrc));
1962
1963   res = ValidateVariantType( V_VT(pvargSrc) );
1964
1965   /* If the pointer are to the same variant we don't need
1966    * to do anything.
1967    */
1968   if( pvargDest != pvargSrc && res == S_OK )
1969   {
1970     VariantClear( pvargDest ); /* result is not checked */
1971
1972     if( V_VT(pvargSrc) & VT_BYREF )
1973     {
1974       /* In the case of byreference we only need
1975        * to copy the pointer.
1976        */
1977       pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1978       V_VT(pvargDest) = V_VT(pvargSrc);
1979     }
1980     else
1981     {
1982       /*
1983        * The VT_ARRAY flag is another way to designate a safe array.
1984        */
1985       if (V_VT(pvargSrc) & VT_ARRAY)
1986       {
1987         SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1988       }
1989       else
1990       {
1991         /* In the case of by value we need to
1992          * copy the actual value. In the case of
1993          * VT_BSTR a copy of the string is made,
1994          * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1995          * called to increment the object's reference count.
1996          */
1997         switch( V_VT(pvargSrc) & VT_TYPEMASK )
1998         {
1999           case( VT_BSTR ):
2000             V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
2001             break;
2002           case( VT_DISPATCH ):
2003             V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
2004             if (V_UNION(pvargDest,pdispVal)!=NULL)
2005               IDispatch_AddRef(V_UNION(pvargDest,pdispVal));
2006             break;
2007           case( VT_VARIANT ):
2008             VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
2009             break;
2010           case( VT_UNKNOWN ):
2011             V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
2012             if (V_UNION(pvargDest,pdispVal)!=NULL)
2013               IUnknown_AddRef(V_UNION(pvargDest,punkVal));
2014             break;
2015           case( VT_SAFEARRAY ):
2016             SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
2017             break;
2018           default:
2019             pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
2020             break;
2021         }
2022       }
2023       V_VT(pvargDest) = V_VT(pvargSrc);
2024       dump_Variant(pvargDest);
2025     }
2026   }
2027
2028   return res;
2029 }
2030
2031
2032 /******************************************************************************
2033  *              VariantCopyInd  [OLEAUT32.11]
2034  *
2035  * Frees up the destination variant and makes a copy of the source.  If
2036  * the source is of type VT_BYREF it performs the necessary indirections.
2037  */
2038 HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
2039 {
2040   HRESULT res = S_OK;
2041
2042   TRACE("(%p, %p)\n", pvargDest, pvargSrc);
2043
2044   res = ValidateVariantType( V_VT(pvargSrc) );
2045
2046   if( res != S_OK )
2047     return res;
2048
2049   if( V_VT(pvargSrc) & VT_BYREF )
2050   {
2051     VARIANTARG varg;
2052     VariantInit( &varg );
2053
2054     /* handle the in place copy.
2055      */
2056     if( pvargDest == pvargSrc )
2057     {
2058       /* we will use a copy of the source instead.
2059        */
2060       res = VariantCopy( &varg, pvargSrc );
2061       pvargSrc = &varg;
2062     }
2063
2064     if( res == S_OK )
2065     {
2066       res = VariantClear( pvargDest );
2067
2068       if( res == S_OK )
2069       {
2070         /*
2071          * The VT_ARRAY flag is another way to designate a safearray variant.
2072          */
2073         if ( V_VT(pvargSrc) & VT_ARRAY)
2074         {
2075           SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2076         }
2077         else
2078         {
2079           /* In the case of by reference we need
2080            * to copy the date pointed to by the variant.
2081            */
2082
2083           /* Get the variant type.
2084            */
2085           switch( V_VT(pvargSrc) & VT_TYPEMASK )
2086           {
2087             case( VT_BSTR ):
2088               V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
2089               break;
2090             case( VT_DISPATCH ):
2091               V_UNION(pvargDest,pdispVal) = *V_UNION(pvargSrc,ppdispVal);
2092               if (V_UNION(pvargDest,pdispVal)!=NULL)
2093                 IDispatch_AddRef(V_UNION(pvargDest,pdispVal));
2094               break;
2095             case( VT_VARIANT ):
2096               {
2097                 /* Prevent from cycling.  According to tests on
2098                  * VariantCopyInd in Windows and the documentation
2099                  * this API dereferences the inner Variants to only one depth.
2100                  * If the inner Variant itself contains an
2101                  * other inner variant the E_INVALIDARG error is
2102                  * returned.
2103                  */
2104                 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
2105                 {
2106                   /* If we get here we are attempting to deference
2107                    * an inner variant that that is itself contained
2108                    * in an inner variant so report E_INVALIDARG error.
2109                    */
2110                   res = E_INVALIDARG;
2111                 }
2112                 else
2113                 {
2114                   /* Set the processing inner variant flag.
2115                    * We will set this flag in the inner variant
2116                    * that will be passed to the VariantCopyInd function.
2117                    */
2118                   (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
2119
2120                   /* Dereference the inner variant.
2121                    */
2122                   res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
2123                   /* We must also copy its type, I think.
2124                    */
2125                   V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
2126                 }
2127               }
2128               break;
2129             case( VT_UNKNOWN ):
2130               V_UNION(pvargDest,punkVal) = *V_UNION(pvargSrc,ppunkVal);
2131               if (V_UNION(pvargDest,pdispVal)!=NULL)
2132                 IUnknown_AddRef(V_UNION(pvargDest,punkVal));
2133               break;
2134             case( VT_SAFEARRAY ):
2135               SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2136               break;
2137             default:
2138               /* This is a by reference Variant which means that the union
2139                * part of the Variant contains a pointer to some data of
2140                * type "V_VT(pvargSrc) & VT_TYPEMASK".
2141                * We will deference this data in a generic fashion using
2142                * the void pointer "Variant.u.byref".
2143                * We will copy this data into the union of the destination
2144                * Variant.
2145                */
2146               memcpy( &pvargDest->n1.n2.n3, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
2147               break;
2148           }
2149         }
2150
2151         if (res == S_OK) V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
2152       }
2153     }
2154
2155     /* this should not fail.
2156      */
2157     VariantClear( &varg );
2158   }
2159   else
2160   {
2161     res = VariantCopy( pvargDest, pvargSrc );
2162   }
2163
2164   return res;
2165 }
2166
2167 /******************************************************************************
2168  * Coerces a full safearray. Not optimal code.
2169  */
2170 static HRESULT
2171 coerce_array(
2172         VARIANTARG* src, VARIANTARG *dst, LCID lcid, USHORT wFlags, VARTYPE vt
2173 ) {
2174         SAFEARRAY       *sarr = V_ARRAY(src);
2175         HRESULT         hres;
2176         LPVOID          data;
2177         VARTYPE         vartype;
2178
2179         SafeArrayGetVartype(sarr,&vartype);
2180         switch (vt) {
2181         case VT_BSTR:
2182                 if (sarr->cDims != 1) {
2183                         FIXME("Can not coerce array with dim %d into BSTR\n", sarr->cDims);
2184                         return E_FAIL;
2185                 }
2186                 switch (V_VT(src) & VT_TYPEMASK) {
2187                 case VT_UI1:
2188                         hres = SafeArrayAccessData(sarr, &data);
2189                         if (FAILED(hres)) return hres;
2190
2191                         /* Yes, just memcpied apparently. */
2192                         V_BSTR(dst) = SysAllocStringByteLen(data, sarr->rgsabound[0].cElements);
2193                         hres = SafeArrayUnaccessData(sarr);
2194                         if (FAILED(hres)) return hres;
2195                         break;
2196                 default:
2197                         FIXME("Cannot coerce array of %d into BSTR yet. Please report!\n", V_VT(src) & VT_TYPEMASK);
2198                         return E_FAIL;
2199                 }
2200                 break;
2201         case VT_SAFEARRAY:
2202                 V_VT(dst) = VT_SAFEARRAY;
2203                 return SafeArrayCopy(sarr, &V_ARRAY(dst));
2204         default:
2205                 FIXME("Cannot coerce array of vt 0x%x/0x%x into vt 0x%x yet. Please report/implement!\n", vartype, V_VT(src), vt);
2206                 return E_FAIL;
2207         }
2208         return S_OK;
2209 }
2210
2211 /******************************************************************************
2212  *              VariantChangeType       [OLEAUT32.12]
2213  */
2214 HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2215                                                         USHORT wFlags, VARTYPE vt)
2216 {
2217         return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
2218 }
2219
2220 /******************************************************************************
2221  *              VariantChangeTypeEx     [OLEAUT32.147]
2222  */
2223 HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2224                                                           LCID lcid, USHORT wFlags, VARTYPE vt)
2225 {
2226         HRESULT res = S_OK;
2227         VARIANTARG varg;
2228         VariantInit( &varg );
2229
2230         TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
2231     TRACE("Src Var:\n");
2232     dump_Variant(pvargSrc);
2233
2234         /* validate our source argument.
2235          */
2236         res = ValidateVariantType( V_VT(pvargSrc) );
2237
2238         /* validate the vartype.
2239          */
2240         if( res == S_OK )
2241         {
2242                 res = ValidateVt( vt );
2243         }
2244
2245         /* if we are doing an in-place conversion make a copy of the source.
2246          */
2247         if( res == S_OK && pvargDest == pvargSrc )
2248         {
2249                 res = VariantCopy( &varg, pvargSrc );
2250                 pvargSrc = &varg;
2251         }
2252
2253         if( res == S_OK )
2254         {
2255                 /* free up the destination variant.
2256                  */
2257                 res = VariantClear( pvargDest );
2258         }
2259
2260         if( res == S_OK )
2261         {
2262                 if( V_VT(pvargSrc) & VT_BYREF )
2263                 {
2264                         /* Convert the source variant to a "byvalue" variant.
2265                          */
2266                         VARIANTARG Variant;
2267                         
2268                         if ((V_VT(pvargSrc) & 0xf000) != VT_BYREF) {
2269                                 FIXME("VT_TYPEMASK %x is unhandled.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2270                                 return E_FAIL;
2271                         }
2272
2273                         VariantInit( &Variant );
2274                         res = VariantCopyInd( &Variant, pvargSrc );
2275                         if( res == S_OK )
2276                         {
2277                                 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2278                                 /* this should not fail.
2279                                  */
2280                                 VariantClear( &Variant );
2281                         }
2282                 } else {
2283                         if (V_VT(pvargSrc) & VT_ARRAY) {
2284                                 if ((V_VT(pvargSrc) & 0xf000) != VT_ARRAY) {
2285                                         FIXME("VT_TYPEMASK %x is unhandled in VT_ARRAY.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2286                                         return E_FAIL;
2287                                 }
2288                                 V_VT(pvargDest) = VT_ARRAY | vt;
2289                                 res = coerce_array(pvargSrc, pvargDest, lcid, wFlags, vt);
2290                         } else {
2291                                 if ((V_VT(pvargSrc) & 0xf000)) {
2292                                         FIXME("VT_TYPEMASK %x is unhandled in normal case.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2293                                         return E_FAIL;
2294                                 }
2295                                 /* Use the current "byvalue" source variant.
2296                                  */
2297                                 res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2298                         }
2299                 }
2300         }
2301         /* this should not fail.
2302          */
2303         VariantClear( &varg );
2304
2305         /* set the type of the destination
2306          */
2307         if ( res == S_OK )
2308                 V_VT(pvargDest) = vt;
2309
2310     TRACE("Dest Var:\n");
2311     dump_Variant(pvargDest);
2312
2313         return res;
2314 }
2315
2316
2317
2318
2319 /******************************************************************************
2320  *              VarUI1FromI2            [OLEAUT32.130]
2321  */
2322 HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2323 {
2324         TRACE("( %d, %p ), stub\n", sIn, pbOut );
2325
2326         /* Check range of value.
2327          */
2328         if( sIn < UI1_MIN || sIn > UI1_MAX )
2329         {
2330                 return DISP_E_OVERFLOW;
2331         }
2332
2333         *pbOut = (BYTE) sIn;
2334
2335         return S_OK;
2336 }
2337
2338 /******************************************************************************
2339  *              VarUI1FromI4            [OLEAUT32.131]
2340  */
2341 HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2342 {
2343         TRACE("( %ld, %p ), stub\n", lIn, pbOut );
2344
2345         /* Check range of value.
2346          */
2347         if( lIn < UI1_MIN || lIn > UI1_MAX )
2348         {
2349                 return DISP_E_OVERFLOW;
2350         }
2351
2352         *pbOut = (BYTE) lIn;
2353
2354         return S_OK;
2355 }
2356
2357
2358 /******************************************************************************
2359  *              VarUI1FromR4            [OLEAUT32.132]
2360  */
2361 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2362 {
2363         TRACE("( %f, %p ), stub\n", fltIn, pbOut );
2364
2365         /* Check range of value.
2366      */
2367     fltIn = round( fltIn );
2368         if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2369         {
2370                 return DISP_E_OVERFLOW;
2371         }
2372
2373         *pbOut = (BYTE) fltIn;
2374
2375         return S_OK;
2376 }
2377
2378 /******************************************************************************
2379  *              VarUI1FromR8            [OLEAUT32.133]
2380  */
2381 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2382 {
2383         TRACE("( %f, %p ), stub\n", dblIn, pbOut );
2384
2385         /* Check range of value.
2386      */
2387     dblIn = round( dblIn );
2388         if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2389         {
2390                 return DISP_E_OVERFLOW;
2391         }
2392
2393         *pbOut = (BYTE) dblIn;
2394
2395         return S_OK;
2396 }
2397
2398 /******************************************************************************
2399  *              VarUI1FromDate          [OLEAUT32.135]
2400  */
2401 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2402 {
2403         TRACE("( %f, %p ), stub\n", dateIn, pbOut );
2404
2405         /* Check range of value.
2406      */
2407     dateIn = round( dateIn );
2408         if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2409         {
2410                 return DISP_E_OVERFLOW;
2411         }
2412
2413         *pbOut = (BYTE) dateIn;
2414
2415         return S_OK;
2416 }
2417
2418 /******************************************************************************
2419  *              VarUI1FromBool          [OLEAUT32.138]
2420  */
2421 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2422 {
2423         TRACE("( %d, %p ), stub\n", boolIn, pbOut );
2424
2425         *pbOut = (BYTE) boolIn;
2426
2427         return S_OK;
2428 }
2429
2430 /******************************************************************************
2431  *              VarUI1FromI1            [OLEAUT32.237]
2432  */
2433 HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
2434 {
2435         TRACE("( %c, %p ), stub\n", cIn, pbOut );
2436
2437         *pbOut = cIn;
2438
2439         return S_OK;
2440 }
2441
2442 /******************************************************************************
2443  *              VarUI1FromUI2           [OLEAUT32.238]
2444  */
2445 HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2446 {
2447         TRACE("( %d, %p ), stub\n", uiIn, pbOut );
2448
2449         /* Check range of value.
2450          */
2451         if( uiIn > UI1_MAX )
2452         {
2453                 return DISP_E_OVERFLOW;
2454         }
2455
2456         *pbOut = (BYTE) uiIn;
2457
2458         return S_OK;
2459 }
2460
2461 /******************************************************************************
2462  *              VarUI1FromUI4           [OLEAUT32.239]
2463  */
2464 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2465 {
2466         TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
2467
2468         /* Check range of value.
2469          */
2470         if( ulIn > UI1_MAX )
2471         {
2472                 return DISP_E_OVERFLOW;
2473         }
2474
2475         *pbOut = (BYTE) ulIn;
2476
2477         return S_OK;
2478 }
2479
2480
2481 /******************************************************************************
2482  *              VarUI1FromStr           [OLEAUT32.136]
2483  */
2484 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2485 {
2486         double dValue = 0.0;
2487         LPSTR pNewString = NULL;
2488
2489         TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
2490
2491         /* Check if we have a valid argument
2492          */
2493         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2494         RemoveCharacterFromString( pNewString, "," );
2495         if( IsValidRealString( pNewString ) == FALSE )
2496         {
2497                 return DISP_E_TYPEMISMATCH;
2498         }
2499
2500         /* Convert the valid string to a floating point number.
2501          */
2502         dValue = atof( pNewString );
2503
2504         /* We don't need the string anymore so free it.
2505          */
2506         HeapFree( GetProcessHeap(), 0 , pNewString );
2507
2508         /* Check range of value.
2509      */
2510     dValue = round( dValue );
2511         if( dValue < UI1_MIN || dValue > UI1_MAX )
2512         {
2513                 return DISP_E_OVERFLOW;
2514         }
2515
2516         *pbOut = (BYTE) dValue;
2517
2518         return S_OK;
2519 }
2520
2521 /**********************************************************************
2522  *              VarUI1FromCy [OLEAUT32.134]
2523  * Convert currency to unsigned char
2524  */
2525 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
2526    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2527
2528    if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
2529
2530    *pbOut = (BYTE)t;
2531    return S_OK;
2532 }
2533
2534 /******************************************************************************
2535  *              VarI2FromUI1            [OLEAUT32.48]
2536  */
2537 HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2538 {
2539         TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
2540
2541         *psOut = (short) bIn;
2542
2543         return S_OK;
2544 }
2545
2546 /******************************************************************************
2547  *              VarI2FromI4             [OLEAUT32.49]
2548  */
2549 HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2550 {
2551         TRACE("( %lx, %p ), stub\n", lIn, psOut );
2552
2553         /* Check range of value.
2554          */
2555         if( lIn < I2_MIN || lIn > I2_MAX )
2556         {
2557                 return DISP_E_OVERFLOW;
2558         }
2559
2560         *psOut = (short) lIn;
2561
2562         return S_OK;
2563 }
2564
2565 /******************************************************************************
2566  *              VarI2FromR4             [OLEAUT32.50]
2567  */
2568 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2569 {
2570         TRACE("( %f, %p ), stub\n", fltIn, psOut );
2571
2572         /* Check range of value.
2573      */
2574     fltIn = round( fltIn );
2575         if( fltIn < I2_MIN || fltIn > I2_MAX )
2576         {
2577                 return DISP_E_OVERFLOW;
2578         }
2579
2580         *psOut = (short) fltIn;
2581
2582         return S_OK;
2583 }
2584
2585 /******************************************************************************
2586  *              VarI2FromR8             [OLEAUT32.51]
2587  */
2588 HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2589 {
2590         TRACE("( %f, %p ), stub\n", dblIn, psOut );
2591
2592         /* Check range of value.
2593      */
2594     dblIn = round( dblIn );
2595         if( dblIn < I2_MIN || dblIn > I2_MAX )
2596         {
2597                 return DISP_E_OVERFLOW;
2598         }
2599
2600         *psOut = (short) dblIn;
2601
2602         return S_OK;
2603 }
2604
2605 /******************************************************************************
2606  *              VarI2FromDate           [OLEAUT32.53]
2607  */
2608 HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2609 {
2610         TRACE("( %f, %p ), stub\n", dateIn, psOut );
2611
2612         /* Check range of value.
2613      */
2614     dateIn = round( dateIn );
2615         if( dateIn < I2_MIN || dateIn > I2_MAX )
2616         {
2617                 return DISP_E_OVERFLOW;
2618         }
2619
2620         *psOut = (short) dateIn;
2621
2622         return S_OK;
2623 }
2624
2625 /******************************************************************************
2626  *              VarI2FromBool           [OLEAUT32.56]
2627  */
2628 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2629 {
2630         TRACE("( %d, %p ), stub\n", boolIn, psOut );
2631
2632         *psOut = (short) boolIn;
2633
2634         return S_OK;
2635 }
2636
2637 /******************************************************************************
2638  *              VarI2FromI1             [OLEAUT32.205]
2639  */
2640 HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
2641 {
2642         TRACE("( %c, %p ), stub\n", cIn, psOut );
2643
2644         *psOut = (short) cIn;
2645
2646         return S_OK;
2647 }
2648
2649 /******************************************************************************
2650  *              VarI2FromUI2            [OLEAUT32.206]
2651  */
2652 HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2653 {
2654         TRACE("( %d, %p ), stub\n", uiIn, psOut );
2655
2656         /* Check range of value.
2657          */
2658         if( uiIn > I2_MAX )
2659         {
2660                 return DISP_E_OVERFLOW;
2661         }
2662
2663         *psOut = (short) uiIn;
2664
2665         return S_OK;
2666 }
2667
2668 /******************************************************************************
2669  *              VarI2FromUI4            [OLEAUT32.207]
2670  */
2671 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2672 {
2673         TRACE("( %lx, %p ), stub\n", ulIn, psOut );
2674
2675         /* Check range of value.
2676          */
2677         if( ulIn < I2_MIN || ulIn > I2_MAX )
2678         {
2679                 return DISP_E_OVERFLOW;
2680         }
2681
2682         *psOut = (short) ulIn;
2683
2684         return S_OK;
2685 }
2686
2687 /******************************************************************************
2688  *              VarI2FromStr            [OLEAUT32.54]
2689  */
2690 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2691 {
2692         double dValue = 0.0;
2693         LPSTR pNewString = NULL;
2694
2695         TRACE("( %s, 0x%08lx, 0x%08lx, %p ), stub\n", debugstr_w(strIn), lcid, dwFlags, psOut );
2696
2697         /* Check if we have a valid argument
2698          */
2699         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2700         RemoveCharacterFromString( pNewString, "," );
2701         if( IsValidRealString( pNewString ) == FALSE )
2702         {
2703                 return DISP_E_TYPEMISMATCH;
2704         }
2705
2706         /* Convert the valid string to a floating point number.
2707          */
2708         dValue = atof( pNewString );
2709
2710         /* We don't need the string anymore so free it.
2711          */
2712         HeapFree( GetProcessHeap(), 0, pNewString );
2713
2714         /* Check range of value.
2715      */
2716     dValue = round( dValue );
2717         if( dValue < I2_MIN || dValue > I2_MAX )
2718         {
2719                 return DISP_E_OVERFLOW;
2720         }
2721
2722         *psOut = (short)  dValue;
2723
2724         return S_OK;
2725 }
2726
2727 /**********************************************************************
2728  *              VarI2FromCy [OLEAUT32.52]
2729  * Convert currency to signed short
2730  */
2731 HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
2732    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2733
2734    if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
2735
2736    *psOut = (SHORT)t;
2737    return S_OK;
2738 }
2739
2740 /******************************************************************************
2741  *              VarI4FromUI1            [OLEAUT32.58]
2742  */
2743 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2744 {
2745         TRACE("( %X, %p ), stub\n", bIn, plOut );
2746
2747         *plOut = (LONG) bIn;
2748
2749         return S_OK;
2750 }
2751
2752
2753 /******************************************************************************
2754  *              VarI4FromR4             [OLEAUT32.60]
2755  */
2756 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2757 {
2758         TRACE("( %f, %p ), stub\n", fltIn, plOut );
2759
2760         /* Check range of value.
2761      */
2762     fltIn = round( fltIn );
2763         if( fltIn < I4_MIN || fltIn > I4_MAX )
2764         {
2765                 return DISP_E_OVERFLOW;
2766         }
2767
2768         *plOut = (LONG) fltIn;
2769
2770         return S_OK;
2771 }
2772
2773 /******************************************************************************
2774  *              VarI4FromR8             [OLEAUT32.61]
2775  */
2776 HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2777 {
2778         TRACE("( %f, %p ), stub\n", dblIn, plOut );
2779
2780         /* Check range of value.
2781      */
2782     dblIn = round( dblIn );
2783         if( dblIn < I4_MIN || dblIn > I4_MAX )
2784         {
2785                 return DISP_E_OVERFLOW;
2786         }
2787
2788         *plOut = (LONG) dblIn;
2789
2790         return S_OK;
2791 }
2792
2793 /******************************************************************************
2794  *              VarI4FromDate           [OLEAUT32.63]
2795  */
2796 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2797 {
2798         TRACE("( %f, %p ), stub\n", dateIn, plOut );
2799
2800         /* Check range of value.
2801      */
2802     dateIn = round( dateIn );
2803         if( dateIn < I4_MIN || dateIn > I4_MAX )
2804         {
2805                 return DISP_E_OVERFLOW;
2806         }
2807
2808         *plOut = (LONG) dateIn;
2809
2810         return S_OK;
2811 }
2812
2813 /******************************************************************************
2814  *              VarI4FromBool           [OLEAUT32.66]
2815  */
2816 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2817 {
2818         TRACE("( %d, %p ), stub\n", boolIn, plOut );
2819
2820         *plOut = (LONG) boolIn;
2821
2822         return S_OK;
2823 }
2824
2825 /******************************************************************************
2826  *              VarI4FromI1             [OLEAUT32.209]
2827  */
2828 HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
2829 {
2830         TRACE("( %c, %p ), stub\n", cIn, plOut );
2831
2832         *plOut = (LONG) cIn;
2833
2834         return S_OK;
2835 }
2836
2837 /******************************************************************************
2838  *              VarI4FromUI2            [OLEAUT32.210]
2839  */
2840 HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2841 {
2842         TRACE("( %d, %p ), stub\n", uiIn, plOut );
2843
2844         *plOut = (LONG) uiIn;
2845
2846         return S_OK;
2847 }
2848
2849 /******************************************************************************
2850  *              VarI4FromUI4            [OLEAUT32.211]
2851  */
2852 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2853 {
2854         TRACE("( %lx, %p ), stub\n", ulIn, plOut );
2855
2856         /* Check range of value.
2857          */
2858         if( ulIn < I4_MIN || ulIn > I4_MAX )
2859         {
2860                 return DISP_E_OVERFLOW;
2861         }
2862
2863         *plOut = (LONG) ulIn;
2864
2865         return S_OK;
2866 }
2867
2868 /******************************************************************************
2869  *              VarI4FromI2             [OLEAUT32.59]
2870  */
2871 HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2872 {
2873         TRACE("( %d, %p ), stub\n", sIn, plOut );
2874
2875         *plOut = (LONG) sIn;
2876
2877         return S_OK;
2878 }
2879
2880 /******************************************************************************
2881  *              VarI4FromStr            [OLEAUT32.64]
2882  */
2883 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2884 {
2885         double dValue = 0.0;
2886         LPSTR pNewString = NULL;
2887
2888         TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
2889
2890         /* Check if we have a valid argument
2891          */
2892         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2893         RemoveCharacterFromString( pNewString, "," );
2894         if( IsValidRealString( pNewString ) == FALSE )
2895         {
2896                 return DISP_E_TYPEMISMATCH;
2897         }
2898
2899         /* Convert the valid string to a floating point number.
2900          */
2901         dValue = atof( pNewString );
2902
2903         /* We don't need the string anymore so free it.
2904          */
2905         HeapFree( GetProcessHeap(), 0, pNewString );
2906
2907         /* Check range of value.
2908      */
2909     dValue = round( dValue );
2910         if( dValue < I4_MIN || dValue > I4_MAX )
2911         {
2912                 return DISP_E_OVERFLOW;
2913         }
2914
2915         *plOut = (LONG) dValue;
2916
2917         return S_OK;
2918 }
2919
2920 /**********************************************************************
2921  *              VarI4FromCy [OLEAUT32.62]
2922  * Convert currency to signed long
2923  */
2924 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
2925    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2926
2927    if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
2928
2929    *plOut = (LONG)t;
2930    return S_OK;
2931 }
2932
2933 /******************************************************************************
2934  *              VarR4FromUI1            [OLEAUT32.68]
2935  */
2936 HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
2937 {
2938         TRACE("( %X, %p ), stub\n", bIn, pfltOut );
2939
2940         *pfltOut = (FLOAT) bIn;
2941
2942         return S_OK;
2943 }
2944
2945 /******************************************************************************
2946  *              VarR4FromI2             [OLEAUT32.69]
2947  */
2948 HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
2949 {
2950         TRACE("( %d, %p ), stub\n", sIn, pfltOut );
2951
2952         *pfltOut = (FLOAT) sIn;
2953
2954         return S_OK;
2955 }
2956
2957 /******************************************************************************
2958  *              VarR4FromI4             [OLEAUT32.70]
2959  */
2960 HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
2961 {
2962         TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
2963
2964         *pfltOut = (FLOAT) lIn;
2965
2966         return S_OK;
2967 }
2968
2969 /******************************************************************************
2970  *              VarR4FromR8             [OLEAUT32.71]
2971  */
2972 HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
2973 {
2974         TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
2975
2976         /* Check range of value.
2977          */
2978         if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
2979         {
2980                 return DISP_E_OVERFLOW;
2981         }
2982
2983         *pfltOut = (FLOAT) dblIn;
2984
2985         return S_OK;
2986 }
2987
2988 /******************************************************************************
2989  *              VarR4FromDate           [OLEAUT32.73]
2990  */
2991 HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
2992 {
2993         TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
2994
2995         /* Check range of value.
2996          */
2997         if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
2998         {
2999                 return DISP_E_OVERFLOW;
3000         }
3001
3002         *pfltOut = (FLOAT) dateIn;
3003
3004         return S_OK;
3005 }
3006
3007 /******************************************************************************
3008  *              VarR4FromBool           [OLEAUT32.76]
3009  */
3010 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
3011 {
3012         TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
3013
3014         *pfltOut = (FLOAT) boolIn;
3015
3016         return S_OK;
3017 }
3018
3019 /******************************************************************************
3020  *              VarR4FromI1             [OLEAUT32.213]
3021  */
3022 HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
3023 {
3024         TRACE("( %c, %p ), stub\n", cIn, pfltOut );
3025
3026         *pfltOut = (FLOAT) cIn;
3027
3028         return S_OK;
3029 }
3030
3031 /******************************************************************************
3032  *              VarR4FromUI2            [OLEAUT32.214]
3033  */
3034 HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
3035 {
3036         TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
3037
3038         *pfltOut = (FLOAT) uiIn;
3039
3040         return S_OK;
3041 }
3042
3043 /******************************************************************************
3044  *              VarR4FromUI4            [OLEAUT32.215]
3045  */
3046 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
3047 {
3048         TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
3049
3050         *pfltOut = (FLOAT) ulIn;
3051
3052         return S_OK;
3053 }
3054
3055 /******************************************************************************
3056  *              VarR4FromStr            [OLEAUT32.74]
3057  */
3058 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
3059 {
3060         double dValue = 0.0;
3061         LPSTR pNewString = NULL;
3062
3063         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
3064
3065         /* Check if we have a valid argument
3066          */
3067         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3068         RemoveCharacterFromString( pNewString, "," );
3069         if( IsValidRealString( pNewString ) == FALSE )
3070         {
3071                 return DISP_E_TYPEMISMATCH;
3072         }
3073
3074         /* Convert the valid string to a floating point number.
3075          */
3076         dValue = atof( pNewString );
3077
3078         /* We don't need the string anymore so free it.
3079          */
3080         HeapFree( GetProcessHeap(), 0, pNewString );
3081
3082         /* Check range of value.
3083          */
3084         if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
3085         {
3086                 return DISP_E_OVERFLOW;
3087         }
3088
3089         *pfltOut = (FLOAT) dValue;
3090
3091         return S_OK;
3092 }
3093
3094 /**********************************************************************
3095  *              VarR4FromCy [OLEAUT32.72]
3096  * Convert currency to float
3097  */
3098 HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
3099    *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3100
3101    return S_OK;
3102 }
3103
3104 /******************************************************************************
3105  *              VarR8FromUI1            [OLEAUT32.78]
3106  */
3107 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
3108 {
3109         TRACE("( %d, %p ), stub\n", bIn, pdblOut );
3110
3111         *pdblOut = (double) bIn;
3112
3113         return S_OK;
3114 }
3115
3116 /******************************************************************************
3117  *              VarR8FromI2             [OLEAUT32.79]
3118  */
3119 HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
3120 {
3121         TRACE("( %d, %p ), stub\n", sIn, pdblOut );
3122
3123         *pdblOut = (double) sIn;
3124
3125         return S_OK;
3126 }
3127
3128 /******************************************************************************
3129  *              VarR8FromI4             [OLEAUT32.80]
3130  */
3131 HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
3132 {
3133         TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
3134
3135         *pdblOut = (double) lIn;
3136
3137         return S_OK;
3138 }
3139
3140 /******************************************************************************
3141  *              VarR8FromR4             [OLEAUT32.81]
3142  */
3143 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
3144 {
3145         TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
3146
3147         *pdblOut = (double) fltIn;
3148
3149         return S_OK;
3150 }
3151
3152 /******************************************************************************
3153  *              VarR8FromDate           [OLEAUT32.83]
3154  */
3155 HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
3156 {
3157         TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
3158
3159         *pdblOut = (double) dateIn;
3160
3161         return S_OK;
3162 }
3163
3164 /******************************************************************************
3165  *              VarR8FromBool           [OLEAUT32.86]
3166  */
3167 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
3168 {
3169         TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
3170
3171         *pdblOut = (double) boolIn;
3172
3173         return S_OK;
3174 }
3175
3176 /******************************************************************************
3177  *              VarR8FromI1             [OLEAUT32.217]
3178  */
3179 HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
3180 {
3181         TRACE("( %c, %p ), stub\n", cIn, pdblOut );
3182
3183         *pdblOut = (double) cIn;
3184
3185         return S_OK;
3186 }
3187
3188 /******************************************************************************
3189  *              VarR8FromUI2            [OLEAUT32.218]
3190  */
3191 HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
3192 {
3193         TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
3194
3195         *pdblOut = (double) uiIn;
3196
3197         return S_OK;
3198 }
3199
3200 /******************************************************************************
3201  *              VarR8FromUI4            [OLEAUT32.219]
3202  */
3203 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
3204 {
3205         TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
3206
3207         *pdblOut = (double) ulIn;
3208
3209         return S_OK;
3210 }
3211
3212 /******************************************************************************
3213  *              VarR8FromStr            [OLEAUT32.84]
3214  */
3215 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
3216 {
3217         double dValue = 0.0;
3218         LPSTR pNewString = NULL;
3219
3220         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3221         TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString, lcid, dwFlags, pdblOut );
3222
3223         /* Check if we have a valid argument
3224          */
3225         RemoveCharacterFromString( pNewString, "," );
3226         if( IsValidRealString( pNewString ) == FALSE )
3227         {
3228                 return DISP_E_TYPEMISMATCH;
3229         }
3230
3231         /* Convert the valid string to a floating point number.
3232          */
3233         dValue = atof( pNewString );
3234
3235         /* We don't need the string anymore so free it.
3236          */
3237         HeapFree( GetProcessHeap(), 0, pNewString );
3238
3239         *pdblOut = dValue;
3240
3241         return S_OK;
3242 }
3243
3244 /**********************************************************************
3245  *              VarR8FromCy [OLEAUT32.82]
3246  * Convert currency to double
3247  */
3248 HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
3249    *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3250    TRACE("%lu %ld -> %f\n", cyIn.s.Hi, cyIn.s.Lo, *pdblOut);
3251    return S_OK;
3252 }
3253
3254 /******************************************************************************
3255  *              VarDateFromUI1          [OLEAUT32.88]
3256  */
3257 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
3258 {
3259         TRACE("( %d, %p ), stub\n", bIn, pdateOut );
3260
3261         *pdateOut = (DATE) bIn;
3262
3263         return S_OK;
3264 }
3265
3266 /******************************************************************************
3267  *              VarDateFromI2           [OLEAUT32.89]
3268  */
3269 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
3270 {
3271         TRACE("( %d, %p ), stub\n", sIn, pdateOut );
3272
3273         *pdateOut = (DATE) sIn;
3274
3275         return S_OK;
3276 }
3277
3278 /******************************************************************************
3279  *              VarDateFromI4           [OLEAUT32.90]
3280  */
3281 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3282 {
3283         TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
3284
3285         if( lIn < DATE_MIN || lIn > DATE_MAX )
3286         {
3287                 return DISP_E_OVERFLOW;
3288         }
3289
3290         *pdateOut = (DATE) lIn;
3291
3292         return S_OK;
3293 }
3294
3295 /******************************************************************************
3296  *              VarDateFromR4           [OLEAUT32.91]
3297  */
3298 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3299 {
3300     TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3301
3302     if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
3303         {
3304                 return DISP_E_OVERFLOW;
3305         }
3306
3307         *pdateOut = (DATE) fltIn;
3308
3309         return S_OK;
3310 }
3311
3312 /******************************************************************************
3313  *              VarDateFromR8           [OLEAUT32.92]
3314  */
3315 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3316 {
3317     TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3318
3319         if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3320         {
3321                 return DISP_E_OVERFLOW;
3322         }
3323
3324         *pdateOut = (DATE) dblIn;
3325
3326         return S_OK;
3327 }
3328
3329 /******************************************************************************
3330  *              VarDateFromStr          [OLEAUT32.94]
3331  * The string representing the date is composed of two parts, a date and time.
3332  *
3333  * The format of the time is has follows:
3334  * hh[:mm][:ss][AM|PM]
3335  * Whitespace can be inserted anywhere between these tokens.  A whitespace consists
3336  * of space and/or tab characters, which are ignored.
3337  *
3338  * The formats for the date part are has follows:
3339  * mm/[dd/][yy]yy
3340  * [dd/]mm/[yy]yy
3341  * [yy]yy/mm/dd
3342  * January dd[,] [yy]yy
3343  * dd January [yy]yy
3344  * [yy]yy January dd
3345  * Whitespace can be inserted anywhere between these tokens.
3346  *
3347  * The formats for the date and time string are has follows.
3348  * date[whitespace][time]
3349  * [time][whitespace]date
3350  *
3351  * These are the only characters allowed in a string representing a date and time:
3352  * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3353  */
3354 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3355 {
3356     HRESULT ret = S_OK;
3357     struct tm TM;
3358
3359     memset( &TM, 0, sizeof(TM) );
3360
3361     TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3362
3363     if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
3364     {
3365         if( TmToDATE( &TM, pdateOut ) == FALSE )
3366         {
3367             ret = E_INVALIDARG;
3368         }
3369     }
3370     else
3371     {
3372         ret = DISP_E_TYPEMISMATCH;
3373     }
3374     TRACE("Return value %f\n", *pdateOut);
3375         return ret;
3376 }
3377
3378 /******************************************************************************
3379  *              VarDateFromI1           [OLEAUT32.221]
3380  */
3381 HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
3382 {
3383         TRACE("( %c, %p ), stub\n", cIn, pdateOut );
3384
3385         *pdateOut = (DATE) cIn;
3386
3387         return S_OK;
3388 }
3389
3390 /******************************************************************************
3391  *              VarDateFromUI2          [OLEAUT32.222]
3392  */
3393 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3394 {
3395         TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
3396
3397         if( uiIn > DATE_MAX )
3398         {
3399                 return DISP_E_OVERFLOW;
3400         }
3401
3402         *pdateOut = (DATE) uiIn;
3403
3404         return S_OK;
3405 }
3406
3407 /******************************************************************************
3408  *              VarDateFromUI4          [OLEAUT32.223]
3409  */
3410 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3411 {
3412         TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
3413
3414         if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3415         {
3416                 return DISP_E_OVERFLOW;
3417         }
3418
3419         *pdateOut = (DATE) ulIn;
3420
3421         return S_OK;
3422 }
3423
3424 /******************************************************************************
3425  *              VarDateFromBool         [OLEAUT32.96]
3426  */
3427 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3428 {
3429         TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
3430
3431         *pdateOut = (DATE) boolIn;
3432
3433         return S_OK;
3434 }
3435
3436 /**********************************************************************
3437  *              VarDateFromCy [OLEAUT32.93]
3438  * Convert currency to date
3439  */
3440 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
3441    *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3442
3443    if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3444    return S_OK;
3445 }
3446
3447 /******************************************************************************
3448  *              VarBstrFromUI1          [OLEAUT32.108]
3449  */
3450 HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3451 {
3452         TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3453         sprintf( pBuffer, "%d", bVal );
3454
3455         *pbstrOut =  StringDupAtoBstr( pBuffer );
3456
3457         return S_OK;
3458 }
3459
3460 /******************************************************************************
3461  *              VarBstrFromI2           [OLEAUT32.109]
3462  */
3463 HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3464 {
3465         TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3466         sprintf( pBuffer, "%d", iVal );
3467         *pbstrOut = StringDupAtoBstr( pBuffer );
3468
3469         return S_OK;
3470 }
3471
3472 /******************************************************************************
3473  *              VarBstrFromI4           [OLEAUT32.110]
3474  */
3475 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3476 {
3477         TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
3478
3479         sprintf( pBuffer, "%ld", lIn );
3480         *pbstrOut = StringDupAtoBstr( pBuffer );
3481
3482         return S_OK;
3483 }
3484
3485 /******************************************************************************
3486  *              VarBstrFromR4           [OLEAUT32.111]
3487  */
3488 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3489 {
3490         TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
3491
3492         sprintf( pBuffer, "%.7G", fltIn );
3493         *pbstrOut = StringDupAtoBstr( pBuffer );
3494
3495         return S_OK;
3496 }
3497
3498 /******************************************************************************
3499  *              VarBstrFromR8           [OLEAUT32.112]
3500  */
3501 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3502 {
3503         TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
3504
3505         sprintf( pBuffer, "%.15G", dblIn );
3506         *pbstrOut = StringDupAtoBstr( pBuffer );
3507
3508         return S_OK;
3509 }
3510
3511 /******************************************************************************
3512  *    VarBstrFromCy   [OLEAUT32.113]
3513  */
3514 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
3515     HRESULT rc = S_OK;
3516     double curVal = 0.0;
3517
3518         TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid, dwFlags, pbstrOut);
3519
3520     /* Firstly get the currency in a double, then put it in a buffer */
3521     rc = VarR8FromCy(cyIn, &curVal);
3522     if (rc == S_OK) {
3523         sprintf(pBuffer, "%G", curVal);
3524         *pbstrOut = StringDupAtoBstr( pBuffer );
3525     }
3526         return rc;
3527 }
3528
3529
3530 /******************************************************************************
3531  *              VarBstrFromDate         [OLEAUT32.114]
3532  *
3533  * The date is implemented using an 8 byte floating-point number.
3534  * Days are represented by whole numbers increments starting with 0.00 as
3535  * being December 30 1899, midnight.
3536  * The hours are expressed as the fractional part of the number.
3537  * December 30 1899 at midnight = 0.00
3538  * January 1 1900 at midnight = 2.00
3539  * January 4 1900 at 6 AM = 5.25
3540  * January 4 1900 at noon = 5.50
3541  * December 29 1899 at midnight = -1.00
3542  * December 18 1899 at midnight = -12.00
3543  * December 18 1899 at 6AM = -12.25
3544  * December 18 1899 at 6PM = -12.75
3545  * December 19 1899 at midnight = -11.00
3546  * The tm structure is as follows:
3547  * struct tm {
3548  *                int tm_sec;      seconds after the minute - [0,59]
3549  *                int tm_min;      minutes after the hour - [0,59]
3550  *                int tm_hour;     hours since midnight - [0,23]
3551  *                int tm_mday;     day of the month - [1,31]
3552  *                int tm_mon;      months since January - [0,11]
3553  *                int tm_year;     years
3554  *                int tm_wday;     days since Sunday - [0,6]
3555  *                int tm_yday;     days since January 1 - [0,365]
3556  *                int tm_isdst;    daylight savings time flag
3557  *                };
3558  */
3559 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3560 {
3561     struct tm TM;
3562     memset( &TM, 0, sizeof(TM) );
3563
3564     TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
3565
3566     if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
3567                         {
3568         return E_INVALIDARG;
3569                 }
3570
3571     if( dwFlags & VAR_DATEVALUEONLY )
3572                         strftime( pBuffer, BUFFER_MAX, "%x", &TM );
3573     else if( dwFlags & VAR_TIMEVALUEONLY )
3574                         strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3575                 else
3576         strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3577
3578         TRACE("result: %s\n", pBuffer);
3579                 *pbstrOut = StringDupAtoBstr( pBuffer );
3580         return S_OK;
3581 }
3582
3583 /******************************************************************************
3584  *              VarBstrFromBool         [OLEAUT32.116]
3585  */
3586 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3587 {
3588         TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
3589
3590         sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
3591
3592         *pbstrOut = StringDupAtoBstr( pBuffer );
3593
3594         return S_OK;
3595 }
3596
3597 /******************************************************************************
3598  *              VarBstrFromI1           [OLEAUT32.229]
3599  */
3600 HRESULT WINAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3601 {
3602         TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3603         sprintf( pBuffer, "%d", cIn );
3604         *pbstrOut = StringDupAtoBstr( pBuffer );
3605
3606         return S_OK;
3607 }
3608
3609 /******************************************************************************
3610  *              VarBstrFromUI2          [OLEAUT32.230]
3611  */
3612 HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3613 {
3614         TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3615         sprintf( pBuffer, "%d", uiIn );
3616         *pbstrOut = StringDupAtoBstr( pBuffer );
3617
3618         return S_OK;
3619 }
3620
3621 /******************************************************************************
3622  *              VarBstrFromUI4          [OLEAUT32.231]
3623  */
3624 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3625 {
3626         TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3627         sprintf( pBuffer, "%ld", ulIn );
3628         *pbstrOut = StringDupAtoBstr( pBuffer );
3629
3630         return S_OK;
3631 }
3632
3633 /******************************************************************************
3634  *              VarBoolFromUI1          [OLEAUT32.118]
3635  */
3636 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3637 {
3638         TRACE("( %d, %p ), stub\n", bIn, pboolOut );
3639
3640         if( bIn == 0 )
3641         {
3642                 *pboolOut = VARIANT_FALSE;
3643         }
3644         else
3645         {
3646                 *pboolOut = VARIANT_TRUE;
3647         }
3648
3649         return S_OK;
3650 }
3651
3652 /******************************************************************************
3653  *              VarBoolFromI2           [OLEAUT32.119]
3654  */
3655 HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3656 {
3657         TRACE("( %d, %p ), stub\n", sIn, pboolOut );
3658
3659         *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
3660
3661         return S_OK;
3662 }
3663
3664 /******************************************************************************
3665  *              VarBoolFromI4           [OLEAUT32.120]
3666  */
3667 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3668 {
3669         TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
3670
3671         *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
3672
3673         return S_OK;
3674 }
3675
3676 /******************************************************************************
3677  *              VarBoolFromR4           [OLEAUT32.121]
3678  */
3679 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3680 {
3681         TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
3682
3683         *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3684
3685         return S_OK;
3686 }
3687
3688 /******************************************************************************
3689  *              VarBoolFromR8           [OLEAUT32.122]
3690  */
3691 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3692 {
3693         TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
3694
3695         *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3696
3697         return S_OK;
3698 }
3699
3700 /******************************************************************************
3701  *              VarBoolFromDate         [OLEAUT32.123]
3702  */
3703 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3704 {
3705         TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
3706
3707         *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3708
3709         return S_OK;
3710 }
3711
3712 /******************************************************************************
3713  *              VarBoolFromStr          [OLEAUT32.125]
3714  */
3715 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3716 {
3717         HRESULT ret = S_OK;
3718         char* pNewString = NULL;
3719
3720         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
3721
3722     pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3723
3724         if( pNewString == NULL || strlen( pNewString ) == 0 )
3725         {
3726                 ret = DISP_E_TYPEMISMATCH;
3727         }
3728
3729         if( ret == S_OK )
3730         {
3731                 if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
3732                 {
3733                         *pboolOut = VARIANT_TRUE;
3734                 }
3735                 else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
3736                 {
3737                         *pboolOut = VARIANT_FALSE;
3738                 }
3739                 else
3740                 {
3741                         /* Try converting the string to a floating point number.
3742                          */
3743                         double dValue = 0.0;
3744                         HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3745                         if( res != S_OK )
3746                         {
3747                                 ret = DISP_E_TYPEMISMATCH;
3748                         }
3749                         else
3750                                 *pboolOut = (dValue == 0.0) ?
3751                                                 VARIANT_FALSE : VARIANT_TRUE;
3752                 }
3753         }
3754
3755         HeapFree( GetProcessHeap(), 0, pNewString );
3756
3757         return ret;
3758 }
3759
3760 /******************************************************************************
3761  *              VarBoolFromI1           [OLEAUT32.233]
3762  */
3763 HRESULT WINAPI VarBoolFromI1(CHAR cIn, VARIANT_BOOL* pboolOut)
3764 {
3765         TRACE("( %c, %p ), stub\n", cIn, pboolOut );
3766
3767         *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3768
3769         return S_OK;
3770 }
3771
3772 /******************************************************************************
3773  *              VarBoolFromUI2          [OLEAUT32.234]
3774  */
3775 HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3776 {
3777         TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
3778
3779         *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3780
3781         return S_OK;
3782 }
3783
3784 /******************************************************************************
3785  *              VarBoolFromUI4          [OLEAUT32.235]
3786  */
3787 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3788 {
3789         TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
3790
3791         *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3792
3793         return S_OK;
3794 }
3795
3796 /**********************************************************************
3797  *              VarBoolFromCy [OLEAUT32.124]
3798  * Convert currency to boolean
3799  */
3800 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
3801       if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
3802       else *pboolOut = 0;
3803
3804       return S_OK;
3805 }
3806
3807 /******************************************************************************
3808  *              VarI1FromUI1            [OLEAUT32.244]
3809  */
3810 HRESULT WINAPI VarI1FromUI1(BYTE bIn, CHAR* pcOut)
3811 {
3812         TRACE("( %d, %p ), stub\n", bIn, pcOut );
3813
3814         /* Check range of value.
3815          */
3816         if( bIn > CHAR_MAX )
3817         {
3818                 return DISP_E_OVERFLOW;
3819         }
3820
3821         *pcOut = (CHAR) bIn;
3822
3823         return S_OK;
3824 }
3825
3826 /******************************************************************************
3827  *              VarI1FromI2             [OLEAUT32.245]
3828  */
3829 HRESULT WINAPI VarI1FromI2(short uiIn, CHAR* pcOut)
3830 {
3831         TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3832
3833         if( uiIn > CHAR_MAX )
3834         {
3835                 return DISP_E_OVERFLOW;
3836         }
3837
3838         *pcOut = (CHAR) uiIn;
3839
3840         return S_OK;
3841 }
3842
3843 /******************************************************************************
3844  *              VarI1FromI4             [OLEAUT32.246]
3845  */
3846 HRESULT WINAPI VarI1FromI4(LONG lIn, CHAR* pcOut)
3847 {
3848         TRACE("( %ld, %p ), stub\n", lIn, pcOut );
3849
3850         if( lIn < CHAR_MIN || lIn > CHAR_MAX )
3851         {
3852                 return DISP_E_OVERFLOW;
3853         }
3854
3855         *pcOut = (CHAR) lIn;
3856
3857         return S_OK;
3858 }
3859
3860 /******************************************************************************
3861  *              VarI1FromR4             [OLEAUT32.247]
3862  */
3863 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, CHAR* pcOut)
3864 {
3865         TRACE("( %f, %p ), stub\n", fltIn, pcOut );
3866
3867     fltIn = round( fltIn );
3868         if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
3869         {
3870                 return DISP_E_OVERFLOW;
3871         }
3872
3873         *pcOut = (CHAR) fltIn;
3874
3875         return S_OK;
3876 }
3877
3878 /******************************************************************************
3879  *              VarI1FromR8             [OLEAUT32.248]
3880  */
3881 HRESULT WINAPI VarI1FromR8(double dblIn, CHAR* pcOut)
3882 {
3883         TRACE("( %f, %p ), stub\n", dblIn, pcOut );
3884
3885     dblIn = round( dblIn );
3886     if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
3887         {
3888                 return DISP_E_OVERFLOW;
3889         }
3890
3891         *pcOut = (CHAR) dblIn;
3892
3893         return S_OK;
3894 }
3895
3896 /******************************************************************************
3897  *              VarI1FromDate           [OLEAUT32.249]
3898  */
3899 HRESULT WINAPI VarI1FromDate(DATE dateIn, CHAR* pcOut)
3900 {
3901         TRACE("( %f, %p ), stub\n", dateIn, pcOut );
3902
3903     dateIn = round( dateIn );
3904         if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
3905         {
3906                 return DISP_E_OVERFLOW;
3907         }
3908
3909         *pcOut = (CHAR) dateIn;
3910
3911         return S_OK;
3912 }
3913
3914 /******************************************************************************
3915  *              VarI1FromStr            [OLEAUT32.251]
3916  */
3917 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CHAR* pcOut)
3918 {
3919         double dValue = 0.0;
3920         LPSTR pNewString = NULL;
3921
3922         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
3923
3924         /* Check if we have a valid argument
3925          */
3926         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3927         RemoveCharacterFromString( pNewString, "," );
3928         if( IsValidRealString( pNewString ) == FALSE )
3929         {
3930                 return DISP_E_TYPEMISMATCH;
3931         }
3932
3933         /* Convert the valid string to a floating point number.
3934          */
3935         dValue = atof( pNewString );
3936
3937         /* We don't need the string anymore so free it.
3938          */
3939         HeapFree( GetProcessHeap(), 0, pNewString );
3940
3941         /* Check range of value.
3942      */
3943     dValue = round( dValue );
3944         if( dValue < CHAR_MIN || dValue > CHAR_MAX )
3945         {
3946                 return DISP_E_OVERFLOW;
3947         }
3948
3949         *pcOut = (CHAR) dValue;
3950
3951         return S_OK;
3952 }
3953
3954 /******************************************************************************
3955  *              VarI1FromBool           [OLEAUT32.253]
3956  */
3957 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
3958 {
3959         TRACE("( %d, %p ), stub\n", boolIn, pcOut );
3960
3961         *pcOut = (CHAR) boolIn;
3962
3963         return S_OK;
3964 }
3965
3966 /******************************************************************************
3967  *              VarI1FromUI2            [OLEAUT32.254]
3968  */
3969 HRESULT WINAPI VarI1FromUI2(USHORT uiIn, CHAR* pcOut)
3970 {
3971         TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3972
3973         if( uiIn > CHAR_MAX )
3974         {
3975                 return DISP_E_OVERFLOW;
3976         }
3977
3978         *pcOut = (CHAR) uiIn;
3979
3980         return S_OK;
3981 }
3982
3983 /******************************************************************************
3984  *              VarI1FromUI4            [OLEAUT32.255]
3985  */
3986 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, CHAR* pcOut)
3987 {
3988         TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
3989
3990         if( ulIn > CHAR_MAX )
3991         {
3992                 return DISP_E_OVERFLOW;
3993         }
3994
3995         *pcOut = (CHAR) ulIn;
3996
3997         return S_OK;
3998 }
3999
4000 /**********************************************************************
4001  *              VarI1FromCy [OLEAUT32.250]
4002  * Convert currency to signed char
4003  */
4004 HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
4005    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4006
4007    if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
4008
4009    *pcOut = (CHAR)t;
4010    return S_OK;
4011 }
4012
4013 /******************************************************************************
4014  *              VarUI2FromUI1           [OLEAUT32.257]
4015  */
4016 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
4017 {
4018         TRACE("( %d, %p ), stub\n", bIn, puiOut );
4019
4020         *puiOut = (USHORT) bIn;
4021
4022         return S_OK;
4023 }
4024
4025 /******************************************************************************
4026  *              VarUI2FromI2            [OLEAUT32.258]
4027  */
4028 HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
4029 {
4030         TRACE("( %d, %p ), stub\n", uiIn, puiOut );
4031
4032         if( uiIn < UI2_MIN )
4033         {
4034                 return DISP_E_OVERFLOW;
4035         }
4036
4037         *puiOut = (USHORT) uiIn;
4038
4039         return S_OK;
4040 }
4041
4042 /******************************************************************************
4043  *              VarUI2FromI4            [OLEAUT32.259]
4044  */
4045 HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
4046 {
4047         TRACE("( %ld, %p ), stub\n", lIn, puiOut );
4048
4049         if( lIn < UI2_MIN || lIn > UI2_MAX )
4050         {
4051                 return DISP_E_OVERFLOW;
4052         }
4053
4054         *puiOut = (USHORT) lIn;
4055
4056         return S_OK;
4057 }
4058
4059 /******************************************************************************
4060  *              VarUI2FromR4            [OLEAUT32.260]
4061  */
4062 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
4063 {
4064         TRACE("( %f, %p ), stub\n", fltIn, puiOut );
4065
4066     fltIn = round( fltIn );
4067         if( fltIn < UI2_MIN || fltIn > UI2_MAX )
4068         {
4069                 return DISP_E_OVERFLOW;
4070         }
4071
4072         *puiOut = (USHORT) fltIn;
4073
4074         return S_OK;
4075 }
4076
4077 /******************************************************************************
4078  *              VarUI2FromR8            [OLEAUT32.261]
4079  */
4080 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
4081 {
4082         TRACE("( %f, %p ), stub\n", dblIn, puiOut );
4083
4084     dblIn = round( dblIn );
4085     if( dblIn < UI2_MIN || dblIn > UI2_MAX )
4086         {
4087                 return DISP_E_OVERFLOW;
4088         }
4089
4090         *puiOut = (USHORT) dblIn;
4091
4092         return S_OK;
4093 }
4094
4095 /******************************************************************************
4096  *              VarUI2FromDate          [OLEAUT32.262]
4097  */
4098 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
4099 {
4100         TRACE("( %f, %p ), stub\n", dateIn, puiOut );
4101
4102     dateIn = round( dateIn );
4103         if( dateIn < UI2_MIN || dateIn > UI2_MAX )
4104         {
4105                 return DISP_E_OVERFLOW;
4106         }
4107
4108         *puiOut = (USHORT) dateIn;
4109
4110         return S_OK;
4111 }
4112
4113 /******************************************************************************
4114  *              VarUI2FromStr           [OLEAUT32.264]
4115  */
4116 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
4117 {
4118         double dValue = 0.0;
4119         LPSTR pNewString = NULL;
4120
4121         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
4122
4123         /* Check if we have a valid argument
4124          */
4125         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4126         RemoveCharacterFromString( pNewString, "," );
4127         if( IsValidRealString( pNewString ) == FALSE )
4128         {
4129                 return DISP_E_TYPEMISMATCH;
4130         }
4131
4132         /* Convert the valid string to a floating point number.
4133          */
4134         dValue = atof( pNewString );
4135
4136         /* We don't need the string anymore so free it.
4137          */
4138         HeapFree( GetProcessHeap(), 0, pNewString );
4139
4140         /* Check range of value.
4141      */
4142     dValue = round( dValue );
4143         if( dValue < UI2_MIN || dValue > UI2_MAX )
4144         {
4145                 return DISP_E_OVERFLOW;
4146         }
4147
4148         *puiOut = (USHORT) dValue;
4149
4150         return S_OK;
4151 }
4152
4153 /******************************************************************************
4154  *              VarUI2FromBool          [OLEAUT32.266]
4155  */
4156 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
4157 {
4158         TRACE("( %d, %p ), stub\n", boolIn, puiOut );
4159
4160         *puiOut = (USHORT) boolIn;
4161
4162         return S_OK;
4163 }
4164
4165 /******************************************************************************
4166  *              VarUI2FromI1            [OLEAUT32.267]
4167  */
4168 HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
4169 {
4170         TRACE("( %c, %p ), stub\n", cIn, puiOut );
4171
4172         *puiOut = (USHORT) cIn;
4173
4174         return S_OK;
4175 }
4176
4177 /******************************************************************************
4178  *              VarUI2FromUI4           [OLEAUT32.268]
4179  */
4180 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
4181 {
4182         TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
4183
4184         if( ulIn > UI2_MAX )
4185         {
4186                 return DISP_E_OVERFLOW;
4187         }
4188
4189         *puiOut = (USHORT) ulIn;
4190
4191         return S_OK;
4192 }
4193
4194 /******************************************************************************
4195  *              VarUI4FromStr           [OLEAUT32.277]
4196  */
4197 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
4198 {
4199         double dValue = 0.0;
4200         LPSTR pNewString = NULL;
4201
4202         TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
4203
4204         /* Check if we have a valid argument
4205          */
4206         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4207         RemoveCharacterFromString( pNewString, "," );
4208         if( IsValidRealString( pNewString ) == FALSE )
4209         {
4210                 return DISP_E_TYPEMISMATCH;
4211         }
4212
4213         /* Convert the valid string to a floating point number.
4214          */
4215         dValue = atof( pNewString );
4216
4217         /* We don't need the string anymore so free it.
4218          */
4219         HeapFree( GetProcessHeap(), 0, pNewString );
4220
4221         /* Check range of value.
4222      */
4223     dValue = round( dValue );
4224         if( dValue < UI4_MIN || dValue > UI4_MAX )
4225         {
4226                 return DISP_E_OVERFLOW;
4227         }
4228
4229         *pulOut = (ULONG) dValue;
4230
4231         return S_OK;
4232 }
4233
4234 /**********************************************************************
4235  *              VarUI2FromCy [OLEAUT32.263]
4236  * Convert currency to unsigned short
4237  */
4238 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
4239    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4240
4241    if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
4242
4243    *pusOut = (USHORT)t;
4244
4245    return S_OK;
4246 }
4247
4248 /******************************************************************************
4249  *              VarUI4FromUI1           [OLEAUT32.270]
4250  */
4251 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
4252 {
4253         TRACE("( %d, %p ), stub\n", bIn, pulOut );
4254
4255         *pulOut = (USHORT) bIn;
4256
4257         return S_OK;
4258 }
4259
4260 /******************************************************************************
4261  *              VarUI4FromI2            [OLEAUT32.271]
4262  */
4263 HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
4264 {
4265         TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4266
4267         if( uiIn < UI4_MIN )
4268         {
4269                 return DISP_E_OVERFLOW;
4270         }
4271
4272         *pulOut = (ULONG) uiIn;
4273
4274         return S_OK;
4275 }
4276
4277 /******************************************************************************
4278  *              VarUI4FromI4            [OLEAUT32.272]
4279  */
4280 HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
4281 {
4282         TRACE("( %ld, %p ), stub\n", lIn, pulOut );
4283
4284         if( lIn < 0 )
4285         {
4286                 return DISP_E_OVERFLOW;
4287         }
4288
4289         *pulOut = (ULONG) lIn;
4290
4291         return S_OK;
4292 }
4293
4294 /******************************************************************************
4295  *              VarUI4FromR4            [OLEAUT32.273]
4296  */
4297 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
4298 {
4299     fltIn = round( fltIn );
4300     if( fltIn < UI4_MIN || fltIn > UI4_MAX )
4301         {
4302                 return DISP_E_OVERFLOW;
4303         }
4304
4305         *pulOut = (ULONG) fltIn;
4306
4307         return S_OK;
4308 }
4309
4310 /******************************************************************************
4311  *              VarUI4FromR8            [OLEAUT32.274]
4312  */
4313 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
4314 {
4315         TRACE("( %f, %p ), stub\n", dblIn, pulOut );
4316
4317         dblIn = round( dblIn );
4318         if( dblIn < UI4_MIN || dblIn > UI4_MAX )
4319         {
4320                 return DISP_E_OVERFLOW;
4321         }
4322
4323         *pulOut = (ULONG) dblIn;
4324
4325         return S_OK;
4326 }
4327
4328 /******************************************************************************
4329  *              VarUI4FromDate          [OLEAUT32.275]
4330  */
4331 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
4332 {
4333         TRACE("( %f, %p ), stub\n", dateIn, pulOut );
4334
4335         dateIn = round( dateIn );
4336         if( dateIn < UI4_MIN || dateIn > UI4_MAX )
4337         {
4338                 return DISP_E_OVERFLOW;
4339         }
4340
4341         *pulOut = (ULONG) dateIn;
4342
4343         return S_OK;
4344 }
4345
4346 /******************************************************************************
4347  *              VarUI4FromBool          [OLEAUT32.279]
4348  */
4349 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
4350 {
4351         TRACE("( %d, %p ), stub\n", boolIn, pulOut );
4352
4353         *pulOut = (ULONG) boolIn;
4354
4355         return S_OK;
4356 }
4357
4358 /******************************************************************************
4359  *              VarUI4FromI1            [OLEAUT32.280]
4360  */
4361 HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
4362 {
4363         TRACE("( %c, %p ), stub\n", cIn, pulOut );
4364
4365         *pulOut = (ULONG) cIn;
4366
4367         return S_OK;
4368 }
4369
4370 /******************************************************************************
4371  *              VarUI4FromUI2           [OLEAUT32.281]
4372  */
4373 HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4374 {
4375         TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4376
4377         *pulOut = (ULONG) uiIn;
4378
4379         return S_OK;
4380 }
4381
4382 /**********************************************************************
4383  *              VarUI4FromCy [OLEAUT32.276]
4384  * Convert currency to unsigned long
4385  */
4386 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
4387    double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4388
4389    if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4390
4391    *pulOut = (ULONG)t;
4392
4393    return S_OK;
4394 }
4395
4396 /**********************************************************************
4397  *              VarCyFromUI1 [OLEAUT32.98]
4398  * Convert unsigned char to currency
4399  */
4400 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
4401     pcyOut->s.Hi = 0;
4402     pcyOut->s.Lo = ((ULONG)bIn) * 10000;
4403
4404     return S_OK;
4405 }
4406
4407 /**********************************************************************
4408  *              VarCyFromI2 [OLEAUT32.99]
4409  * Convert signed short to currency
4410  */
4411 HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
4412     if (sIn < 0) pcyOut->s.Hi = -1;
4413     else pcyOut->s.Hi = 0;
4414     pcyOut->s.Lo = ((ULONG)sIn) * 10000;
4415
4416     return S_OK;
4417 }
4418
4419 /**********************************************************************
4420  *              VarCyFromI4 [OLEAUT32.100]
4421  * Convert signed long to currency
4422  */
4423 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4424       double t = (double)lIn * (double)10000;
4425       pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4426       pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4427       if (lIn < 0) pcyOut->s.Hi--;
4428
4429       return S_OK;
4430 }
4431
4432 /**********************************************************************
4433  *              VarCyFromR4 [OLEAUT32.101]
4434  * Convert float to currency
4435  */
4436 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
4437    double t = round((double)fltIn * (double)10000);
4438    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4439    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4440    if (fltIn < 0) pcyOut->s.Hi--;
4441
4442    return S_OK;
4443 }
4444
4445 /**********************************************************************
4446  *              VarCyFromR8 [OLEAUT32.102]
4447  * Convert double to currency
4448  */
4449 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
4450    double t = round(dblIn * (double)10000);
4451    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4452    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4453    if (dblIn < 0) pcyOut->s.Hi--;
4454
4455    return S_OK;
4456 }
4457
4458 /**********************************************************************
4459  *              VarCyFromDate [OLEAUT32.103]
4460  * Convert date to currency
4461  */
4462 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
4463    double t = round((double)dateIn * (double)10000);
4464    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4465    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4466    if (dateIn < 0) pcyOut->s.Hi--;
4467
4468    return S_OK;
4469 }
4470
4471 /**********************************************************************
4472  *              VarCyFromStr [OLEAUT32.104]
4473  * FIXME: Never tested with decimal seperator other than '.'
4474  */
4475 HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
4476
4477         LPSTR   pNewString      = NULL;
4478     char   *decSep          = NULL;
4479     char   *strPtr,*curPtr  = NULL;
4480     int size, rc;
4481     double currencyVal = 0.0;
4482
4483
4484         pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4485         TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString, lcid, dwFlags, pcyOut );
4486
4487     /* Get locale information - Decimal Seperator (size includes 0x00) */
4488     size = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, NULL, 0);
4489     decSep = (char *) malloc(size);
4490     rc = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, decSep, size);
4491     TRACE("Decimal Seperator is '%s'\n", decSep);
4492
4493     /* Now copy to temporary buffer, skipping any character except 0-9 and
4494        the decimal seperator */
4495     curPtr = pBuffer;      /* Current position in string being built       */
4496     strPtr = pNewString;   /* Current position in supplied currenct string */
4497
4498     while (*strPtr) {
4499         /* If decimal seperator, skip it and put '.' in string */
4500         if (strncmp(strPtr, decSep, (size-1)) == 0) {
4501             strPtr = strPtr + (size-1);
4502             *curPtr = '.';
4503             curPtr++;
4504         } else if ((*strPtr == '+' || *strPtr == '-') ||
4505                    (*strPtr >= '0' && *strPtr <= '9')) {
4506             *curPtr = *strPtr;
4507             strPtr++;
4508             curPtr++;
4509         } else strPtr++;
4510     }
4511     *curPtr = 0x00;
4512
4513     /* Try to get currency into a double */
4514     currencyVal = atof(pBuffer);
4515     TRACE("Converted string '%s' to %f\n", pBuffer, currencyVal);
4516
4517     /* Free allocated storage */
4518     HeapFree( GetProcessHeap(), 0, pNewString );
4519     free(decSep);
4520
4521     /* Convert double -> currency using internal routine */
4522         return VarCyFromR8(currencyVal, pcyOut);
4523 }
4524
4525
4526 /**********************************************************************
4527  *              VarCyFromBool [OLEAUT32.106]
4528  * Convert boolean to currency
4529  */
4530 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
4531    if (boolIn < 0) pcyOut->s.Hi = -1;
4532    else pcyOut->s.Hi = 0;
4533    pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
4534
4535    return S_OK;
4536 }
4537
4538 /**********************************************************************
4539  *              VarCyFromI1 [OLEAUT32.225]
4540  * Convert signed char to currency
4541  */
4542 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
4543    if (cIn < 0) pcyOut->s.Hi = -1;
4544    else pcyOut->s.Hi = 0;
4545    pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
4546
4547    return S_OK;
4548 }
4549
4550 /**********************************************************************
4551  *              VarCyFromUI2 [OLEAUT32.226]
4552  * Convert unsigned short to currency
4553  */
4554 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
4555    pcyOut->s.Hi = 0;
4556    pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
4557
4558    return S_OK;
4559 }
4560
4561 /**********************************************************************
4562  *              VarCyFromUI4 [OLEAUT32.227]
4563  * Convert unsigned long to currency
4564  */
4565 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4566    double t = (double)ulIn * (double)10000;
4567    pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4568    pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4569
4570    return S_OK;
4571 }
4572
4573
4574 /**********************************************************************
4575  *              DosDateTimeToVariantTime [OLEAUT32.14]
4576  * Convert dos representation of time to the date and time representation
4577  * stored in a variant.
4578  */
4579 INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4580                                     DATE *pvtime)
4581 {
4582     struct tm t;
4583
4584     TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
4585
4586     t.tm_sec = (wDosTime & 0x001f) * 2;
4587     t.tm_min = (wDosTime & 0x07e0) >> 5;
4588     t.tm_hour = (wDosTime & 0xf800) >> 11;
4589
4590     t.tm_mday = (wDosDate & 0x001f);
4591     t.tm_mon = (wDosDate & 0x01e0) >> 5;
4592     t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
4593
4594     return TmToDATE( &t, pvtime );
4595 }
4596
4597
4598 /**********************************************************************
4599  *              VarParseNumFromStr [OLEAUT32.46]
4600  */
4601 HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
4602                                   NUMPARSE * pnumprs, BYTE * rgbDig)
4603 {
4604     int i,lastent=0;
4605     int cDig;
4606     BOOL foundNum=FALSE;
4607
4608     FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
4609     FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
4610
4611     /* The other struct components are to be set by us */
4612     memset(rgbDig,0,pnumprs->cDig);
4613
4614     /* FIXME: Just patching some values in */
4615     pnumprs->nPwr10     = 0;
4616     pnumprs->nBaseShift = 0;
4617     pnumprs->cchUsed    = lastent;
4618     pnumprs->dwOutFlags = NUMPRS_DECIMAL;
4619
4620     cDig = 0;
4621     for (i=0; strIn[i] ;i++) {
4622         if ((strIn[i]>='0') && (strIn[i]<='9')) {
4623             foundNum = TRUE;
4624             if (pnumprs->cDig > cDig) {
4625                 *(rgbDig++)=strIn[i]-'0';
4626                 cDig++;
4627                 lastent = i;
4628             }
4629         } else if ((strIn[i]=='-') && (foundNum==FALSE)) {
4630             pnumprs->dwOutFlags |= NUMPRS_NEG;
4631         }
4632     }
4633     pnumprs->cDig       = cDig;
4634     TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags);
4635     return S_OK;
4636 }
4637
4638
4639 /**********************************************************************
4640  *              VarNumFromParseNum [OLEAUT32.47]
4641  */
4642 HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
4643                                   ULONG dwVtBits, VARIANT * pvar)
4644 {
4645     DWORD xint;
4646     int i;
4647     FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
4648
4649     xint = 0;
4650     for (i=0;i<pnumprs->cDig;i++)
4651         xint = xint*10 + rgbDig[i];
4652
4653     if (pnumprs->dwOutFlags & NUMPRS_NEG) {
4654         xint = xint * -1;
4655     }
4656
4657     VariantInit(pvar);
4658     if (dwVtBits & VTBIT_I4) {
4659         V_VT(pvar) = VT_I4;
4660         V_UNION(pvar,intVal) = xint;
4661         return S_OK;
4662     }
4663     if (dwVtBits & VTBIT_R8) {
4664         V_VT(pvar) = VT_R8;
4665         V_UNION(pvar,dblVal) = xint;
4666         return S_OK;
4667     }
4668     if (dwVtBits & VTBIT_R4) {
4669         V_VT(pvar) = VT_R4;
4670         V_UNION(pvar,fltVal) = xint;
4671         return S_OK;
4672     }
4673     if (dwVtBits & VTBIT_I2) {
4674         V_VT(pvar) = VT_I2;
4675         V_UNION(pvar,iVal) = xint;
4676         return S_OK;
4677     }
4678     /* FIXME: Currency should be from a double */
4679     if (dwVtBits & VTBIT_CY) {
4680         V_VT(pvar) = VT_CY;
4681         TRACE("Calculated currency is xint=%ld\n", xint);
4682         VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4683         TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar,cyVal).s.Hi, V_UNION(pvar,cyVal).s.Lo);
4684         return VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4685     }
4686
4687         FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint);
4688         return E_FAIL;
4689 }
4690
4691
4692 /**********************************************************************
4693  *              VarFormatDateTime [OLEAUT32.97]
4694  */
4695 HRESULT WINAPI VarFormatDateTime(LPVARIANT var, INT format, ULONG dwFlags, BSTR *out)
4696 {
4697     FIXME("%p %d %lx %p\n", var, format, dwFlags, out);
4698     return E_NOTIMPL;
4699 }
4700
4701 /**********************************************************************
4702  *              VarFormatCurrency [OLEAUT32.127]
4703  */
4704 HRESULT WINAPI VarFormatCurrency(LPVARIANT var, INT digits, INT lead, INT paren, INT group, ULONG dwFlags, BSTR *out)
4705 {
4706     FIXME("%p %d %d %d %d %lx %p\n", var, digits, lead, paren, group, dwFlags, out);
4707     return E_NOTIMPL;
4708 }
4709
4710 /**********************************************************************
4711  *              VariantTimeToDosDateTime [OLEAUT32.13]
4712  * Convert variant representation of time to the date and time representation
4713  * stored in dos.
4714  */
4715 INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
4716 {
4717     struct tm t;
4718     *wDosTime = 0;
4719     *wDosDate = 0;
4720
4721     TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate, *wDosTime, &pvtime );
4722
4723     if (DateToTm(pvtime, 0, &t) < 0) return 0;
4724
4725     *wDosTime = *wDosTime | (t.tm_sec / 2);
4726     *wDosTime = *wDosTime | (t.tm_min << 5);
4727     *wDosTime = *wDosTime | (t.tm_hour << 11);
4728
4729     *wDosDate = *wDosDate | t.tm_mday ;
4730     *wDosDate = *wDosDate | t.tm_mon << 5;
4731     *wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
4732
4733     return 1;
4734 }
4735
4736
4737 /***********************************************************************
4738  *              SystemTimeToVariantTime [OLEAUT32.184]
4739  */
4740 HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME  lpSystemTime, double *pvtime )
4741 {
4742     struct tm t;
4743
4744     TRACE(" %d/%d/%d %d:%d:%d\n",
4745           lpSystemTime->wMonth, lpSystemTime->wDay,
4746           lpSystemTime->wYear, lpSystemTime->wHour,
4747           lpSystemTime->wMinute, lpSystemTime->wSecond);
4748
4749     if (lpSystemTime->wYear >= 1900)
4750     {
4751         t.tm_sec = lpSystemTime->wSecond;
4752         t.tm_min = lpSystemTime->wMinute;
4753         t.tm_hour = lpSystemTime->wHour;
4754
4755         t.tm_mday = lpSystemTime->wDay;
4756         t.tm_mon = lpSystemTime->wMonth - 1; /* tm_mon is 0..11, wMonth is 1..12 */
4757         t.tm_year = lpSystemTime->wYear;
4758
4759         return TmToDATE( &t, pvtime );
4760     }
4761     else
4762     {
4763         double tmpDate;
4764         long firstDayOfNextYear;
4765         long thisDay;
4766         long leftInYear;
4767         long result;
4768
4769         double decimalPart = 0.0;
4770
4771         t.tm_sec = lpSystemTime->wSecond;
4772         t.tm_min = lpSystemTime->wMinute;
4773         t.tm_hour = lpSystemTime->wHour;
4774
4775         /* Step year forward the same number of years before 1900 */
4776         t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
4777         t.tm_mon = lpSystemTime->wMonth - 1;
4778         t.tm_mday = lpSystemTime->wDay;
4779
4780         /* Calculate date */
4781         TmToDATE( &t, pvtime );
4782
4783         thisDay = (double) floor( *pvtime );
4784         decimalPart = fmod( *pvtime, thisDay );
4785
4786         /* Now, calculate the same time for the first of Jan that year */
4787         t.tm_mon = 0;
4788         t.tm_mday = 1;
4789         t.tm_sec = 0;
4790         t.tm_min = 0;
4791         t.tm_hour = 0;
4792         t.tm_year = t.tm_year+1;
4793         TmToDATE( &t, &tmpDate );
4794         firstDayOfNextYear = (long) floor(tmpDate);
4795
4796         /* Finally since we know the size of the year, subtract the two to get
4797            remaining time in the year                                          */
4798         leftInYear = firstDayOfNextYear - thisDay;
4799
4800         /* Now we want full years up to the year in question, and remainder of year
4801            of the year in question */
4802         if (isleap(lpSystemTime->wYear) ) {
4803            TRACE("Extra day due to leap year\n");
4804            result = 2.0 - ((firstDayOfNextYear - 366) + leftInYear - 2.0);
4805         } else {
4806            result = 2.0 - ((firstDayOfNextYear - 365) + leftInYear - 2.0);
4807         }
4808         *pvtime = (double) result + decimalPart;
4809         TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime, firstDayOfNextYear, thisDay, leftInYear);
4810
4811         return 1;
4812     }
4813
4814     return 0;
4815 }
4816
4817 /***********************************************************************
4818  *              VariantTimeToSystemTime [OLEAUT32.185]
4819  */
4820 HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME  lpSystemTime )
4821 {
4822     double t = 0, timeofday = 0;
4823
4824     static const BYTE Days_Per_Month[] =    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4825     static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4826
4827     /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4828     static const BYTE Month_Code[] =    {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4829     static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4830
4831     /* The Century_Code is used to find the Day of the Week */
4832     static const BYTE Century_Code[]  = {0, 6, 4, 2};
4833
4834     struct tm r;
4835
4836     TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime);
4837
4838     if (vtime >= 0)
4839     {
4840
4841         if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4842
4843         lpSystemTime->wSecond = r.tm_sec;
4844         lpSystemTime->wMinute = r.tm_min;
4845         lpSystemTime->wHour = r.tm_hour;
4846         lpSystemTime->wDay = r.tm_mday;
4847         lpSystemTime->wMonth = r.tm_mon;
4848
4849         if (lpSystemTime->wMonth == 12)
4850             lpSystemTime->wMonth = 1;
4851         else
4852             lpSystemTime->wMonth++;
4853
4854         lpSystemTime->wYear = r.tm_year;
4855     }
4856     else
4857     {
4858         vtime = -1*vtime;
4859
4860         if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4861
4862         lpSystemTime->wSecond = r.tm_sec;
4863         lpSystemTime->wMinute = r.tm_min;
4864         lpSystemTime->wHour = r.tm_hour;
4865
4866         lpSystemTime->wMonth = 13 - r.tm_mon;
4867
4868         if (lpSystemTime->wMonth == 1)
4869             lpSystemTime->wMonth = 12;
4870         else
4871             lpSystemTime->wMonth--;
4872
4873         lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
4874
4875         if (!isleap(lpSystemTime->wYear) )
4876             lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
4877         else
4878             lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
4879
4880
4881     }
4882
4883     if (!isleap(lpSystemTime->wYear))
4884     {
4885         /*
4886           (Century_Code+Month_Code+Year_Code+Day) % 7
4887
4888           The century code repeats every 400 years , so the array
4889           works out like this,
4890
4891           Century_Code[0] is for 16th/20th Centry
4892           Century_Code[1] is for 17th/21th Centry
4893           Century_Code[2] is for 18th/22th Centry
4894           Century_Code[3] is for 19th/23th Centry
4895
4896           The year code is found with the formula (year + (year / 4))
4897           the "year" must be between 0 and 99 .
4898
4899           The Month Code (Month_Code[1]) starts with January and
4900           ends with December.
4901         */
4902
4903         lpSystemTime->wDayOfWeek = (
4904             Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
4905             ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4906             Month_Code[lpSystemTime->wMonth]+
4907             lpSystemTime->wDay) % 7;
4908
4909         if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4910         else lpSystemTime->wDayOfWeek -= 1;
4911     }
4912     else
4913     {
4914         lpSystemTime->wDayOfWeek = (
4915             Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
4916             ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4917             Month_Code_LY[lpSystemTime->wMonth]+
4918             lpSystemTime->wDay) % 7;
4919
4920         if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4921         else lpSystemTime->wDayOfWeek -= 1;
4922     }
4923
4924     t = floor(vtime);
4925     timeofday = vtime - t;
4926
4927     lpSystemTime->wMilliseconds = (timeofday
4928                                    - lpSystemTime->wHour*(1/24)
4929                                    - lpSystemTime->wMinute*(1/1440)
4930                                    - lpSystemTime->wSecond*(1/86400) )*(1/5184000);
4931
4932     return 1;
4933 }
4934
4935 /***********************************************************************
4936  *              VarUdateFromDate [OLEAUT32.331]
4937  */
4938 HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
4939 {
4940     HRESULT i = 0;
4941     static const BYTE Days_Per_Month[] =    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4942     static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4943
4944     TRACE("DATE = %f\n", (double)datein);
4945     i = VariantTimeToSystemTime(datein, &(pudateout->st) );
4946
4947     if (i)
4948     {
4949         pudateout->wDayOfYear = 0;
4950
4951         if (isleap(pudateout->st.wYear))
4952         {
4953             for (i =1; i<pudateout->st.wMonth; i++)
4954                 pudateout->wDayOfYear += Days_Per_Month[i];
4955         }
4956         else
4957         {
4958             for (i =1; i<pudateout->st.wMonth; i++)
4959                 pudateout->wDayOfYear += Days_Per_Month_LY[i];
4960         }
4961
4962         pudateout->wDayOfYear += pudateout->st.wDay;
4963         dwFlags = 0; /*VAR_VALIDDATE*/
4964     }
4965     else dwFlags = 0;
4966
4967     return i;
4968 }
4969
4970 /***********************************************************************
4971  *              VarDateFromUdate [OLEAUT32.330]
4972  */
4973 HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
4974                                 ULONG dwFlags, DATE *datein)
4975 {
4976     HRESULT i;
4977     double t = 0;
4978     TRACE(" %d/%d/%d %d:%d:%d\n",
4979           pudateout->st.wMonth, pudateout->st.wDay,
4980           pudateout->st.wYear, pudateout->st.wHour,
4981           pudateout->st.wMinute, pudateout->st.wSecond);
4982
4983
4984     i = SystemTimeToVariantTime(&(pudateout->st), &t);
4985     *datein = t;
4986
4987     if (i) return S_OK;
4988     else return E_INVALIDARG;
4989 }
4990
4991
4992 /**********************************************************************
4993  *              VarBstrCmp [OLEAUT32.314]
4994  *
4995  * flags can be:
4996  *   NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4997  *   NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4998  *
4999  */
5000 HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
5001 {
5002     INT r;
5003
5004     TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
5005
5006     /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
5007     if((!left) || (!right)) {
5008
5009         if (!left && (!right || *right==0)) return VARCMP_EQ;
5010         else if (!right && (!left || *left==0)) return VARCMP_EQ;
5011         else return VARCMP_NULL;
5012     }
5013
5014     if(flags&NORM_IGNORECASE)
5015         r = lstrcmpiW(left,right);
5016     else
5017         r = lstrcmpW(left,right);
5018
5019     if(r<0)
5020         return VARCMP_LT;
5021     if(r>0)
5022         return VARCMP_GT;
5023
5024     return VARCMP_EQ;
5025 }
5026
5027 /**********************************************************************
5028  *              VarBstrCat [OLEAUT32.313]
5029  */
5030 HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
5031 {
5032     BSTR result;
5033     int size = 0;
5034
5035     TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
5036
5037     /* On Windows, NULL parms are still handled (as empty strings) */
5038     if (left)  size=size + lstrlenW(left);
5039     if (right) size=size + lstrlenW(right);
5040
5041     if (out) {
5042         result = SysAllocStringLen(NULL, size);
5043         *out = result;
5044         if (left) lstrcatW(result,left);
5045         if (right) lstrcatW(result,right);
5046         TRACE("result = %s, [%p]\n", debugstr_w(result), result);
5047     }
5048     return S_OK;
5049 }
5050
5051 /**********************************************************************
5052  *              VarCat [OLEAUT32.318]
5053  */
5054 HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
5055 {
5056     /* Should we VariantClear out? */
5057     /* Can we handle array, vector, by ref etc. */
5058     if ((V_VT(left)&VT_TYPEMASK) == VT_NULL &&
5059         (V_VT(right)&VT_TYPEMASK) == VT_NULL)
5060     {
5061         V_VT(out) = VT_NULL;
5062         return S_OK;
5063     }
5064
5065     if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR)
5066     {
5067         V_VT(out) = VT_BSTR;
5068         VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out));
5069         return S_OK;
5070     }
5071     if (V_VT(left) == VT_BSTR) {
5072         VARIANT bstrvar;
5073         HRESULT hres;
5074
5075         V_VT(out) = VT_BSTR;
5076         hres = VariantChangeTypeEx(&bstrvar,right,0,0,VT_BSTR);
5077         if (hres) {
5078             FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right));
5079             return hres;
5080         }
5081         VarBstrCat (V_BSTR(left), V_BSTR(&bstrvar), &V_BSTR(out));
5082         return S_OK;
5083     }
5084     if (V_VT(right) == VT_BSTR) {
5085         VARIANT bstrvar;
5086         HRESULT hres;
5087
5088         V_VT(out) = VT_BSTR;
5089         hres = VariantChangeTypeEx(&bstrvar,left,0,0,VT_BSTR);
5090         if (hres) {
5091             FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right));
5092             return hres;
5093         }
5094         VarBstrCat (V_BSTR(&bstrvar), V_BSTR(right), &V_BSTR(out));
5095         return S_OK;
5096     }
5097     FIXME ("types %d / %d not supported\n",V_VT(left)&VT_TYPEMASK, V_VT(right)&VT_TYPEMASK);
5098     return S_OK;
5099 }
5100
5101 /**********************************************************************
5102  *              VarCmp [OLEAUT32.176]
5103  *
5104  * flags can be:
5105  *   NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
5106  *   NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
5107  *
5108  */
5109 HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
5110 {
5111
5112
5113     BOOL        lOk        = TRUE;
5114     BOOL        rOk        = TRUE;
5115     LONGLONG    lVal = -1;
5116     LONGLONG    rVal = -1;
5117     VARIANT     rv,lv;
5118     DWORD       xmask;
5119     HRESULT     rc;
5120
5121     VariantInit(&lv);VariantInit(&rv);
5122     V_VT(right) &= ~0x8000; /* hack since we sometime get this flag.  */
5123     V_VT(left) &= ~0x8000; /* hack since we sometime get this flag. */
5124
5125     TRACE("Left Var:\n");
5126     dump_Variant(left);
5127     TRACE("Right Var:\n");
5128     dump_Variant(right);
5129
5130     /* If either are null, then return VARCMP_NULL */
5131     if ((V_VT(left)&VT_TYPEMASK) == VT_NULL ||
5132         (V_VT(right)&VT_TYPEMASK) == VT_NULL)
5133         return VARCMP_NULL;
5134
5135     /* Strings - use VarBstrCmp */
5136     if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
5137         (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
5138         return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags);
5139     }
5140
5141     xmask = (1<<(V_VT(left)&VT_TYPEMASK))|(1<<(V_VT(right)&VT_TYPEMASK));
5142     if (xmask & (1<<VT_R8)) {
5143         rc = VariantChangeType(&lv,left,0,VT_R8);
5144         if (FAILED(rc)) return rc;
5145         rc = VariantChangeType(&rv,right,0,VT_R8);
5146         if (FAILED(rc)) return rc;
5147         
5148         if (V_R8(&lv) == V_R8(&rv)) return VARCMP_EQ;
5149         if (V_R8(&lv) < V_R8(&rv)) return VARCMP_LT;
5150         if (V_R8(&lv) > V_R8(&rv)) return VARCMP_GT;
5151         return E_FAIL; /* can't get here */
5152     }
5153     if (xmask & (1<<VT_R4)) {
5154         rc = VariantChangeType(&lv,left,0,VT_R4);
5155         if (FAILED(rc)) return rc;
5156         rc = VariantChangeType(&rv,right,0,VT_R4);
5157         if (FAILED(rc)) return rc;
5158         
5159         if (V_R4(&lv) == V_R4(&rv)) return VARCMP_EQ;
5160         if (V_R4(&lv) < V_R4(&rv)) return VARCMP_LT;
5161         if (V_R4(&lv) > V_R4(&rv)) return VARCMP_GT;
5162         return E_FAIL; /* can't get here */
5163     }
5164
5165     /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
5166            Use LONGLONG to maximize ranges                              */
5167     lOk = TRUE;
5168     switch (V_VT(left)&VT_TYPEMASK) {
5169     case VT_I1   : lVal = V_UNION(left,cVal); break;
5170     case VT_I2   : lVal = V_UNION(left,iVal); break;
5171     case VT_I4   : lVal = V_UNION(left,lVal); break;
5172     case VT_INT  : lVal = V_UNION(left,lVal); break;
5173     case VT_UI1  : lVal = V_UNION(left,bVal); break;
5174     case VT_UI2  : lVal = V_UNION(left,uiVal); break;
5175     case VT_UI4  : lVal = V_UNION(left,ulVal); break;
5176     case VT_UINT : lVal = V_UNION(left,ulVal); break;
5177     case VT_BOOL : lVal = V_UNION(left,boolVal); break;
5178     default: lOk = FALSE;
5179     }
5180
5181     rOk = TRUE;
5182     switch (V_VT(right)&VT_TYPEMASK) {
5183     case VT_I1   : rVal = V_UNION(right,cVal); break;
5184     case VT_I2   : rVal = V_UNION(right,iVal); break;
5185     case VT_I4   : rVal = V_UNION(right,lVal); break;
5186     case VT_INT  : rVal = V_UNION(right,lVal); break;
5187     case VT_UI1  : rVal = V_UNION(right,bVal); break;
5188     case VT_UI2  : rVal = V_UNION(right,uiVal); break;
5189     case VT_UI4  : rVal = V_UNION(right,ulVal); break;
5190     case VT_UINT : rVal = V_UNION(right,ulVal); break;
5191     case VT_BOOL : rVal = V_UNION(right,boolVal); break;
5192     default: rOk = FALSE;
5193     }
5194
5195     if (lOk && rOk) {
5196         if (lVal < rVal) {
5197             return VARCMP_LT;
5198         } else if (lVal > rVal) {
5199             return VARCMP_GT;
5200         } else {
5201             return VARCMP_EQ;
5202         }
5203     }
5204
5205     /* Strings - use VarBstrCmp */
5206     if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
5207         (V_VT(right)&VT_TYPEMASK) == VT_DATE) {
5208
5209         if (floor(V_UNION(left,date)) == floor(V_UNION(right,date))) {
5210             /* Due to floating point rounding errors, calculate varDate in whole numbers) */
5211             double wholePart = 0.0;
5212             double leftR;
5213             double rightR;
5214
5215             /* Get the fraction * 24*60*60 to make it into whole seconds */
5216             wholePart = (double) floor( V_UNION(left,date) );
5217             if (wholePart == 0) wholePart = 1;
5218             leftR = floor(fmod( V_UNION(left,date), wholePart ) * (24*60*60));
5219
5220             wholePart = (double) floor( V_UNION(right,date) );
5221             if (wholePart == 0) wholePart = 1;
5222             rightR = floor(fmod( V_UNION(right,date), wholePart ) * (24*60*60));
5223
5224             if (leftR < rightR) {
5225                 return VARCMP_LT;
5226             } else if (leftR > rightR) {
5227                 return VARCMP_GT;
5228             } else {
5229                 return VARCMP_EQ;
5230             }
5231
5232         } else if (V_UNION(left,date) < V_UNION(right,date)) {
5233             return VARCMP_LT;
5234         } else if (V_UNION(left,date) > V_UNION(right,date)) {
5235             return VARCMP_GT;
5236         }
5237     }
5238     FIXME("VarCmp partial implementation, doesnt support vt 0x%x / 0x%x\n",V_VT(left), V_VT(right));
5239     return E_FAIL;
5240 }
5241
5242 /**********************************************************************
5243  *              VarAnd [OLEAUT32.142]
5244  *
5245  */
5246 HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5247 {
5248     HRESULT rc = E_FAIL;
5249
5250     TRACE("Left Var:\n");
5251     dump_Variant(left);
5252     TRACE("Right Var:\n");
5253     dump_Variant(right);
5254
5255     if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5256         (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5257
5258         V_VT(result) = VT_BOOL;
5259         if (V_BOOL(left) && V_BOOL(right)) {
5260             V_BOOL(result) = VARIANT_TRUE;
5261         } else {
5262             V_BOOL(result) = VARIANT_FALSE;
5263         }
5264         rc = S_OK;
5265
5266     } else {
5267         /* Integers */
5268         BOOL         lOk        = TRUE;
5269         BOOL         rOk        = TRUE;
5270         LONGLONG     lVal = -1;
5271         LONGLONG     rVal = -1;
5272         LONGLONG     res  = -1;
5273         int          resT = 0; /* Testing has shown I2 & I2 == I2, all else 
5274                                   becomes I4, even unsigned ints (incl. UI2) */
5275
5276         lOk = TRUE;
5277         switch (V_VT(left)&VT_TYPEMASK) {
5278         case VT_I1   : lVal = V_UNION(left,cVal);  resT=VT_I4; break;
5279         case VT_I2   : lVal = V_UNION(left,iVal);  resT=VT_I2; break;
5280         case VT_I4   : lVal = V_UNION(left,lVal);  resT=VT_I4; break;
5281         case VT_INT  : lVal = V_UNION(left,lVal);  resT=VT_I4; break;
5282         case VT_UI1  : lVal = V_UNION(left,bVal);  resT=VT_I4; break;
5283         case VT_UI2  : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5284         case VT_UI4  : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5285         case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5286         default: lOk = FALSE;
5287         }
5288
5289         rOk = TRUE;
5290         switch (V_VT(right)&VT_TYPEMASK) {
5291         case VT_I1   : rVal = V_UNION(right,cVal);  resT=VT_I4; break;
5292         case VT_I2   : rVal = V_UNION(right,iVal);  resT=max(VT_I2, resT); break;
5293         case VT_I4   : rVal = V_UNION(right,lVal);  resT=VT_I4; break;
5294         case VT_INT  : rVal = V_UNION(right,lVal);  resT=VT_I4; break;
5295         case VT_UI1  : rVal = V_UNION(right,bVal);  resT=VT_I4; break;
5296         case VT_UI2  : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5297         case VT_UI4  : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5298         case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5299         default: rOk = FALSE;
5300         }
5301
5302         if (lOk && rOk) {
5303             res = (lVal & rVal);
5304             V_VT(result) = resT;
5305             switch (resT) {
5306             case VT_I2   : V_UNION(result,iVal)  = res; break;
5307             case VT_I4   : V_UNION(result,lVal)  = res; break;
5308             default:
5309                 FIXME("Unexpected result variant type %x\n", resT);
5310                 V_UNION(result,lVal)  = res;
5311             }
5312             rc = S_OK;
5313
5314         } else {
5315             FIXME("VarAnd stub\n");
5316         }
5317     }
5318
5319     TRACE("rc=%d, Result:\n", (int) rc);
5320     dump_Variant(result);
5321     return rc;
5322 }
5323
5324 /**********************************************************************
5325  *              VarAdd [OLEAUT32.141]
5326  * FIXME: From MSDN: If ... Then
5327  * Both expressions are of the string type Concatenated.
5328  * One expression is a string type and the other a character Addition.
5329  * One expression is numeric and the other is a string Addition.
5330  * Both expressions are numeric Addition.
5331  * Either expression is NULL NULL is returned.
5332  * Both expressions are empty  Integer subtype is returned.
5333  *
5334  */
5335 HRESULT WINAPI VarAdd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5336 {
5337     HRESULT rc = E_FAIL;
5338
5339     TRACE("Left Var:\n");
5340     dump_Variant(left);
5341     TRACE("Right Var:\n");
5342     dump_Variant(right);
5343
5344     /* Handle strings as concat */
5345     if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
5346         (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
5347         V_VT(result) = VT_BSTR;
5348         rc = VarBstrCat(V_BSTR(left), V_BSTR(right), &V_BSTR(result));
5349     } else {
5350
5351         /* Integers */
5352         BOOL         lOk        = TRUE;
5353         BOOL         rOk        = TRUE;
5354         LONGLONG     lVal = -1;
5355         LONGLONG     rVal = -1;
5356         LONGLONG     res  = -1;
5357         int          resT = 0; /* Testing has shown I2 + I2 == I2, all else
5358                                   becomes I4                                */
5359
5360         lOk = TRUE;
5361         switch (V_VT(left)&VT_TYPEMASK) {
5362         case VT_I1   : lVal = V_UNION(left,cVal);  resT=VT_I4; break;
5363         case VT_I2   : lVal = V_UNION(left,iVal);  resT=VT_I2; break;
5364         case VT_I4   : lVal = V_UNION(left,lVal);  resT=VT_I4; break;
5365         case VT_INT  : lVal = V_UNION(left,lVal);  resT=VT_I4; break;
5366         case VT_UI1  : lVal = V_UNION(left,bVal);  resT=VT_I4; break;
5367         case VT_UI2  : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5368         case VT_UI4  : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5369         case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5370         default: lOk = FALSE;
5371         }
5372
5373         rOk = TRUE;
5374         switch (V_VT(right)&VT_TYPEMASK) {
5375         case VT_I1   : rVal = V_UNION(right,cVal);  resT=VT_I4; break;
5376         case VT_I2   : rVal = V_UNION(right,iVal);  resT=max(VT_I2, resT); break;
5377         case VT_I4   : rVal = V_UNION(right,lVal);  resT=VT_I4; break;
5378         case VT_INT  : rVal = V_UNION(right,lVal);  resT=VT_I4; break;
5379         case VT_UI1  : rVal = V_UNION(right,bVal);  resT=VT_I4; break;
5380         case VT_UI2  : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5381         case VT_UI4  : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5382         case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5383         default: rOk = FALSE;
5384         }
5385
5386         if (lOk && rOk) {
5387             res = (lVal + rVal);
5388             V_VT(result) = resT;
5389             switch (resT) {
5390             case VT_I2   : V_UNION(result,iVal)  = res; break;
5391             case VT_I4   : V_UNION(result,lVal)  = res; break;
5392             default:
5393                 FIXME("Unexpected result variant type %x\n", resT);
5394                 V_UNION(result,lVal)  = res;
5395             }
5396             rc = S_OK;
5397
5398         } else {
5399             FIXME("unimplemented part\n");
5400         }
5401     }
5402
5403     TRACE("rc=%d, Result:\n", (int) rc);
5404     dump_Variant(result);
5405     return rc;
5406 }
5407
5408 /**********************************************************************
5409  *              VarMul [OLEAUT32.156]
5410  *
5411  */
5412 HRESULT WINAPI VarMul(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5413 {
5414     HRESULT rc = E_FAIL;
5415     VARTYPE lvt,rvt,resvt;
5416     VARIANT lv,rv;
5417     BOOL found;
5418
5419     TRACE("left: ");dump_Variant(left);
5420     TRACE("right: ");dump_Variant(right);
5421
5422     VariantInit(&lv);VariantInit(&rv);
5423     lvt = V_VT(left)&VT_TYPEMASK;
5424     rvt = V_VT(right)&VT_TYPEMASK;
5425     found = FALSE;resvt=VT_VOID;
5426     if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
5427         found = TRUE;
5428         resvt = VT_R8;
5429     }
5430     if (!found && (((1<<lvt) | (1<<rvt)) & ((1<<VT_I1)|(1<<VT_I2)|(1<<VT_UI1)|(1<<VT_UI2)|(1<<VT_I4)|(1<<VT_UI4)|(1<<VT_INT)|(1<<VT_UINT)))) {
5431         found = TRUE;
5432         resvt = VT_I4;
5433     }
5434     if (!found) {
5435         FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
5436         return E_FAIL;
5437     }
5438     rc = VariantChangeType(&lv, left, 0, resvt);
5439     if (FAILED(rc)) {
5440         FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
5441         return rc;
5442     }
5443     rc = VariantChangeType(&rv, right, 0, resvt);
5444     if (FAILED(rc)) {
5445         FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
5446         return rc;
5447     }
5448     switch (resvt) {
5449     case VT_R8:
5450         V_VT(result) = resvt;
5451         V_R8(result) = V_R8(&lv) * V_R8(&rv);
5452         rc = S_OK;
5453         break;
5454     case VT_I4:
5455         V_VT(result) = resvt;
5456         V_I4(result) = V_I4(&lv) * V_I4(&rv);
5457         rc = S_OK;
5458         break;
5459     }
5460     TRACE("rc=%d, Result:\n", (int) rc);
5461     dump_Variant(result);
5462     return rc;
5463 }
5464
5465 /**********************************************************************
5466  *              VarDiv [OLEAUT32.143]
5467  *
5468  */
5469 HRESULT WINAPI VarDiv(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5470 {
5471     HRESULT rc = E_FAIL;
5472     VARTYPE lvt,rvt,resvt;
5473     VARIANT lv,rv;
5474     BOOL found;
5475
5476     TRACE("left: ");dump_Variant(left);
5477     TRACE("right: ");dump_Variant(right);
5478
5479     VariantInit(&lv);VariantInit(&rv);
5480     lvt = V_VT(left)&VT_TYPEMASK;
5481     rvt = V_VT(right)&VT_TYPEMASK;
5482     found = FALSE;resvt = VT_VOID;
5483     if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
5484         found = TRUE;
5485         resvt = VT_R8;
5486     }
5487     if (!found && (((1<<lvt) | (1<<rvt)) & ((1<<VT_I1)|(1<<VT_I2)|(1<<VT_UI1)|(1<<VT_UI2)|(1<<VT_I4)|(1<<VT_UI4)|(1<<VT_INT)|(1<<VT_UINT)))) {
5488         found = TRUE;
5489         resvt = VT_I4;
5490     }
5491     if (!found) {
5492         FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
5493         return E_FAIL;
5494     }
5495     rc = VariantChangeType(&lv, left, 0, resvt);
5496     if (FAILED(rc)) {
5497         FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
5498         return rc;
5499     }
5500     rc = VariantChangeType(&rv, right, 0, resvt);
5501     if (FAILED(rc)) {
5502         FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
5503         return rc;
5504     }
5505     switch (resvt) {
5506     case VT_R8:
5507         V_VT(result) = resvt;
5508         V_R8(result) = V_R8(&lv) / V_R8(&rv);
5509         rc = S_OK;
5510         break;
5511     case VT_I4:
5512         V_VT(result) = resvt;
5513         V_I4(result) = V_I4(&lv) / V_I4(&rv);
5514         rc = S_OK;
5515         break;
5516     }
5517     TRACE("rc=%d, Result:\n", (int) rc);
5518     dump_Variant(result);
5519     return rc;
5520 }
5521
5522 /**********************************************************************
5523  *              VarSub [OLEAUT32.159]
5524  *
5525  */
5526 HRESULT WINAPI VarSub(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5527 {
5528     HRESULT rc = E_FAIL;
5529     VARTYPE lvt,rvt,resvt;
5530     VARIANT lv,rv;
5531     BOOL found;
5532
5533     TRACE("left: ");dump_Variant(left);
5534     TRACE("right: ");dump_Variant(right);
5535
5536     VariantInit(&lv);VariantInit(&rv);
5537     lvt = V_VT(left)&VT_TYPEMASK;
5538     rvt = V_VT(right)&VT_TYPEMASK;
5539     found = FALSE;resvt = VT_VOID;
5540     if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
5541         found = TRUE;
5542         resvt = VT_R8;
5543     }
5544     if (!found && (((1<<lvt) | (1<<rvt)) & ((1<<VT_I1)|(1<<VT_I2)|(1<<VT_UI1)|(1<<VT_UI2)|(1<<VT_I4)|(1<<VT_UI4)|(1<<VT_INT)|(1<<VT_UINT)))) {
5545         found = TRUE;
5546         resvt = VT_I4;
5547     }
5548     if (!found) {
5549         FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
5550         return E_FAIL;
5551     }
5552     rc = VariantChangeType(&lv, left, 0, resvt);
5553     if (FAILED(rc)) {
5554         FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
5555         return rc;
5556     }
5557     rc = VariantChangeType(&rv, right, 0, resvt);
5558     if (FAILED(rc)) {
5559         FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
5560         return rc;
5561     }
5562     switch (resvt) {
5563     case VT_R8:
5564         V_VT(result) = resvt;
5565         V_R8(result) = V_R8(&lv) - V_R8(&rv);
5566         rc = S_OK;
5567         break;
5568     case VT_I4:
5569         V_VT(result) = resvt;
5570         V_I4(result) = V_I4(&lv) - V_I4(&rv);
5571         rc = S_OK;
5572         break;
5573     }
5574     TRACE("rc=%d, Result:\n", (int) rc);
5575     dump_Variant(result);
5576     return rc;
5577 }
5578
5579 /**********************************************************************
5580  *              VarOr [OLEAUT32.157]
5581  *
5582  */
5583 HRESULT WINAPI VarOr(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5584 {
5585     HRESULT rc = E_FAIL;
5586
5587     TRACE("Left Var:\n");
5588     dump_Variant(left);
5589     TRACE("Right Var:\n");
5590     dump_Variant(right);
5591
5592     if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5593         (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5594
5595         V_VT(result) = VT_BOOL;
5596         if (V_BOOL(left) || V_BOOL(right)) {
5597             V_BOOL(result) = VARIANT_TRUE;
5598         } else {
5599             V_BOOL(result) = VARIANT_FALSE;
5600         }
5601         rc = S_OK;
5602
5603     } else {
5604         /* Integers */
5605         BOOL         lOk        = TRUE;
5606         BOOL         rOk        = TRUE;
5607         LONGLONG     lVal = -1;
5608         LONGLONG     rVal = -1;
5609         LONGLONG     res  = -1;
5610         int          resT = 0; /* Testing has shown I2 & I2 == I2, all else 
5611                                   becomes I4, even unsigned ints (incl. UI2) */
5612
5613         lOk = TRUE;
5614         switch (V_VT(left)&VT_TYPEMASK) {
5615         case VT_I1   : lVal = V_UNION(left,cVal);  resT=VT_I4; break;
5616         case VT_I2   : lVal = V_UNION(left,iVal);  resT=VT_I2; break;
5617         case VT_I4   : lVal = V_UNION(left,lVal);  resT=VT_I4; break;
5618         case VT_INT  : lVal = V_UNION(left,lVal);  resT=VT_I4; break;
5619         case VT_UI1  : lVal = V_UNION(left,bVal);  resT=VT_I4; break;
5620         case VT_UI2  : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5621         case VT_UI4  : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5622         case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5623         default: lOk = FALSE;
5624         }
5625
5626         rOk = TRUE;
5627         switch (V_VT(right)&VT_TYPEMASK) {
5628         case VT_I1   : rVal = V_UNION(right,cVal);  resT=VT_I4; break;
5629         case VT_I2   : rVal = V_UNION(right,iVal);  resT=max(VT_I2, resT); break;
5630         case VT_I4   : rVal = V_UNION(right,lVal);  resT=VT_I4; break;
5631         case VT_INT  : rVal = V_UNION(right,lVal);  resT=VT_I4; break;
5632         case VT_UI1  : rVal = V_UNION(right,bVal);  resT=VT_I4; break;
5633         case VT_UI2  : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5634         case VT_UI4  : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5635         case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5636         default: rOk = FALSE;
5637         }
5638
5639         if (lOk && rOk) {
5640             res = (lVal | rVal);
5641             V_VT(result) = resT;
5642             switch (resT) {
5643             case VT_I2   : V_UNION(result,iVal)  = res; break;
5644             case VT_I4   : V_UNION(result,lVal)  = res; break;
5645             default:
5646                 FIXME("Unexpected result variant type %x\n", resT);
5647                 V_UNION(result,lVal)  = res;
5648             }
5649             rc = S_OK;
5650
5651         } else {
5652             FIXME("unimplemented part\n");
5653         }
5654     }
5655
5656     TRACE("rc=%d, Result:\n", (int) rc);
5657     dump_Variant(result);
5658     return rc;
5659 }
5660
5661 /**********************************************************************
5662  *              VarNot [OLEAUT32.174]
5663  *
5664  */
5665 HRESULT WINAPI VarNot(LPVARIANT in, LPVARIANT result)
5666 {
5667     HRESULT rc = E_FAIL;
5668
5669     TRACE("Var In:\n");
5670     dump_Variant(in);
5671
5672     if ((V_VT(in)&VT_TYPEMASK) == VT_BOOL) {
5673
5674         V_VT(result) = VT_BOOL;
5675         if (V_BOOL(in)) {
5676             V_BOOL(result) = VARIANT_FALSE;
5677         } else {
5678             V_BOOL(result) = VARIANT_TRUE;
5679         }
5680         rc = S_OK;
5681
5682     } else {
5683         FIXME("VarNot stub\n");
5684     }
5685
5686     TRACE("rc=%d, Result:\n", (int) rc);
5687     dump_Variant(result);
5688     return rc;
5689 }
5690
5691 /**********************************************************************
5692  *              VarTokenizeFormatString [OLEAUT32.140]
5693  *
5694  * From investigation on W2K, a list is built up which is:
5695  *
5696  * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
5697  * <token> - Insert appropriate token
5698  *
5699  */
5700 HRESULT WINAPI VarTokenizeFormatString(LPOLESTR  format, LPBYTE rgbTok,
5701                      int   cbTok, int iFirstDay, int iFirstWeek,
5702                      LCID  lcid, int *pcbActual) {
5703
5704     FORMATHDR *hdr;
5705     int        realLen, formatLeft;
5706     BYTE      *pData;
5707     LPSTR      pFormatA, pStart;
5708     int        checkStr;
5709     BOOL       insertCopy = FALSE;
5710     LPSTR      copyFrom = NULL;
5711
5712     TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format), rgbTok, cbTok,
5713                    iFirstDay, iFirstWeek);
5714
5715     /* Big enough for header? */
5716     if (cbTok < sizeof(FORMATHDR)) {
5717         return TYPE_E_BUFFERTOOSMALL;
5718     }
5719
5720     /* Insert header */
5721     hdr = (FORMATHDR *) rgbTok;
5722     memset(hdr, 0x00, sizeof(FORMATHDR));
5723     hdr->hex3 = 0x03; /* No idea what these are */
5724     hdr->hex6 = 0x06;
5725
5726     /* Start parsing string */
5727     realLen    = sizeof(FORMATHDR);
5728     pData      = rgbTok + realLen;
5729     pFormatA   = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5730     pStart     = pFormatA;
5731     formatLeft = strlen(pFormatA);
5732
5733     /* Work through the format */
5734     while (*pFormatA != 0x00) {
5735
5736         checkStr = 0;
5737         while (checkStr>=0 && (formatTokens[checkStr].tokenSize != 0x00)) {
5738             if (formatLeft >= formatTokens[checkStr].tokenSize &&
5739                 strncmp(formatTokens[checkStr].str, pFormatA,
5740                         formatTokens[checkStr].tokenSize) == 0) {
5741                 TRACE("match on '%s'\n", formatTokens[checkStr].str);
5742
5743                 /* Found Match! */
5744
5745                 /* If we have skipped chars, insert the copy */
5746                 if (insertCopy == TRUE) {
5747
5748                     if ((realLen + 3) > cbTok) {
5749                         HeapFree( GetProcessHeap(), 0, pFormatA );
5750                         return TYPE_E_BUFFERTOOSMALL;
5751                     }
5752                     insertCopy = FALSE;
5753                     *pData = TOK_COPY;
5754                     pData++;
5755                     *pData = (BYTE)(copyFrom - pStart);
5756                     pData++;
5757                     *pData = (BYTE)(pFormatA - copyFrom);
5758                     pData++;
5759                     realLen = realLen + 3;
5760                 }
5761
5762
5763                 /* Now insert the token itself */
5764                 if ((realLen + 1) > cbTok) {
5765                     HeapFree( GetProcessHeap(), 0, pFormatA );
5766                     return TYPE_E_BUFFERTOOSMALL;
5767                 }
5768                 *pData = formatTokens[checkStr].tokenId;
5769                 pData = pData + 1;
5770                 realLen = realLen + 1;
5771
5772                 pFormatA = pFormatA + formatTokens[checkStr].tokenSize;
5773                 formatLeft = formatLeft - formatTokens[checkStr].tokenSize;
5774                 checkStr = -1; /* Flag as found and break out of while loop */
5775             } else {
5776                 checkStr++;
5777             }
5778         }
5779
5780         /* Did we ever match a token? */
5781         if (checkStr != -1 && insertCopy == FALSE) {
5782             TRACE("No match - need to insert copy from %p [%p]\n", pFormatA, pStart);
5783             insertCopy = TRUE;
5784             copyFrom   = pFormatA;
5785         } else if (checkStr != -1) {
5786             pFormatA = pFormatA + 1;
5787         }
5788
5789     }
5790
5791     /* Finally, if we have skipped chars, insert the copy */
5792     if (insertCopy == TRUE) {
5793
5794         TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom, pStart, pFormatA);
5795         if ((realLen + 3) > cbTok) {
5796             HeapFree( GetProcessHeap(), 0, pFormatA );
5797             return TYPE_E_BUFFERTOOSMALL;
5798         }
5799         insertCopy = FALSE;
5800         *pData = TOK_COPY;
5801         pData++;
5802         *pData = (BYTE)(copyFrom - pStart);
5803         pData++;
5804         *pData = (BYTE)(pFormatA - copyFrom);
5805         pData++;
5806         realLen = realLen + 3;
5807     }
5808
5809     /* Finally insert the terminator */
5810     if ((realLen + 1) > cbTok) {
5811         HeapFree( GetProcessHeap(), 0, pFormatA );
5812         return TYPE_E_BUFFERTOOSMALL;
5813     }
5814     *pData++ = TOK_END;
5815     realLen = realLen + 1;
5816
5817     /* Finally fill in the length */
5818     hdr->len = realLen;
5819     *pcbActual = realLen;
5820
5821 #if 0
5822     { int i,j;
5823       for (i=0; i<realLen; i=i+0x10) {
5824           printf(" %4.4x : ", i);
5825           for (j=0; j<0x10 && (i+j < realLen); j++) {
5826               printf("%2.2x ", rgbTok[i+j]);
5827           }
5828           printf("\n");
5829       }
5830     }
5831 #endif
5832     HeapFree( GetProcessHeap(), 0, pFormatA );
5833
5834     return S_OK;
5835 }
5836
5837 /**********************************************************************
5838  *              VarFormatFromTokens [OLEAUT32.139]
5839  * FIXME: No account of flags or iFirstDay etc
5840  */
5841 HRESULT WINAPI VarFormatFromTokens(LPVARIANT varIn, LPOLESTR format,
5842                             LPBYTE pbTokCur, ULONG dwFlags, BSTR *pbstrOut,
5843                             LCID  lcid) {
5844
5845     FORMATHDR   *hdr = (FORMATHDR *)pbTokCur;
5846     BYTE        *pData    = pbTokCur + sizeof (FORMATHDR);
5847     LPSTR        pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5848     char         output[BUFFER_MAX];
5849     char        *pNextPos;
5850     int          size, whichToken;
5851     VARIANTARG   Variant;
5852     struct tm    TM;
5853
5854
5855
5856     TRACE("'%s', %p %lx %p only date support\n", pFormatA, pbTokCur, dwFlags, pbstrOut);
5857     TRACE("varIn:\n");
5858     dump_Variant(varIn);
5859
5860     memset(output, 0x00, BUFFER_MAX);
5861     pNextPos = output;
5862
5863     while (*pData != TOK_END && ((pData - pbTokCur) <= (hdr->len))) {
5864
5865         TRACE("Output looks like : '%s'\n", output);
5866
5867         /* Convert varient to appropriate data type */
5868         whichToken = 0;
5869         while ((formatTokens[whichToken].tokenSize != 0x00) &&
5870                (formatTokens[whichToken].tokenId   != *pData)) {
5871             whichToken++;
5872         }
5873
5874         /* Use Variant local from here downwards as always correct type */
5875         if (formatTokens[whichToken].tokenSize > 0 &&
5876             formatTokens[whichToken].varTypeRequired != 0) {
5877                         VariantInit( &Variant );
5878             if (Coerce( &Variant, lcid, dwFlags, varIn,
5879                         formatTokens[whichToken].varTypeRequired ) != S_OK) {
5880                 HeapFree( GetProcessHeap(), 0, pFormatA );
5881                 return DISP_E_TYPEMISMATCH;
5882             } else if (formatTokens[whichToken].varTypeRequired == VT_DATE) {
5883                 if( DateToTm( V_UNION(&Variant,date), dwFlags, &TM ) == FALSE ) {
5884                     HeapFree( GetProcessHeap(), 0, pFormatA );
5885                     return E_INVALIDARG;
5886                 }
5887             }
5888         }
5889
5890         TRACE("Looking for match on token '%x'\n", *pData);
5891         switch (*pData) {
5892         case TOK_COPY:
5893             TRACE("Copy from %d for %d bytes\n", *(pData+1), *(pData+2));
5894             memcpy(pNextPos, &pFormatA[*(pData+1)], *(pData+2));
5895             pNextPos = pNextPos + *(pData+2);
5896             pData = pData + 3;
5897             break;
5898
5899         case TOK_COLON   :
5900             /* Get locale information - Time Seperator */
5901             size = GetLocaleInfoA(lcid, LOCALE_STIME, NULL, 0);
5902             GetLocaleInfoA(lcid, LOCALE_STIME, pNextPos, size);
5903             TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5904             pNextPos = pNextPos + size;
5905             pData = pData + 1;
5906             break;
5907
5908         case TOK_SLASH   :
5909             /* Get locale information - Date Seperator */
5910             size = GetLocaleInfoA(lcid, LOCALE_SDATE, NULL, 0);
5911             GetLocaleInfoA(lcid, LOCALE_SDATE, pNextPos, size);
5912             TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5913             pNextPos = pNextPos + size;
5914             pData = pData + 1;
5915             break;
5916
5917         case TOK_d       :
5918             sprintf(pNextPos, "%d", TM.tm_mday);
5919             pNextPos = pNextPos + strlen(pNextPos);
5920             pData = pData + 1;
5921             break;
5922
5923         case TOK_dd      :
5924             sprintf(pNextPos, "%2.2d", TM.tm_mday);
5925             pNextPos = pNextPos + strlen(pNextPos);
5926             pData = pData + 1;
5927             break;
5928
5929         case TOK_w       :
5930             sprintf(pNextPos, "%d", TM.tm_wday+1);
5931             pNextPos = pNextPos + strlen(pNextPos);
5932             pData = pData + 1;
5933             break;
5934
5935         case TOK_m       :
5936             sprintf(pNextPos, "%d", TM.tm_mon+1);
5937             pNextPos = pNextPos + strlen(pNextPos);
5938             pData = pData + 1;
5939             break;
5940
5941         case TOK_mm      :
5942             sprintf(pNextPos, "%2.2d", TM.tm_mon+1);
5943             pNextPos = pNextPos + strlen(pNextPos);
5944             pData = pData + 1;
5945             break;
5946
5947         case TOK_q       :
5948             sprintf(pNextPos, "%d", ((TM.tm_mon+1)/4)+1);
5949             pNextPos = pNextPos + strlen(pNextPos);
5950             pData = pData + 1;
5951             break;
5952
5953         case TOK_y       :
5954             sprintf(pNextPos, "%2.2d", TM.tm_yday+1);
5955             pNextPos = pNextPos + strlen(pNextPos);
5956             pData = pData + 1;
5957             break;
5958
5959         case TOK_yy      :
5960             sprintf(pNextPos, "%2.2d", TM.tm_year);
5961             pNextPos = pNextPos + strlen(pNextPos);
5962             pData = pData + 1;
5963             break;
5964
5965         case TOK_yyyy    :
5966             sprintf(pNextPos, "%4.4d", TM.tm_year);
5967             pNextPos = pNextPos + strlen(pNextPos);
5968             pData = pData + 1;
5969             break;
5970
5971         case TOK_h       :
5972             sprintf(pNextPos, "%d", TM.tm_hour);
5973             pNextPos = pNextPos + strlen(pNextPos);
5974             pData = pData + 1;
5975             break;
5976
5977         case TOK_Hh      :
5978             sprintf(pNextPos, "%2.2d", TM.tm_hour);
5979             pNextPos = pNextPos + strlen(pNextPos);
5980             pData = pData + 1;
5981             break;
5982
5983         case TOK_N       :
5984             sprintf(pNextPos, "%d", TM.tm_min);
5985             pNextPos = pNextPos + strlen(pNextPos);
5986             pData = pData + 1;
5987             break;
5988
5989         case TOK_Nn      :
5990             sprintf(pNextPos, "%2.2d", TM.tm_min);
5991             pNextPos = pNextPos + strlen(pNextPos);
5992             pData = pData + 1;
5993             break;
5994
5995         case TOK_S       :
5996             sprintf(pNextPos, "%d", TM.tm_sec);
5997             pNextPos = pNextPos + strlen(pNextPos);
5998             pData = pData + 1;
5999             break;
6000
6001         case TOK_Ss      :
6002             sprintf(pNextPos, "%2.2d", TM.tm_sec);
6003             pNextPos = pNextPos + strlen(pNextPos);
6004             pData = pData + 1;
6005             break;
6006
6007         /* FIXME: To Do! */
6008         case TOK_ttttt   :
6009         case TOK_AMsPM   :
6010         case TOK_amspm   :
6011         case TOK_AsP     :
6012         case TOK_asp     :
6013         case TOK_AMPM    :
6014         case TOK_c       :
6015         case TOK_ddd     :
6016         case TOK_dddd    :
6017         case TOK_ddddd   :
6018         case TOK_dddddd  :
6019         case TOK_ww      :
6020         case TOK_mmm     :
6021         case TOK_mmmm    :
6022         default:
6023             FIXME("Unhandled token for VarFormat %d\n", *pData);
6024             HeapFree( GetProcessHeap(), 0, pFormatA );
6025             return E_INVALIDARG;
6026         }
6027
6028     }
6029
6030     *pbstrOut = StringDupAtoBstr( output );
6031     HeapFree( GetProcessHeap(), 0, pFormatA );
6032     return S_OK;
6033 }
6034
6035 /**********************************************************************
6036  *              VarFormat [OLEAUT32.87]
6037  *
6038  */
6039 HRESULT WINAPI VarFormat(LPVARIANT varIn, LPOLESTR format,
6040                          int firstDay, int firstWeek, ULONG dwFlags,
6041                          BSTR *pbstrOut) {
6042
6043     LPSTR   pNewString = NULL;
6044     HRESULT rc = S_OK;
6045
6046     TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
6047           debugstr_w(format), firstDay, firstWeek, dwFlags);
6048     TRACE("varIn:\n");
6049     dump_Variant(varIn);
6050
6051     /* Note: Must Handle references type Variants (contain ptrs
6052           to values rather than values */
6053
6054     /* Get format string */
6055     pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
6056
6057     /* FIXME: Handle some simple pre-definted format strings : */
6058     if (((V_VT(varIn)&VT_TYPEMASK) == VT_CY) && (lstrcmpiA(pNewString, "Currency") == 0)) {
6059
6060         /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
6061         double curVal;
6062
6063
6064         /* Handle references type Variants (contain ptrs to values rather than values */
6065         if (V_VT(varIn)&VT_BYREF) {
6066             rc = VarR8FromCy(*(CY *)V_UNION(varIn,byref), &curVal);
6067         } else {
6068             rc = VarR8FromCy(V_UNION(varIn,cyVal), &curVal);
6069         }
6070
6071         if (rc == S_OK) {
6072             char tmpStr[BUFFER_MAX];
6073             sprintf(tmpStr, "%f", curVal);
6074             if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags, tmpStr, NULL, pBuffer, BUFFER_MAX) == 0) {
6075                 return E_FAIL;
6076             } else {
6077                 *pbstrOut = StringDupAtoBstr( pBuffer );
6078             }
6079         }
6080
6081     } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_DATE) {
6082
6083         /* Attempt to do proper formatting! */
6084         int firstToken = -1;
6085
6086         rc = VarTokenizeFormatString(format, pBuffer, sizeof(pBuffer), firstDay,
6087                                   firstWeek, GetUserDefaultLCID(), &firstToken);
6088         if (rc==S_OK) {
6089             rc = VarFormatFromTokens(varIn, format, pBuffer, dwFlags, pbstrOut, GetUserDefaultLCID());
6090         }
6091
6092     } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_R8) {
6093         if (V_VT(varIn)&VT_BYREF) {
6094             sprintf(pBuffer, "%f", *V_UNION(varIn,pdblVal));
6095         } else {
6096             sprintf(pBuffer, "%f", V_UNION(varIn,dblVal));
6097         }
6098         *pbstrOut = StringDupAtoBstr( pBuffer );
6099     } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_I2) {
6100         if (V_VT(varIn)&VT_BYREF) {
6101             sprintf(pBuffer, "%d", *V_UNION(varIn,piVal));
6102         } else {
6103             sprintf(pBuffer, "%d", V_UNION(varIn,iVal));
6104         }
6105         *pbstrOut = StringDupAtoBstr( pBuffer );
6106     } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_BSTR) {
6107         if (V_VT(varIn)&VT_BYREF)
6108             *pbstrOut = SysAllocString( *V_UNION(varIn,pbstrVal) );
6109         else
6110             *pbstrOut = SysAllocString( V_UNION(varIn,bstrVal) );
6111     } else {
6112         FIXME("VarFormat: Unsupported format %d!\n", V_VT(varIn)&VT_TYPEMASK);
6113         *pbstrOut = StringDupAtoBstr( "??" );
6114     }
6115
6116     /* Free allocated storage */
6117     HeapFree( GetProcessHeap(), 0, pNewString );
6118     TRACE("result: '%s'\n", debugstr_w(*pbstrOut));
6119     return rc;
6120 }
6121
6122 /**********************************************************************
6123  *              VarCyMulI4 [OLEAUT32.304]
6124  * Multiply currency value by integer
6125  */
6126 HRESULT WINAPI VarCyMulI4(CY cyIn, LONG mulBy, CY *pcyOut) {
6127
6128     double cyVal = 0;
6129     HRESULT rc = S_OK;
6130
6131     rc = VarR8FromCy(cyIn, &cyVal);
6132     if (rc == S_OK) {
6133         rc = VarCyFromR8((cyVal * (double) mulBy), pcyOut);
6134         TRACE("Multiply %f by %ld = %f [%ld,%lu]\n", cyVal, mulBy, (cyVal * (double) mulBy),
6135                     pcyOut->s.Hi, pcyOut->s.Lo);
6136     }
6137     return rc;
6138 }