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