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