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