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