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