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