Small spelling/punctuation fixes.
[wine/wine64.git] / dlls / oleaut32 / variant.c
blob4b22ee5ebbae5fe87aa72502db23c390e026edeb
1 /*
2 * VARIANT
4 * Copyright 1998 Jean-Claude Cote
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.
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.
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
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.
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.
37 #include "config.h"
39 #include <string.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <math.h>
43 #include <time.h>
45 #ifdef HAVE_FLOAT_H
46 # include <float.h>
47 #endif
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"
60 WINE_DEFAULT_DEBUG_CHANNEL(ole);
62 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
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
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;
89 /* the largest valid type
91 #define VT_MAXVALIDTYPE VT_CLSID
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.
97 #define PROCESSING_INNER_VARIANT 0x0001
99 /* General use buffer.
101 #define BUFFER_MAX 1024
102 static char pBuffer[BUFFER_MAX];
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.
111 * Use 365 days/year and a manual calculation for leap year days
112 * to keep arithmetic simple
114 static const double DAYS_IN_ONE_YEAR = 365.0;
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
122 /* Pre defined tokens */
123 #define TOK_COPY 0x00
124 #define TOK_END 0x02
125 #define LARGEST_TOKENID 6
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
161 typedef struct tagFORMATTOKEN {
162 char *str;
163 BYTE tokenSize;
164 BYTE tokenId;
165 int varTypeRequired;
166 } FORMATTOKEN;
168 typedef struct tagFORMATHDR {
169 BYTE len;
170 BYTE hex3;
171 BYTE hex6;
172 BYTE reserved[8];
173 } FORMATHDR;
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}
210 /******************************************************************************
211 * DateTimeStringToTm [INTERNAL]
213 * Converts a string representation of a date and/or time to a tm structure.
215 * Note this function uses the postgresql date parsing functions found
216 * in the parsedt.c file.
218 * Returns TRUE if successful.
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.
224 ******************************************************************************/
225 static BOOL DateTimeStringToTm( OLECHAR* strIn, DWORD dwFlags, struct tm* pTm )
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;
237 /* Convert the string to ASCII since this is the only format
238 * postgesql can handle.
240 strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
242 if( strDateTime != NULL )
244 /* Make sure we don't go over the maximum length
245 * accepted by postgesql.
247 if( strlen( strDateTime ) <= MAXDATELEN )
249 if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
251 if( dwFlags & VAR_DATEVALUEONLY )
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.
258 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
260 /* Eliminate the time information since we
261 * were asked to get date information only.
263 pTm->tm_sec = 0;
264 pTm->tm_min = 0;
265 pTm->tm_hour = 0;
266 res = TRUE;
269 if( dwFlags & VAR_TIMEVALUEONLY )
271 /* Get time information only.
273 if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
275 res = TRUE;
278 else
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.
285 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
287 res = TRUE;
292 HeapFree( GetProcessHeap(), 0, strDateTime );
295 return res;
303 /******************************************************************************
304 * TmToDATE [INTERNAL]
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 * };
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.
336 * Returns TRUE if successful.
338 static BOOL TmToDATE( struct tm* pTm, DATE *pDateOut )
340 int leapYear = 0;
342 /* Hmmm... An uninitialized Date in VB is December 30 1899 so
343 Start at 0. This is the way DATE is defined. */
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.
350 *pDateOut = 1;
352 if( (pTm->tm_year - 1900) >= 0 ) {
354 /* Add the number of days corresponding to
355 * tm_year.
357 *pDateOut += (pTm->tm_year - 1900) * 365;
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
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 );
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.
374 if( isleap( pTm->tm_year ) )
375 leapYear = 1;
377 /* Add the number of days corresponding to
378 * the month. (remember tm_mon is 0..11)
380 switch( pTm->tm_mon )
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;
416 /* Add the number of days in this month.
418 *pDateOut += pTm->tm_mday;
420 /* Add the number of seconds, minutes, and hours
421 * to the DATE. Note these are the fractional part
422 * of the DATE so seconds / number of seconds in a day.
424 } else {
425 *pDateOut = 0;
428 *pDateOut += pTm->tm_hour / 24.0;
429 *pDateOut += pTm->tm_min / 1440.0;
430 *pDateOut += pTm->tm_sec / 86400.0;
431 return TRUE;
434 /******************************************************************************
435 * DateToTm [INTERNAL]
437 * This function converts a windows DATE to a tm structure.
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.
443 * Note this function does not support dates before the January 1, 1900
444 * or ( dateIn < 2.0 ).
446 * Returns TRUE if successful.
448 BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )
450 double decimalPart = 0.0;
451 double wholePart = 0.0;
453 memset(pTm,0,sizeof(*pTm));
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.
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 );
466 if( !(dwFlags & VAR_TIMEVALUEONLY) )
468 unsigned int nDay = 0;
469 int leapYear = 0;
470 double yearsSince1900 = 0;
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;
484 } else {
486 /* Start at 1900, this is where the DATE time 0.0 starts.
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.
492 yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 );
493 pTm->tm_year += yearsSince1900;
494 /* determine if this is a leap year.
496 if( isleap( pTm->tm_year ) )
498 leapYear = 1;
499 wholePart++;
502 /* find what day of that year the "wholePart" corresponds to.
503 * Note: nDay is in [1-366] format
505 nDay = (((unsigned int) wholePart) - ((pTm->tm_year-1900) * DAYS_IN_ONE_YEAR ));
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
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 );
517 /* Set the tm_yday value.
518 * Note: The day must be converted from [1-366] to [0-365]
520 /*pTm->tm_yday = nDay - 1;*/
521 /* find which month this day corresponds to.
523 if( nDay <= 31 )
525 pTm->tm_mday = nDay;
526 pTm->tm_mon = 0;
528 else if( nDay <= ( 59 + leapYear ) )
530 pTm->tm_mday = nDay - 31;
531 pTm->tm_mon = 1;
533 else if( nDay <= ( 90 + leapYear ) )
535 pTm->tm_mday = nDay - ( 59 + leapYear );
536 pTm->tm_mon = 2;
538 else if( nDay <= ( 120 + leapYear ) )
540 pTm->tm_mday = nDay - ( 90 + leapYear );
541 pTm->tm_mon = 3;
543 else if( nDay <= ( 151 + leapYear ) )
545 pTm->tm_mday = nDay - ( 120 + leapYear );
546 pTm->tm_mon = 4;
548 else if( nDay <= ( 181 + leapYear ) )
550 pTm->tm_mday = nDay - ( 151 + leapYear );
551 pTm->tm_mon = 5;
553 else if( nDay <= ( 212 + leapYear ) )
555 pTm->tm_mday = nDay - ( 181 + leapYear );
556 pTm->tm_mon = 6;
558 else if( nDay <= ( 243 + leapYear ) )
560 pTm->tm_mday = nDay - ( 212 + leapYear );
561 pTm->tm_mon = 7;
563 else if( nDay <= ( 273 + leapYear ) )
565 pTm->tm_mday = nDay - ( 243 + leapYear );
566 pTm->tm_mon = 8;
568 else if( nDay <= ( 304 + leapYear ) )
570 pTm->tm_mday = nDay - ( 273 + leapYear );
571 pTm->tm_mon = 9;
573 else if( nDay <= ( 334 + leapYear ) )
575 pTm->tm_mday = nDay - ( 304 + leapYear );
576 pTm->tm_mon = 10;
578 else if( nDay <= ( 365 + leapYear ) )
580 pTm->tm_mday = nDay - ( 334 + leapYear );
581 pTm->tm_mon = 11;
585 if( !(dwFlags & VAR_DATEVALUEONLY) )
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
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);
598 return TRUE;
603 /******************************************************************************
604 * SizeOfVariantData [INTERNAL]
606 * This function finds the size of the data referenced by a Variant based
607 * the type "vt" of the Variant.
609 static int SizeOfVariantData( VARIANT* parg )
611 int size = 0;
612 switch( V_VT(parg) & VT_TYPEMASK )
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;
661 return size;
663 /******************************************************************************
664 * StringDupAtoBstr [INTERNAL]
667 static BSTR StringDupAtoBstr( char* strIn )
669 BSTR bstr = NULL;
670 OLECHAR* pNewString = NULL;
671 UNICODE_STRING usBuffer;
673 RtlCreateUnicodeStringFromAsciiz( &usBuffer, strIn );
674 pNewString = usBuffer.Buffer;
676 bstr = SysAllocString( pNewString );
677 RtlFreeUnicodeString( &usBuffer );
678 return bstr;
681 /******************************************************************************
682 * round [INTERNAL]
684 * Round the double value to the nearest integer value.
686 static double round( double d )
688 double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
689 BOOL bEvenNumber = FALSE;
690 int nSign = 0;
692 /* Save the sign of the number
694 nSign = (d >= 0.0) ? 1 : -1;
695 d = fabs( d );
697 /* Remove the decimals.
699 integerValue = floor( d );
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.
707 bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
709 /* Remove the integral part of the number.
711 decimals = d - integerValue;
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.
716 if( decimals > 0.5 )
718 /* If the decimal part is greater than 1/2
720 roundedValue = ceil( d );
722 else if( decimals < 0.5 )
724 /* If the decimal part is smaller than 1/2
726 roundedValue = floor( d );
728 else
730 /* the decimals are exactly 1/2 so round according to
731 * the bEvenNumber flag.
733 if( bEvenNumber )
735 roundedValue = floor( d );
737 else
739 roundedValue = ceil( d );
743 return roundedValue * nSign;
746 /******************************************************************************
747 * RemoveCharacterFromString [INTERNAL]
749 * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
751 static void RemoveCharacterFromString( LPSTR str, LPSTR strOfCharToRemove )
753 LPSTR pNewString = NULL;
754 LPSTR strToken = NULL;
756 /* Check if we have a valid argument
758 if( str != NULL )
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 );
767 free( pNewString );
769 return;
772 /******************************************************************************
773 * GetValidRealString [INTERNAL]
775 * Checks if the string is of proper format to be converted to a real value.
777 static BOOL IsValidRealString( LPSTR strRealString )
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.
784 BOOL bDigitsRequired = TRUE;
785 /* Processed fields in the string representation of the real number.
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.
797 BOOL bValidRealString = TRUE;
799 /* Used to count the number of tokens in the "strRealString".
801 LPSTR strToken = NULL;
802 int nTokens = 0;
803 LPSTR pChar = NULL;
805 /* Check if we have a valid argument
807 if( strRealString == NULL )
809 bValidRealString = FALSE;
812 if( bValidRealString == TRUE )
814 /* Make sure we only have ONE token in the string.
816 strToken = strtok( strRealString, " " );
817 while( strToken != NULL ) {
818 nTokens++;
819 strToken = strtok( NULL, " " );
822 if( nTokens != 1 )
824 bValidRealString = FALSE;
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.
841 pChar = strRealString;
842 while( bValidRealString == TRUE && *pChar != '\0' )
844 switch( *pChar )
846 /* If whitespace...
848 case ' ':
849 case '\t':
850 if( bWhiteSpaceProcessed ||
851 bFirstSignProcessed ||
852 bFirstDigitsProcessed ||
853 bDecimalPointProcessed ||
854 bSecondDigitsProcessed ||
855 bExponentProcessed ||
856 bSecondSignProcessed ||
857 bThirdDigitsProcessed )
859 bValidRealString = FALSE;
861 break;
862 /* If sign...
864 case '+':
865 case '-':
866 if( bFirstSignProcessed == FALSE )
868 if( bFirstDigitsProcessed ||
869 bDecimalPointProcessed ||
870 bSecondDigitsProcessed ||
871 bExponentProcessed ||
872 bSecondSignProcessed ||
873 bThirdDigitsProcessed )
875 bValidRealString = FALSE;
877 bWhiteSpaceProcessed = TRUE;
878 bFirstSignProcessed = TRUE;
880 else if( bSecondSignProcessed == FALSE )
882 /* Note: The exponent must be present in
883 * order to accept the second sign...
885 if( bExponentProcessed == FALSE ||
886 bThirdDigitsProcessed ||
887 bDigitsRequired )
889 bValidRealString = FALSE;
891 bFirstSignProcessed = TRUE;
892 bWhiteSpaceProcessed = TRUE;
893 bFirstDigitsProcessed = TRUE;
894 bDecimalPointProcessed = TRUE;
895 bSecondDigitsProcessed = TRUE;
896 bSecondSignProcessed = TRUE;
898 break;
900 /* If decimals...
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 )
914 if( bDecimalPointProcessed ||
915 bSecondDigitsProcessed ||
916 bExponentProcessed ||
917 bSecondSignProcessed ||
918 bThirdDigitsProcessed )
920 bValidRealString = FALSE;
922 bFirstSignProcessed = TRUE;
923 bWhiteSpaceProcessed = TRUE;
924 /* We have found some digits before the decimal point
925 * so disable the "Digits required" flag.
927 bDigitsRequired = FALSE;
929 else if( bSecondDigitsProcessed == FALSE )
931 if( bExponentProcessed ||
932 bSecondSignProcessed ||
933 bThirdDigitsProcessed )
935 bValidRealString = FALSE;
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.
944 bDigitsRequired = FALSE;
946 else if( bThirdDigitsProcessed == FALSE )
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.
954 break;
955 /* If DecimalPoint...
957 case '.':
958 if( bDecimalPointProcessed ||
959 bSecondDigitsProcessed ||
960 bExponentProcessed ||
961 bSecondSignProcessed ||
962 bThirdDigitsProcessed )
964 bValidRealString = FALSE;
966 bFirstSignProcessed = TRUE;
967 bWhiteSpaceProcessed = TRUE;
968 bFirstDigitsProcessed = TRUE;
969 bDecimalPointProcessed = TRUE;
970 break;
971 /* If Exponent...
973 case 'e':
974 case 'E':
975 case 'd':
976 case 'D':
977 if( bExponentProcessed ||
978 bSecondSignProcessed ||
979 bThirdDigitsProcessed ||
980 bDigitsRequired )
982 bValidRealString = FALSE;
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;
995 /* Process next character.
997 pChar++;
1000 /* If the required digits were not present we have an invalid
1001 * string representation of a real number.
1003 if( bDigitsRequired == TRUE )
1005 bValidRealString = FALSE;
1008 return bValidRealString;
1012 /******************************************************************************
1013 * Coerce [INTERNAL]
1015 * This function dispatches execution to the proper conversion API
1016 * to do the necessary coercion.
1018 * FIXME: Passing down dwFlags to the conversion functions is wrong, this
1019 * is a different flagmask. Check MSDN.
1021 static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
1023 HRESULT res = S_OK;
1024 unsigned short vtFrom = 0;
1025 vtFrom = V_VT(ps) & VT_TYPEMASK;
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.
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);
1039 /* Cases requiring thought*/
1040 switch( vt )
1043 case( VT_EMPTY ):
1044 res = VariantClear( pd );
1045 break;
1046 case( VT_NULL ):
1047 res = VariantClear( pd );
1048 if( res == S_OK )
1050 V_VT(pd) = VT_NULL;
1052 break;
1053 case( VT_I1 ):
1054 switch( vtFrom )
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;
1101 break;
1103 case( VT_I2 ):
1104 switch( vtFrom )
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;
1151 break;
1153 case( VT_INT ):
1154 case( VT_I4 ):
1155 switch( vtFrom )
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) );
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;
1214 break;
1216 case( VT_UI1 ):
1217 switch( vtFrom )
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;
1267 break;
1269 case( VT_UI2 ):
1270 switch( vtFrom )
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;
1320 break;
1322 case( VT_UINT ):
1323 case( VT_UI4 ):
1324 switch( vtFrom )
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;
1373 break;
1375 case( VT_R4 ):
1376 switch( vtFrom )
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;
1430 break;
1432 case( VT_R8 ):
1433 switch( vtFrom )
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;
1483 break;
1485 case( VT_DATE ):
1486 switch( vtFrom )
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;
1537 break;
1539 case( VT_BOOL ):
1540 switch( vtFrom )
1542 case( VT_NULL ):
1543 case( VT_EMPTY ):
1544 res = S_OK;
1545 V_UNION(pd,boolVal) = VARIANT_FALSE;
1546 break;
1547 case( VT_I1 ):
1548 res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
1549 break;
1550 case( VT_I2 ):
1551 res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
1552 break;
1553 case( VT_INT ):
1554 res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
1555 break;
1556 case( VT_I4 ):
1557 res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
1558 break;
1559 case( VT_UI1 ):
1560 res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
1561 break;
1562 case( VT_UI2 ):
1563 res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
1564 break;
1565 case( VT_UINT ):
1566 res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
1567 break;
1568 case( VT_UI4 ):
1569 res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
1570 break;
1571 case( VT_R4 ):
1572 res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
1573 break;
1574 case( VT_R8 ):
1575 res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
1576 break;
1577 case( VT_DATE ):
1578 res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
1579 break;
1580 case( VT_BSTR ):
1581 res = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
1582 break;
1583 case( VT_CY ):
1584 res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
1585 break;
1586 case( VT_DISPATCH ):
1587 /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1588 case( VT_DECIMAL ):
1589 /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1590 case( VT_UNKNOWN ):
1591 default:
1592 res = DISP_E_TYPEMISMATCH;
1593 FIXME("Coercion from %d to VT_BOOL\n", vtFrom);
1594 break;
1596 break;
1598 case( VT_BSTR ):
1599 switch( vtFrom )
1601 case( VT_EMPTY ):
1602 if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
1603 res = S_OK;
1604 else
1605 res = E_OUTOFMEMORY;
1606 break;
1607 case( VT_I1 ):
1608 res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
1609 break;
1610 case( VT_I2 ):
1611 res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
1612 break;
1613 case( VT_INT ):
1614 res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
1615 break;
1616 case( VT_I4 ):
1617 res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
1618 break;
1619 case( VT_UI1 ):
1620 res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
1621 break;
1622 case( VT_UI2 ):
1623 res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
1624 break;
1625 case( VT_UINT ):
1626 res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
1627 break;
1628 case( VT_UI4 ):
1629 res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
1630 break;
1631 case( VT_R4 ):
1632 res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
1633 break;
1634 case( VT_R8 ):
1635 res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
1636 break;
1637 case( VT_DATE ):
1638 res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
1639 break;
1640 case( VT_BOOL ):
1641 res = VarBstrFromBool( V_UNION(ps,boolVal), lcid, 0, &V_UNION(pd,bstrVal) );
1642 break;
1643 case( VT_BSTR ):
1644 res = VariantCopy( pd, ps );
1645 break;
1646 case( VT_CY ):
1647 res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
1648 break;
1649 case( VT_DISPATCH ):
1650 /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1651 case( VT_DECIMAL ):
1652 /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1653 case( VT_UNKNOWN ):
1654 default:
1655 res = DISP_E_TYPEMISMATCH;
1656 FIXME("Coercion from %d to VT_BSTR\n", vtFrom);
1657 break;
1659 break;
1661 case( VT_CY ):
1662 switch( vtFrom )
1664 case( VT_I1 ):
1665 res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
1666 break;
1667 case( VT_I2 ):
1668 res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
1669 break;
1670 case( VT_INT ):
1671 res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
1672 break;
1673 case( VT_I4 ):
1674 res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
1675 break;
1676 case( VT_UI1 ):
1677 res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
1678 break;
1679 case( VT_UI2 ):
1680 res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
1681 break;
1682 case( VT_UINT ):
1683 res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
1684 break;
1685 case( VT_UI4 ):
1686 res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
1687 break;
1688 case( VT_R4 ):
1689 res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
1690 break;
1691 case( VT_R8 ):
1692 res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
1693 break;
1694 case( VT_DATE ):
1695 res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1696 break;
1697 case( VT_BOOL ):
1698 res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1699 break;
1700 case( VT_CY ):
1701 res = VariantCopy( pd, ps );
1702 break;
1703 case( VT_BSTR ):
1704 res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
1705 break;
1706 case( VT_DISPATCH ):
1707 /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1708 case( VT_DECIMAL ):
1709 /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1710 break;
1711 case( VT_UNKNOWN ):
1712 default:
1713 res = DISP_E_TYPEMISMATCH;
1714 FIXME("Coercion from %d to VT_CY\n", vtFrom);
1715 break;
1717 break;
1719 case( VT_UNKNOWN ):
1720 switch (vtFrom) {
1721 case VT_DISPATCH:
1722 if (V_DISPATCH(ps) == NULL) {
1723 V_UNKNOWN(pd) = NULL;
1724 } else {
1725 res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1727 break;
1728 case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4:
1729 case VT_R4: case VT_R8: case VT_CY: case VT_DATE:
1730 case VT_BSTR: case VT_ERROR: case VT_BOOL:
1731 case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1:
1732 case VT_UI2: case VT_UI4: case VT_I8: case VT_UI8: case VT_INT:
1733 case VT_UINT: case VT_VOID: case VT_HRESULT: case VT_PTR:
1734 case VT_SAFEARRAY: case VT_CARRAY: case VT_USERDEFINED:
1735 case VT_LPSTR: case VT_LPWSTR: case VT_RECORD: case VT_FILETIME:
1736 case VT_BLOB: case VT_STREAM: case VT_STORAGE:
1737 case VT_STREAMED_OBJECT: case VT_STORED_OBJECT: case VT_BLOB_OBJECT:
1738 case VT_CF: case VT_CLSID:
1739 res = DISP_E_TYPEMISMATCH;
1740 break;
1741 default:
1742 FIXME("Coercion from %d to VT_UNKNOWN unhandled.\n", vtFrom);
1743 res = DISP_E_BADVARTYPE;
1744 break;
1746 break;
1748 case( VT_DISPATCH ):
1749 switch (vtFrom) {
1750 case VT_UNKNOWN:
1751 if (V_UNION(ps,punkVal) == NULL) {
1752 V_UNION(pd,pdispVal) = NULL;
1753 } else {
1754 res = IUnknown_QueryInterface(V_UNION(ps,punkVal), &IID_IDispatch, (LPVOID*)&V_UNION(pd,pdispVal));
1756 break;
1757 case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4:
1758 case VT_R4: case VT_R8: case VT_CY: case VT_DATE:
1759 case VT_BSTR: case VT_ERROR: case VT_BOOL:
1760 case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1:
1761 case VT_UI2: case VT_UI4: case VT_I8: case VT_UI8: case VT_INT:
1762 case VT_UINT: case VT_VOID: case VT_HRESULT:
1763 case VT_SAFEARRAY: case VT_CARRAY: case VT_USERDEFINED:
1764 case VT_LPSTR: case VT_LPWSTR: case VT_RECORD: case VT_FILETIME:
1765 case VT_BLOB: case VT_STREAM: case VT_STORAGE:
1766 case VT_STREAMED_OBJECT: case VT_STORED_OBJECT: case VT_BLOB_OBJECT:
1767 case VT_CF: case VT_CLSID:
1768 res = DISP_E_TYPEMISMATCH;
1769 break;
1770 case VT_PTR:
1771 V_UNION(pd,pdispVal) = V_UNION(ps,pdispVal);
1772 break;
1773 default:
1774 FIXME("Coercion from %d to VT_DISPATCH unhandled.\n", vtFrom);
1775 res = DISP_E_BADVARTYPE;
1776 break;
1778 break;
1780 default:
1781 res = DISP_E_TYPEMISMATCH;
1782 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1783 break;
1786 return res;
1789 /******************************************************************************
1790 * ValidateVtRange [INTERNAL]
1792 * Used internally by the hi-level Variant API to determine
1793 * if the vartypes are valid.
1795 static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
1797 /* if by value we must make sure it is in the
1798 * range of the valid types.
1800 if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1802 return DISP_E_BADVARTYPE;
1804 return S_OK;
1808 /******************************************************************************
1809 * ValidateVartype [INTERNAL]
1811 * Used internally by the hi-level Variant API to determine
1812 * if the vartypes are valid.
1814 static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
1816 HRESULT res = S_OK;
1818 /* check if we have a valid argument.
1820 if( vt & VT_BYREF )
1822 /* if by reference check that the type is in
1823 * the valid range and that it is not of empty or null type
1825 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1826 ( vt & VT_TYPEMASK ) == VT_NULL ||
1827 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1829 res = DISP_E_BADVARTYPE;
1833 else
1835 res = ValidateVtRange( vt );
1838 return res;
1841 /******************************************************************************
1842 * ValidateVt [INTERNAL]
1844 * Used internally by the hi-level Variant API to determine
1845 * if the vartypes are valid.
1847 static HRESULT WINAPI ValidateVt( VARTYPE vt )
1849 HRESULT res = S_OK;
1851 /* check if we have a valid argument.
1853 if( vt & VT_BYREF )
1855 /* if by reference check that the type is in
1856 * the valid range and that it is not of empty or null type
1858 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1859 ( vt & VT_TYPEMASK ) == VT_NULL ||
1860 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1862 res = DISP_E_BADVARTYPE;
1866 else
1868 res = ValidateVtRange( vt );
1871 return res;
1878 /******************************************************************************
1879 * VariantInit [OLEAUT32.8]
1881 * Initializes the Variant. Unlike VariantClear it does not interpret
1882 * the current contents of the Variant.
1884 void WINAPI VariantInit(VARIANTARG* pvarg)
1886 TRACE("(%p)\n",pvarg);
1888 memset(pvarg, 0, sizeof (VARIANTARG));
1889 V_VT(pvarg) = VT_EMPTY;
1891 return;
1894 /******************************************************************************
1895 * VariantClear [OLEAUT32.9]
1897 * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1898 * sets the wReservedX field to 0. The current contents of the VARIANT are
1899 * freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1900 * released. If VT_ARRAY the array is freed.
1902 HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
1904 HRESULT res = S_OK;
1905 TRACE("(%p)\n",pvarg);
1907 res = ValidateVariantType( V_VT(pvarg) );
1908 if( res == S_OK )
1910 if( !( V_VT(pvarg) & VT_BYREF ) )
1913 * The VT_ARRAY flag is a special case of a safe array.
1915 if ( (V_VT(pvarg) & VT_ARRAY) != 0)
1917 SafeArrayDestroy(V_UNION(pvarg,parray));
1919 else
1921 switch( V_VT(pvarg) & VT_TYPEMASK )
1923 case( VT_BSTR ):
1924 SysFreeString( V_UNION(pvarg,bstrVal) );
1925 break;
1926 case( VT_DISPATCH ):
1927 if(V_UNION(pvarg,pdispVal)!=NULL)
1928 IDispatch_Release(V_UNION(pvarg,pdispVal));
1929 break;
1930 case( VT_VARIANT ):
1931 VariantClear(V_UNION(pvarg,pvarVal));
1932 break;
1933 case( VT_UNKNOWN ):
1934 if(V_UNION(pvarg,punkVal)!=NULL)
1935 IUnknown_Release(V_UNION(pvarg,punkVal));
1936 break;
1937 case( VT_SAFEARRAY ):
1938 SafeArrayDestroy(V_UNION(pvarg,parray));
1939 break;
1940 default:
1941 break;
1947 * Empty all the fields and mark the type as empty.
1949 memset(pvarg, 0, sizeof (VARIANTARG));
1950 V_VT(pvarg) = VT_EMPTY;
1953 return res;
1956 /******************************************************************************
1957 * VariantCopy [OLEAUT32.10]
1959 * Frees up the designation variant and makes a copy of the source.
1961 HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
1963 HRESULT res = S_OK;
1965 TRACE("(%p, %p), vt=%d\n", pvargDest, pvargSrc, V_VT(pvargSrc));
1967 res = ValidateVariantType( V_VT(pvargSrc) );
1969 /* If the pointer are to the same variant we don't need
1970 * to do anything.
1972 if( pvargDest != pvargSrc && res == S_OK )
1974 VariantClear( pvargDest ); /* result is not checked */
1976 if( V_VT(pvargSrc) & VT_BYREF )
1978 /* In the case of byreference we only need
1979 * to copy the pointer.
1981 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1982 V_VT(pvargDest) = V_VT(pvargSrc);
1984 else
1987 * The VT_ARRAY flag is another way to designate a safe array.
1989 if (V_VT(pvargSrc) & VT_ARRAY)
1991 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1993 else
1995 /* In the case of by value we need to
1996 * copy the actual value. In the case of
1997 * VT_BSTR a copy of the string is made,
1998 * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1999 * called to increment the object's reference count.
2001 switch( V_VT(pvargSrc) & VT_TYPEMASK )
2003 case( VT_BSTR ):
2004 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
2005 break;
2006 case( VT_DISPATCH ):
2007 V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
2008 if (V_UNION(pvargDest,pdispVal)!=NULL)
2009 IDispatch_AddRef(V_UNION(pvargDest,pdispVal));
2010 break;
2011 case( VT_VARIANT ):
2012 VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
2013 break;
2014 case( VT_UNKNOWN ):
2015 V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
2016 if (V_UNION(pvargDest,pdispVal)!=NULL)
2017 IUnknown_AddRef(V_UNION(pvargDest,punkVal));
2018 break;
2019 case( VT_SAFEARRAY ):
2020 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
2021 break;
2022 default:
2023 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
2024 break;
2027 V_VT(pvargDest) = V_VT(pvargSrc);
2028 dump_Variant(pvargDest);
2032 return res;
2036 /******************************************************************************
2037 * VariantCopyInd [OLEAUT32.11]
2039 * Frees up the destination variant and makes a copy of the source. If
2040 * the source is of type VT_BYREF it performs the necessary indirections.
2042 HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
2044 HRESULT res = S_OK;
2046 TRACE("(%p, %p)\n", pvargDest, pvargSrc);
2048 res = ValidateVariantType( V_VT(pvargSrc) );
2050 if( res != S_OK )
2051 return res;
2053 if( V_VT(pvargSrc) & VT_BYREF )
2055 VARIANTARG varg;
2056 VariantInit( &varg );
2058 /* handle the in place copy.
2060 if( pvargDest == pvargSrc )
2062 /* we will use a copy of the source instead.
2064 res = VariantCopy( &varg, pvargSrc );
2065 pvargSrc = &varg;
2068 if( res == S_OK )
2070 res = VariantClear( pvargDest );
2072 if( res == S_OK )
2075 * The VT_ARRAY flag is another way to designate a safearray variant.
2077 if ( V_VT(pvargSrc) & VT_ARRAY)
2079 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2081 else
2083 /* In the case of by reference we need
2084 * to copy the date pointed to by the variant.
2087 /* Get the variant type.
2089 switch( V_VT(pvargSrc) & VT_TYPEMASK )
2091 case( VT_BSTR ):
2092 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
2093 break;
2094 case( VT_DISPATCH ):
2095 V_UNION(pvargDest,pdispVal) = *V_UNION(pvargSrc,ppdispVal);
2096 if (V_UNION(pvargDest,pdispVal)!=NULL)
2097 IDispatch_AddRef(V_UNION(pvargDest,pdispVal));
2098 break;
2099 case( VT_VARIANT ):
2101 /* Prevent from cycling. According to tests on
2102 * VariantCopyInd in Windows and the documentation
2103 * this API dereferences the inner Variants to only one depth.
2104 * If the inner Variant itself contains an
2105 * other inner variant the E_INVALIDARG error is
2106 * returned.
2108 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
2110 /* If we get here we are attempting to deference
2111 * an inner variant that that is itself contained
2112 * in an inner variant so report E_INVALIDARG error.
2114 res = E_INVALIDARG;
2116 else
2118 /* Set the processing inner variant flag.
2119 * We will set this flag in the inner variant
2120 * that will be passed to the VariantCopyInd function.
2122 (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
2124 /* Dereference the inner variant.
2126 res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
2127 /* We must also copy its type, I think.
2129 V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
2132 break;
2133 case( VT_UNKNOWN ):
2134 V_UNION(pvargDest,punkVal) = *V_UNION(pvargSrc,ppunkVal);
2135 if (V_UNION(pvargDest,pdispVal)!=NULL)
2136 IUnknown_AddRef(V_UNION(pvargDest,punkVal));
2137 break;
2138 case( VT_SAFEARRAY ):
2139 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2140 break;
2141 default:
2142 /* This is a by reference Variant which means that the union
2143 * part of the Variant contains a pointer to some data of
2144 * type "V_VT(pvargSrc) & VT_TYPEMASK".
2145 * We will deference this data in a generic fashion using
2146 * the void pointer "Variant.u.byref".
2147 * We will copy this data into the union of the destination
2148 * Variant.
2150 memcpy( &pvargDest->n1.n2.n3, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
2151 break;
2155 if (res == S_OK) V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
2159 /* this should not fail.
2161 VariantClear( &varg );
2163 else
2165 res = VariantCopy( pvargDest, pvargSrc );
2168 return res;
2171 /******************************************************************************
2172 * Coerces a full safearray. Not optimal code.
2174 static HRESULT
2175 coerce_array(
2176 VARIANTARG* src, VARIANTARG *dst, LCID lcid, USHORT wFlags, VARTYPE vt
2178 SAFEARRAY *sarr = V_ARRAY(src);
2179 HRESULT hres;
2180 LPVOID data;
2181 VARTYPE vartype;
2183 SafeArrayGetVartype(sarr,&vartype);
2184 switch (vt) {
2185 case VT_BSTR:
2186 if (sarr->cDims != 1) {
2187 FIXME("Can not coerce array with dim %d into BSTR\n", sarr->cDims);
2188 return E_FAIL;
2190 switch (V_VT(src) & VT_TYPEMASK) {
2191 case VT_UI1:
2192 hres = SafeArrayAccessData(sarr, &data);
2193 if (FAILED(hres)) return hres;
2195 /* Yes, just memcpied apparently. */
2196 V_BSTR(dst) = SysAllocStringByteLen(data, sarr->rgsabound[0].cElements);
2197 hres = SafeArrayUnaccessData(sarr);
2198 if (FAILED(hres)) return hres;
2199 break;
2200 default:
2201 FIXME("Cannot coerce array of %d into BSTR yet. Please report!\n", V_VT(src) & VT_TYPEMASK);
2202 return E_FAIL;
2204 break;
2205 case VT_SAFEARRAY:
2206 V_VT(dst) = VT_SAFEARRAY;
2207 return SafeArrayCopy(sarr, &V_ARRAY(dst));
2208 default:
2209 FIXME("Cannot coerce array of vt 0x%x/0x%x into vt 0x%x yet. Please report/implement!\n", vartype, V_VT(src), vt);
2210 return E_FAIL;
2212 return S_OK;
2215 /******************************************************************************
2216 * VariantChangeType [OLEAUT32.12]
2218 HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2219 USHORT wFlags, VARTYPE vt)
2221 return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
2224 /******************************************************************************
2225 * VariantChangeTypeEx [OLEAUT32.147]
2227 HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2228 LCID lcid, USHORT wFlags, VARTYPE vt)
2230 HRESULT res = S_OK;
2231 VARIANTARG varg;
2232 VariantInit( &varg );
2234 TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
2235 TRACE("Src Var:\n");
2236 dump_Variant(pvargSrc);
2238 /* validate our source argument.
2240 res = ValidateVariantType( V_VT(pvargSrc) );
2242 /* validate the vartype.
2244 if( res == S_OK )
2246 res = ValidateVt( vt );
2249 /* if we are doing an in-place conversion make a copy of the source.
2251 if( res == S_OK && pvargDest == pvargSrc )
2253 res = VariantCopy( &varg, pvargSrc );
2254 pvargSrc = &varg;
2257 if( res == S_OK )
2259 /* free up the destination variant.
2261 res = VariantClear( pvargDest );
2264 if( res == S_OK )
2266 if( V_VT(pvargSrc) & VT_BYREF )
2268 /* Convert the source variant to a "byvalue" variant.
2270 VARIANTARG Variant;
2272 if ((V_VT(pvargSrc) & 0xf000) != VT_BYREF) {
2273 FIXME("VT_TYPEMASK %x is unhandled.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2274 return E_FAIL;
2277 VariantInit( &Variant );
2278 res = VariantCopyInd( &Variant, pvargSrc );
2279 if( res == S_OK )
2281 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2282 /* this should not fail.
2284 VariantClear( &Variant );
2286 } else {
2287 if (V_VT(pvargSrc) & VT_ARRAY) {
2288 if ((V_VT(pvargSrc) & 0xf000) != VT_ARRAY) {
2289 FIXME("VT_TYPEMASK %x is unhandled in VT_ARRAY.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2290 return E_FAIL;
2292 V_VT(pvargDest) = VT_ARRAY | vt;
2293 res = coerce_array(pvargSrc, pvargDest, lcid, wFlags, vt);
2294 } else {
2295 if ((V_VT(pvargSrc) & 0xf000)) {
2296 FIXME("VT_TYPEMASK %x is unhandled in normal case.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2297 return E_FAIL;
2299 /* Use the current "byvalue" source variant.
2301 res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2305 /* this should not fail.
2307 VariantClear( &varg );
2309 /* set the type of the destination
2311 if ( res == S_OK )
2312 V_VT(pvargDest) = vt;
2314 TRACE("Dest Var:\n");
2315 dump_Variant(pvargDest);
2317 return res;
2323 /******************************************************************************
2324 * VarUI1FromI2 [OLEAUT32.130]
2326 HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2328 TRACE("( %d, %p ), stub\n", sIn, pbOut );
2330 /* Check range of value.
2332 if( sIn < UI1_MIN || sIn > UI1_MAX )
2334 return DISP_E_OVERFLOW;
2337 *pbOut = (BYTE) sIn;
2339 return S_OK;
2342 /******************************************************************************
2343 * VarUI1FromI4 [OLEAUT32.131]
2345 HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2347 TRACE("( %ld, %p ), stub\n", lIn, pbOut );
2349 /* Check range of value.
2351 if( lIn < UI1_MIN || lIn > UI1_MAX )
2353 return DISP_E_OVERFLOW;
2356 *pbOut = (BYTE) lIn;
2358 return S_OK;
2362 /******************************************************************************
2363 * VarUI1FromR4 [OLEAUT32.132]
2365 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2367 TRACE("( %f, %p ), stub\n", fltIn, pbOut );
2369 /* Check range of value.
2371 fltIn = round( fltIn );
2372 if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2374 return DISP_E_OVERFLOW;
2377 *pbOut = (BYTE) fltIn;
2379 return S_OK;
2382 /******************************************************************************
2383 * VarUI1FromR8 [OLEAUT32.133]
2385 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2387 TRACE("( %f, %p ), stub\n", dblIn, pbOut );
2389 /* Check range of value.
2391 dblIn = round( dblIn );
2392 if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2394 return DISP_E_OVERFLOW;
2397 *pbOut = (BYTE) dblIn;
2399 return S_OK;
2402 /******************************************************************************
2403 * VarUI1FromDate [OLEAUT32.135]
2405 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2407 TRACE("( %f, %p ), stub\n", dateIn, pbOut );
2409 /* Check range of value.
2411 dateIn = round( dateIn );
2412 if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2414 return DISP_E_OVERFLOW;
2417 *pbOut = (BYTE) dateIn;
2419 return S_OK;
2422 /******************************************************************************
2423 * VarUI1FromBool [OLEAUT32.138]
2425 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2427 TRACE("( %d, %p ), stub\n", boolIn, pbOut );
2429 *pbOut = (BYTE) boolIn;
2431 return S_OK;
2434 /******************************************************************************
2435 * VarUI1FromI1 [OLEAUT32.237]
2437 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
2439 TRACE("( %c, %p ), stub\n", cIn, pbOut );
2441 *pbOut = cIn;
2443 return S_OK;
2446 /******************************************************************************
2447 * VarUI1FromUI2 [OLEAUT32.238]
2449 HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2451 TRACE("( %d, %p ), stub\n", uiIn, pbOut );
2453 /* Check range of value.
2455 if( uiIn > UI1_MAX )
2457 return DISP_E_OVERFLOW;
2460 *pbOut = (BYTE) uiIn;
2462 return S_OK;
2465 /******************************************************************************
2466 * VarUI1FromUI4 [OLEAUT32.239]
2468 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2470 TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
2472 /* Check range of value.
2474 if( ulIn > UI1_MAX )
2476 return DISP_E_OVERFLOW;
2479 *pbOut = (BYTE) ulIn;
2481 return S_OK;
2485 /******************************************************************************
2486 * VarUI1FromStr [OLEAUT32.136]
2488 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2490 double dValue = 0.0;
2491 LPSTR pNewString = NULL;
2493 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
2495 /* Check if we have a valid argument
2497 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2498 RemoveCharacterFromString( pNewString, "," );
2499 if( IsValidRealString( pNewString ) == FALSE )
2501 return DISP_E_TYPEMISMATCH;
2504 /* Convert the valid string to a floating point number.
2506 dValue = atof( pNewString );
2508 /* We don't need the string anymore so free it.
2510 HeapFree( GetProcessHeap(), 0 , pNewString );
2512 /* Check range of value.
2514 dValue = round( dValue );
2515 if( dValue < UI1_MIN || dValue > UI1_MAX )
2517 return DISP_E_OVERFLOW;
2520 *pbOut = (BYTE) dValue;
2522 return S_OK;
2525 /**********************************************************************
2526 * VarUI1FromCy [OLEAUT32.134]
2527 * Convert currency to unsigned char
2529 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
2530 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2532 if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
2534 *pbOut = (BYTE)t;
2535 return S_OK;
2538 /******************************************************************************
2539 * VarI2FromUI1 [OLEAUT32.48]
2541 HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2543 TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
2545 *psOut = (short) bIn;
2547 return S_OK;
2550 /******************************************************************************
2551 * VarI2FromI4 [OLEAUT32.49]
2553 HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2555 TRACE("( %lx, %p ), stub\n", lIn, psOut );
2557 /* Check range of value.
2559 if( lIn < I2_MIN || lIn > I2_MAX )
2561 return DISP_E_OVERFLOW;
2564 *psOut = (short) lIn;
2566 return S_OK;
2569 /******************************************************************************
2570 * VarI2FromR4 [OLEAUT32.50]
2572 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2574 TRACE("( %f, %p ), stub\n", fltIn, psOut );
2576 /* Check range of value.
2578 fltIn = round( fltIn );
2579 if( fltIn < I2_MIN || fltIn > I2_MAX )
2581 return DISP_E_OVERFLOW;
2584 *psOut = (short) fltIn;
2586 return S_OK;
2589 /******************************************************************************
2590 * VarI2FromR8 [OLEAUT32.51]
2592 HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2594 TRACE("( %f, %p ), stub\n", dblIn, psOut );
2596 /* Check range of value.
2598 dblIn = round( dblIn );
2599 if( dblIn < I2_MIN || dblIn > I2_MAX )
2601 return DISP_E_OVERFLOW;
2604 *psOut = (short) dblIn;
2606 return S_OK;
2609 /******************************************************************************
2610 * VarI2FromDate [OLEAUT32.53]
2612 HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2614 TRACE("( %f, %p ), stub\n", dateIn, psOut );
2616 /* Check range of value.
2618 dateIn = round( dateIn );
2619 if( dateIn < I2_MIN || dateIn > I2_MAX )
2621 return DISP_E_OVERFLOW;
2624 *psOut = (short) dateIn;
2626 return S_OK;
2629 /******************************************************************************
2630 * VarI2FromBool [OLEAUT32.56]
2632 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2634 TRACE("( %d, %p ), stub\n", boolIn, psOut );
2636 *psOut = (short) boolIn;
2638 return S_OK;
2641 /******************************************************************************
2642 * VarI2FromI1 [OLEAUT32.205]
2644 HRESULT WINAPI VarI2FromI1(signed char cIn, short* psOut)
2646 TRACE("( %c, %p ), stub\n", cIn, psOut );
2648 *psOut = (short) cIn;
2650 return S_OK;
2653 /******************************************************************************
2654 * VarI2FromUI2 [OLEAUT32.206]
2656 HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2658 TRACE("( %d, %p ), stub\n", uiIn, psOut );
2660 /* Check range of value.
2662 if( uiIn > I2_MAX )
2664 return DISP_E_OVERFLOW;
2667 *psOut = (short) uiIn;
2669 return S_OK;
2672 /******************************************************************************
2673 * VarI2FromUI4 [OLEAUT32.207]
2675 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2677 TRACE("( %lx, %p ), stub\n", ulIn, psOut );
2679 /* Check range of value.
2681 if( ulIn < I2_MIN || ulIn > I2_MAX )
2683 return DISP_E_OVERFLOW;
2686 *psOut = (short) ulIn;
2688 return S_OK;
2691 /******************************************************************************
2692 * VarI2FromStr [OLEAUT32.54]
2694 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2696 double dValue = 0.0;
2697 LPSTR pNewString = NULL;
2699 TRACE("( %s, 0x%08lx, 0x%08lx, %p ), stub\n", debugstr_w(strIn), lcid, dwFlags, psOut );
2701 /* Check if we have a valid argument
2703 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2704 RemoveCharacterFromString( pNewString, "," );
2705 if( IsValidRealString( pNewString ) == FALSE )
2707 return DISP_E_TYPEMISMATCH;
2710 /* Convert the valid string to a floating point number.
2712 dValue = atof( pNewString );
2714 /* We don't need the string anymore so free it.
2716 HeapFree( GetProcessHeap(), 0, pNewString );
2718 /* Check range of value.
2720 dValue = round( dValue );
2721 if( dValue < I2_MIN || dValue > I2_MAX )
2723 return DISP_E_OVERFLOW;
2726 *psOut = (short) dValue;
2728 return S_OK;
2731 /**********************************************************************
2732 * VarI2FromCy [OLEAUT32.52]
2733 * Convert currency to signed short
2735 HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
2736 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2738 if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
2740 *psOut = (SHORT)t;
2741 return S_OK;
2744 /******************************************************************************
2745 * VarI4FromUI1 [OLEAUT32.58]
2747 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2749 TRACE("( %X, %p ), stub\n", bIn, plOut );
2751 *plOut = (LONG) bIn;
2753 return S_OK;
2757 /******************************************************************************
2758 * VarI4FromR4 [OLEAUT32.60]
2760 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2762 TRACE("( %f, %p ), stub\n", fltIn, plOut );
2764 /* Check range of value.
2766 fltIn = round( fltIn );
2767 if( fltIn < I4_MIN || fltIn > I4_MAX )
2769 return DISP_E_OVERFLOW;
2772 *plOut = (LONG) fltIn;
2774 return S_OK;
2777 /******************************************************************************
2778 * VarI4FromR8 [OLEAUT32.61]
2780 HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2782 TRACE("( %f, %p ), stub\n", dblIn, plOut );
2784 /* Check range of value.
2786 dblIn = round( dblIn );
2787 if( dblIn < I4_MIN || dblIn > I4_MAX )
2789 return DISP_E_OVERFLOW;
2792 *plOut = (LONG) dblIn;
2794 return S_OK;
2797 /******************************************************************************
2798 * VarI4FromDate [OLEAUT32.63]
2800 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2802 TRACE("( %f, %p ), stub\n", dateIn, plOut );
2804 /* Check range of value.
2806 dateIn = round( dateIn );
2807 if( dateIn < I4_MIN || dateIn > I4_MAX )
2809 return DISP_E_OVERFLOW;
2812 *plOut = (LONG) dateIn;
2814 return S_OK;
2817 /******************************************************************************
2818 * VarI4FromBool [OLEAUT32.66]
2820 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2822 TRACE("( %d, %p ), stub\n", boolIn, plOut );
2824 *plOut = (LONG) boolIn;
2826 return S_OK;
2829 /******************************************************************************
2830 * VarI4FromI1 [OLEAUT32.209]
2832 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG* plOut)
2834 TRACE("( %c, %p ), stub\n", cIn, plOut );
2836 *plOut = (LONG) cIn;
2838 return S_OK;
2841 /******************************************************************************
2842 * VarI4FromUI2 [OLEAUT32.210]
2844 HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2846 TRACE("( %d, %p ), stub\n", uiIn, plOut );
2848 *plOut = (LONG) uiIn;
2850 return S_OK;
2853 /******************************************************************************
2854 * VarI4FromUI4 [OLEAUT32.211]
2856 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2858 TRACE("( %lx, %p ), stub\n", ulIn, plOut );
2860 /* Check range of value.
2862 if( ulIn < I4_MIN || ulIn > I4_MAX )
2864 return DISP_E_OVERFLOW;
2867 *plOut = (LONG) ulIn;
2869 return S_OK;
2872 /******************************************************************************
2873 * VarI4FromI2 [OLEAUT32.59]
2875 HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2877 TRACE("( %d, %p ), stub\n", sIn, plOut );
2879 *plOut = (LONG) sIn;
2881 return S_OK;
2884 /******************************************************************************
2885 * VarI4FromStr [OLEAUT32.64]
2887 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2889 double dValue = 0.0;
2890 LPSTR pNewString = NULL;
2892 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
2894 /* Check if we have a valid argument
2896 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2897 RemoveCharacterFromString( pNewString, "," );
2898 if( IsValidRealString( pNewString ) == FALSE )
2900 return DISP_E_TYPEMISMATCH;
2903 /* Convert the valid string to a floating point number.
2905 dValue = atof( pNewString );
2907 /* We don't need the string anymore so free it.
2909 HeapFree( GetProcessHeap(), 0, pNewString );
2911 /* Check range of value.
2913 dValue = round( dValue );
2914 if( dValue < I4_MIN || dValue > I4_MAX )
2916 return DISP_E_OVERFLOW;
2919 *plOut = (LONG) dValue;
2921 return S_OK;
2924 /**********************************************************************
2925 * VarI4FromCy [OLEAUT32.62]
2926 * Convert currency to signed long
2928 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
2929 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2931 if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
2933 *plOut = (LONG)t;
2934 return S_OK;
2937 /******************************************************************************
2938 * VarR4FromUI1 [OLEAUT32.68]
2940 HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
2942 TRACE("( %X, %p ), stub\n", bIn, pfltOut );
2944 *pfltOut = (FLOAT) bIn;
2946 return S_OK;
2949 /******************************************************************************
2950 * VarR4FromI2 [OLEAUT32.69]
2952 HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
2954 TRACE("( %d, %p ), stub\n", sIn, pfltOut );
2956 *pfltOut = (FLOAT) sIn;
2958 return S_OK;
2961 /******************************************************************************
2962 * VarR4FromI4 [OLEAUT32.70]
2964 HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
2966 TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
2968 *pfltOut = (FLOAT) lIn;
2970 return S_OK;
2973 /******************************************************************************
2974 * VarR4FromR8 [OLEAUT32.71]
2976 HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
2978 TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
2980 /* Check range of value.
2982 if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
2984 return DISP_E_OVERFLOW;
2987 *pfltOut = (FLOAT) dblIn;
2989 return S_OK;
2992 /******************************************************************************
2993 * VarR4FromDate [OLEAUT32.73]
2995 HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
2997 TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
2999 /* Check range of value.
3001 if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
3003 return DISP_E_OVERFLOW;
3006 *pfltOut = (FLOAT) dateIn;
3008 return S_OK;
3011 /******************************************************************************
3012 * VarR4FromBool [OLEAUT32.76]
3014 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
3016 TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
3018 *pfltOut = (FLOAT) boolIn;
3020 return S_OK;
3023 /******************************************************************************
3024 * VarR4FromI1 [OLEAUT32.213]
3026 HRESULT WINAPI VarR4FromI1(signed char cIn, FLOAT* pfltOut)
3028 TRACE("( %c, %p ), stub\n", cIn, pfltOut );
3030 *pfltOut = (FLOAT) cIn;
3032 return S_OK;
3035 /******************************************************************************
3036 * VarR4FromUI2 [OLEAUT32.214]
3038 HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
3040 TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
3042 *pfltOut = (FLOAT) uiIn;
3044 return S_OK;
3047 /******************************************************************************
3048 * VarR4FromUI4 [OLEAUT32.215]
3050 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
3052 TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
3054 *pfltOut = (FLOAT) ulIn;
3056 return S_OK;
3059 /******************************************************************************
3060 * VarR4FromStr [OLEAUT32.74]
3062 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
3064 double dValue = 0.0;
3065 LPSTR pNewString = NULL;
3067 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
3069 /* Check if we have a valid argument
3071 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3072 RemoveCharacterFromString( pNewString, "," );
3073 if( IsValidRealString( pNewString ) == FALSE )
3075 return DISP_E_TYPEMISMATCH;
3078 /* Convert the valid string to a floating point number.
3080 dValue = atof( pNewString );
3082 /* We don't need the string anymore so free it.
3084 HeapFree( GetProcessHeap(), 0, pNewString );
3086 /* Check range of value.
3088 if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
3090 return DISP_E_OVERFLOW;
3093 *pfltOut = (FLOAT) dValue;
3095 return S_OK;
3098 /**********************************************************************
3099 * VarR4FromCy [OLEAUT32.72]
3100 * Convert currency to float
3102 HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
3103 *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3105 return S_OK;
3108 /******************************************************************************
3109 * VarR8FromUI1 [OLEAUT32.78]
3111 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
3113 TRACE("( %d, %p ), stub\n", bIn, pdblOut );
3115 *pdblOut = (double) bIn;
3117 return S_OK;
3120 /******************************************************************************
3121 * VarR8FromI2 [OLEAUT32.79]
3123 HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
3125 TRACE("( %d, %p ), stub\n", sIn, pdblOut );
3127 *pdblOut = (double) sIn;
3129 return S_OK;
3132 /******************************************************************************
3133 * VarR8FromI4 [OLEAUT32.80]
3135 HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
3137 TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
3139 *pdblOut = (double) lIn;
3141 return S_OK;
3144 /******************************************************************************
3145 * VarR8FromR4 [OLEAUT32.81]
3147 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
3149 TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
3151 *pdblOut = (double) fltIn;
3153 return S_OK;
3156 /******************************************************************************
3157 * VarR8FromDate [OLEAUT32.83]
3159 HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
3161 TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
3163 *pdblOut = (double) dateIn;
3165 return S_OK;
3168 /******************************************************************************
3169 * VarR8FromBool [OLEAUT32.86]
3171 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
3173 TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
3175 *pdblOut = (double) boolIn;
3177 return S_OK;
3180 /******************************************************************************
3181 * VarR8FromI1 [OLEAUT32.217]
3183 HRESULT WINAPI VarR8FromI1(signed char cIn, double* pdblOut)
3185 TRACE("( %c, %p ), stub\n", cIn, pdblOut );
3187 *pdblOut = (double) cIn;
3189 return S_OK;
3192 /******************************************************************************
3193 * VarR8FromUI2 [OLEAUT32.218]
3195 HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
3197 TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
3199 *pdblOut = (double) uiIn;
3201 return S_OK;
3204 /******************************************************************************
3205 * VarR8FromUI4 [OLEAUT32.219]
3207 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
3209 TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
3211 *pdblOut = (double) ulIn;
3213 return S_OK;
3216 /******************************************************************************
3217 * VarR8FromStr [OLEAUT32.84]
3219 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
3221 double dValue = 0.0;
3222 LPSTR pNewString = NULL;
3224 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3225 TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString, lcid, dwFlags, pdblOut );
3227 /* Check if we have a valid argument
3229 RemoveCharacterFromString( pNewString, "," );
3230 if( IsValidRealString( pNewString ) == FALSE )
3232 return DISP_E_TYPEMISMATCH;
3235 /* Convert the valid string to a floating point number.
3237 dValue = atof( pNewString );
3239 /* We don't need the string anymore so free it.
3241 HeapFree( GetProcessHeap(), 0, pNewString );
3243 *pdblOut = dValue;
3245 return S_OK;
3248 /**********************************************************************
3249 * VarR8FromCy [OLEAUT32.82]
3250 * Convert currency to double
3252 HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
3253 *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3254 TRACE("%lu %ld -> %f\n", cyIn.s.Hi, cyIn.s.Lo, *pdblOut);
3255 return S_OK;
3258 /******************************************************************************
3259 * VarDateFromUI1 [OLEAUT32.88]
3261 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
3263 TRACE("( %d, %p ), stub\n", bIn, pdateOut );
3265 *pdateOut = (DATE) bIn;
3267 return S_OK;
3270 /******************************************************************************
3271 * VarDateFromI2 [OLEAUT32.89]
3273 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
3275 TRACE("( %d, %p ), stub\n", sIn, pdateOut );
3277 *pdateOut = (DATE) sIn;
3279 return S_OK;
3282 /******************************************************************************
3283 * VarDateFromI4 [OLEAUT32.90]
3285 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3287 TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
3289 if( lIn < DATE_MIN || lIn > DATE_MAX )
3291 return DISP_E_OVERFLOW;
3294 *pdateOut = (DATE) lIn;
3296 return S_OK;
3299 /******************************************************************************
3300 * VarDateFromR4 [OLEAUT32.91]
3302 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3304 TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3306 if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
3308 return DISP_E_OVERFLOW;
3311 *pdateOut = (DATE) fltIn;
3313 return S_OK;
3316 /******************************************************************************
3317 * VarDateFromR8 [OLEAUT32.92]
3319 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3321 TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3323 if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3325 return DISP_E_OVERFLOW;
3328 *pdateOut = (DATE) dblIn;
3330 return S_OK;
3333 /******************************************************************************
3334 * VarDateFromStr [OLEAUT32.94]
3335 * The string representing the date is composed of two parts, a date and time.
3337 * The format of the time is has follows:
3338 * hh[:mm][:ss][AM|PM]
3339 * Whitespace can be inserted anywhere between these tokens. A whitespace consists
3340 * of space and/or tab characters, which are ignored.
3342 * The formats for the date part are has follows:
3343 * mm/[dd/][yy]yy
3344 * [dd/]mm/[yy]yy
3345 * [yy]yy/mm/dd
3346 * January dd[,] [yy]yy
3347 * dd January [yy]yy
3348 * [yy]yy January dd
3349 * Whitespace can be inserted anywhere between these tokens.
3351 * The formats for the date and time string are has follows.
3352 * date[whitespace][time]
3353 * [time][whitespace]date
3355 * These are the only characters allowed in a string representing a date and time:
3356 * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3358 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3360 HRESULT ret = S_OK;
3361 struct tm TM;
3363 memset( &TM, 0, sizeof(TM) );
3365 TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3367 if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
3369 if( TmToDATE( &TM, pdateOut ) == FALSE )
3371 ret = E_INVALIDARG;
3374 else
3376 ret = DISP_E_TYPEMISMATCH;
3378 TRACE("Return value %f\n", *pdateOut);
3379 return ret;
3382 /******************************************************************************
3383 * VarDateFromI1 [OLEAUT32.221]
3385 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
3387 TRACE("( %c, %p ), stub\n", cIn, pdateOut );
3389 *pdateOut = (DATE) cIn;
3391 return S_OK;
3394 /******************************************************************************
3395 * VarDateFromUI2 [OLEAUT32.222]
3397 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3399 TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
3401 if( uiIn > DATE_MAX )
3403 return DISP_E_OVERFLOW;
3406 *pdateOut = (DATE) uiIn;
3408 return S_OK;
3411 /******************************************************************************
3412 * VarDateFromUI4 [OLEAUT32.223]
3414 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3416 TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
3418 if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3420 return DISP_E_OVERFLOW;
3423 *pdateOut = (DATE) ulIn;
3425 return S_OK;
3428 /******************************************************************************
3429 * VarDateFromBool [OLEAUT32.96]
3431 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3433 TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
3435 *pdateOut = (DATE) boolIn;
3437 return S_OK;
3440 /**********************************************************************
3441 * VarDateFromCy [OLEAUT32.93]
3442 * Convert currency to date
3444 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
3445 *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3447 if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3448 return S_OK;
3451 /******************************************************************************
3452 * VarBstrFromUI1 [OLEAUT32.108]
3454 HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3456 TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3457 sprintf( pBuffer, "%d", bVal );
3459 *pbstrOut = StringDupAtoBstr( pBuffer );
3461 return S_OK;
3464 /******************************************************************************
3465 * VarBstrFromI2 [OLEAUT32.109]
3467 HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3469 TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3470 sprintf( pBuffer, "%d", iVal );
3471 *pbstrOut = StringDupAtoBstr( pBuffer );
3473 return S_OK;
3476 /******************************************************************************
3477 * VarBstrFromI4 [OLEAUT32.110]
3479 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3481 TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
3483 sprintf( pBuffer, "%ld", lIn );
3484 *pbstrOut = StringDupAtoBstr( pBuffer );
3486 return S_OK;
3489 /******************************************************************************
3490 * VarBstrFromR4 [OLEAUT32.111]
3492 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3494 TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
3496 sprintf( pBuffer, "%.7G", fltIn );
3497 *pbstrOut = StringDupAtoBstr( pBuffer );
3499 return S_OK;
3502 /******************************************************************************
3503 * VarBstrFromR8 [OLEAUT32.112]
3505 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3507 TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
3509 sprintf( pBuffer, "%.15G", dblIn );
3510 *pbstrOut = StringDupAtoBstr( pBuffer );
3512 return S_OK;
3515 /******************************************************************************
3516 * VarBstrFromCy [OLEAUT32.113]
3518 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
3519 HRESULT rc = S_OK;
3520 double curVal = 0.0;
3522 TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid, dwFlags, pbstrOut);
3524 /* Firstly get the currency in a double, then put it in a buffer */
3525 rc = VarR8FromCy(cyIn, &curVal);
3526 if (rc == S_OK) {
3527 sprintf(pBuffer, "%G", curVal);
3528 *pbstrOut = StringDupAtoBstr( pBuffer );
3530 return rc;
3534 /******************************************************************************
3535 * VarBstrFromDate [OLEAUT32.114]
3537 * The date is implemented using an 8 byte floating-point number.
3538 * Days are represented by whole numbers increments starting with 0.00 as
3539 * being December 30 1899, midnight.
3540 * The hours are expressed as the fractional part of the number.
3541 * December 30 1899 at midnight = 0.00
3542 * January 1 1900 at midnight = 2.00
3543 * January 4 1900 at 6 AM = 5.25
3544 * January 4 1900 at noon = 5.50
3545 * December 29 1899 at midnight = -1.00
3546 * December 18 1899 at midnight = -12.00
3547 * December 18 1899 at 6AM = -12.25
3548 * December 18 1899 at 6PM = -12.75
3549 * December 19 1899 at midnight = -11.00
3550 * The tm structure is as follows:
3551 * struct tm {
3552 * int tm_sec; seconds after the minute - [0,59]
3553 * int tm_min; minutes after the hour - [0,59]
3554 * int tm_hour; hours since midnight - [0,23]
3555 * int tm_mday; day of the month - [1,31]
3556 * int tm_mon; months since January - [0,11]
3557 * int tm_year; years
3558 * int tm_wday; days since Sunday - [0,6]
3559 * int tm_yday; days since January 1 - [0,365]
3560 * int tm_isdst; daylight savings time flag
3561 * };
3563 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3565 struct tm TM;
3566 memset( &TM, 0, sizeof(TM) );
3568 TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
3570 if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
3572 return E_INVALIDARG;
3575 if( dwFlags & VAR_DATEVALUEONLY )
3576 strftime( pBuffer, BUFFER_MAX, "%x", &TM );
3577 else if( dwFlags & VAR_TIMEVALUEONLY )
3578 strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3579 else
3580 strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3582 TRACE("result: %s\n", pBuffer);
3583 *pbstrOut = StringDupAtoBstr( pBuffer );
3584 return S_OK;
3587 /******************************************************************************
3588 * VarBstrFromBool [OLEAUT32.116]
3590 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3592 TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
3594 sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
3596 *pbstrOut = StringDupAtoBstr( pBuffer );
3598 return S_OK;
3601 /******************************************************************************
3602 * VarBstrFromI1 [OLEAUT32.229]
3604 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3606 TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3607 sprintf( pBuffer, "%d", cIn );
3608 *pbstrOut = StringDupAtoBstr( pBuffer );
3610 return S_OK;
3613 /******************************************************************************
3614 * VarBstrFromUI2 [OLEAUT32.230]
3616 HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3618 TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3619 sprintf( pBuffer, "%d", uiIn );
3620 *pbstrOut = StringDupAtoBstr( pBuffer );
3622 return S_OK;
3625 /******************************************************************************
3626 * VarBstrFromUI4 [OLEAUT32.231]
3628 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3630 TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3631 sprintf( pBuffer, "%ld", ulIn );
3632 *pbstrOut = StringDupAtoBstr( pBuffer );
3634 return S_OK;
3637 /******************************************************************************
3638 * VarBstrFromDec [OLEAUT32.@]
3640 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3642 if(!pDecIn->u.s.sign && !pDecIn->u.s.scale &&
3643 !pDecIn->Hi32 && !pDecIn->u1.s1.Mid32)
3644 return VarBstrFromUI4(pDecIn->u1.s1.Lo32, lcid, dwFlags, pbstrOut);
3645 FIXME("%c%08lx%08lx%08lx E%02x stub\n",
3646 (pDecIn->u.s.sign == DECIMAL_NEG) ? '-' :
3647 (pDecIn->u.s.sign == 0) ? '+' : '?',
3648 pDecIn->Hi32, pDecIn->u1.s1.Mid32, pDecIn->u1.s1.Lo32,
3649 pDecIn->u.s.scale);
3650 return E_INVALIDARG;
3653 /******************************************************************************
3654 * VarBoolFromUI1 [OLEAUT32.118]
3656 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3658 TRACE("( %d, %p ), stub\n", bIn, pboolOut );
3660 if( bIn == 0 )
3662 *pboolOut = VARIANT_FALSE;
3664 else
3666 *pboolOut = VARIANT_TRUE;
3669 return S_OK;
3672 /******************************************************************************
3673 * VarBoolFromI2 [OLEAUT32.119]
3675 HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3677 TRACE("( %d, %p ), stub\n", sIn, pboolOut );
3679 *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
3681 return S_OK;
3684 /******************************************************************************
3685 * VarBoolFromI4 [OLEAUT32.120]
3687 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3689 TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
3691 *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
3693 return S_OK;
3696 /******************************************************************************
3697 * VarBoolFromR4 [OLEAUT32.121]
3699 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3701 TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
3703 *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3705 return S_OK;
3708 /******************************************************************************
3709 * VarBoolFromR8 [OLEAUT32.122]
3711 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3713 TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
3715 *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3717 return S_OK;
3720 /******************************************************************************
3721 * VarBoolFromDate [OLEAUT32.123]
3723 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3725 TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
3727 *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3729 return S_OK;
3732 /******************************************************************************
3733 * VarBoolFromStr [OLEAUT32.125]
3735 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3737 HRESULT ret = S_OK;
3738 char* pNewString = NULL;
3740 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
3742 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3744 if( pNewString == NULL || strlen( pNewString ) == 0 )
3746 ret = DISP_E_TYPEMISMATCH;
3749 if( ret == S_OK )
3751 if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
3753 *pboolOut = VARIANT_TRUE;
3755 else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
3757 *pboolOut = VARIANT_FALSE;
3759 else
3761 /* Try converting the string to a floating point number.
3763 double dValue = 0.0;
3764 HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3765 if( res != S_OK )
3767 ret = DISP_E_TYPEMISMATCH;
3769 else
3770 *pboolOut = (dValue == 0.0) ?
3771 VARIANT_FALSE : VARIANT_TRUE;
3775 HeapFree( GetProcessHeap(), 0, pNewString );
3777 return ret;
3780 /******************************************************************************
3781 * VarBoolFromI1 [OLEAUT32.233]
3783 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL* pboolOut)
3785 TRACE("( %c, %p ), stub\n", cIn, pboolOut );
3787 *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3789 return S_OK;
3792 /******************************************************************************
3793 * VarBoolFromUI2 [OLEAUT32.234]
3795 HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3797 TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
3799 *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3801 return S_OK;
3804 /******************************************************************************
3805 * VarBoolFromUI4 [OLEAUT32.235]
3807 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3809 TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
3811 *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3813 return S_OK;
3816 /**********************************************************************
3817 * VarBoolFromCy [OLEAUT32.124]
3818 * Convert currency to boolean
3820 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
3821 if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
3822 else *pboolOut = 0;
3824 return S_OK;
3827 /******************************************************************************
3828 * VarI1FromUI1 [OLEAUT32.244]
3830 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char *pcOut)
3832 TRACE("( %d, %p ), stub\n", bIn, pcOut );
3834 /* Check range of value.
3836 if( bIn > CHAR_MAX )
3838 return DISP_E_OVERFLOW;
3841 *pcOut = (CHAR) bIn;
3843 return S_OK;
3846 /******************************************************************************
3847 * VarI1FromI2 [OLEAUT32.245]
3849 HRESULT WINAPI VarI1FromI2(short uiIn, signed char *pcOut)
3851 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3853 if( uiIn > CHAR_MAX )
3855 return DISP_E_OVERFLOW;
3858 *pcOut = (CHAR) uiIn;
3860 return S_OK;
3863 /******************************************************************************
3864 * VarI1FromI4 [OLEAUT32.246]
3866 HRESULT WINAPI VarI1FromI4(LONG lIn, signed char *pcOut)
3868 TRACE("( %ld, %p ), stub\n", lIn, pcOut );
3870 if( lIn < CHAR_MIN || lIn > CHAR_MAX )
3872 return DISP_E_OVERFLOW;
3875 *pcOut = (CHAR) lIn;
3877 return S_OK;
3880 /******************************************************************************
3881 * VarI1FromR4 [OLEAUT32.247]
3883 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char *pcOut)
3885 TRACE("( %f, %p ), stub\n", fltIn, pcOut );
3887 fltIn = round( fltIn );
3888 if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
3890 return DISP_E_OVERFLOW;
3893 *pcOut = (CHAR) fltIn;
3895 return S_OK;
3898 /******************************************************************************
3899 * VarI1FromR8 [OLEAUT32.248]
3901 HRESULT WINAPI VarI1FromR8(double dblIn, signed char *pcOut)
3903 TRACE("( %f, %p ), stub\n", dblIn, pcOut );
3905 dblIn = round( dblIn );
3906 if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
3908 return DISP_E_OVERFLOW;
3911 *pcOut = (CHAR) dblIn;
3913 return S_OK;
3916 /******************************************************************************
3917 * VarI1FromDate [OLEAUT32.249]
3919 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char *pcOut)
3921 TRACE("( %f, %p ), stub\n", dateIn, pcOut );
3923 dateIn = round( dateIn );
3924 if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
3926 return DISP_E_OVERFLOW;
3929 *pcOut = (CHAR) dateIn;
3931 return S_OK;
3934 /******************************************************************************
3935 * VarI1FromStr [OLEAUT32.251]
3937 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char *pcOut)
3939 double dValue = 0.0;
3940 LPSTR pNewString = NULL;
3942 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
3944 /* Check if we have a valid argument
3946 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3947 RemoveCharacterFromString( pNewString, "," );
3948 if( IsValidRealString( pNewString ) == FALSE )
3950 return DISP_E_TYPEMISMATCH;
3953 /* Convert the valid string to a floating point number.
3955 dValue = atof( pNewString );
3957 /* We don't need the string anymore so free it.
3959 HeapFree( GetProcessHeap(), 0, pNewString );
3961 /* Check range of value.
3963 dValue = round( dValue );
3964 if( dValue < CHAR_MIN || dValue > CHAR_MAX )
3966 return DISP_E_OVERFLOW;
3969 *pcOut = (CHAR) dValue;
3971 return S_OK;
3974 /******************************************************************************
3975 * VarI1FromBool [OLEAUT32.253]
3977 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char *pcOut)
3979 TRACE("( %d, %p ), stub\n", boolIn, pcOut );
3981 *pcOut = (CHAR) boolIn;
3983 return S_OK;
3986 /******************************************************************************
3987 * VarI1FromUI2 [OLEAUT32.254]
3989 HRESULT WINAPI VarI1FromUI2(USHORT uiIn, signed char *pcOut)
3991 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3993 if( uiIn > CHAR_MAX )
3995 return DISP_E_OVERFLOW;
3998 *pcOut = (CHAR) uiIn;
4000 return S_OK;
4003 /******************************************************************************
4004 * VarI1FromUI4 [OLEAUT32.255]
4006 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char *pcOut)
4008 TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
4010 if( ulIn > CHAR_MAX )
4012 return DISP_E_OVERFLOW;
4015 *pcOut = (CHAR) ulIn;
4017 return S_OK;
4020 /**********************************************************************
4021 * VarI1FromCy [OLEAUT32.250]
4022 * Convert currency to signed char
4024 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char *pcOut) {
4025 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4027 if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
4029 *pcOut = (CHAR)t;
4030 return S_OK;
4033 /******************************************************************************
4034 * VarUI2FromUI1 [OLEAUT32.257]
4036 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
4038 TRACE("( %d, %p ), stub\n", bIn, puiOut );
4040 *puiOut = (USHORT) bIn;
4042 return S_OK;
4045 /******************************************************************************
4046 * VarUI2FromI2 [OLEAUT32.258]
4048 HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
4050 TRACE("( %d, %p ), stub\n", uiIn, puiOut );
4052 if( uiIn < UI2_MIN )
4054 return DISP_E_OVERFLOW;
4057 *puiOut = (USHORT) uiIn;
4059 return S_OK;
4062 /******************************************************************************
4063 * VarUI2FromI4 [OLEAUT32.259]
4065 HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
4067 TRACE("( %ld, %p ), stub\n", lIn, puiOut );
4069 if( lIn < UI2_MIN || lIn > UI2_MAX )
4071 return DISP_E_OVERFLOW;
4074 *puiOut = (USHORT) lIn;
4076 return S_OK;
4079 /******************************************************************************
4080 * VarUI2FromR4 [OLEAUT32.260]
4082 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
4084 TRACE("( %f, %p ), stub\n", fltIn, puiOut );
4086 fltIn = round( fltIn );
4087 if( fltIn < UI2_MIN || fltIn > UI2_MAX )
4089 return DISP_E_OVERFLOW;
4092 *puiOut = (USHORT) fltIn;
4094 return S_OK;
4097 /******************************************************************************
4098 * VarUI2FromR8 [OLEAUT32.261]
4100 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
4102 TRACE("( %f, %p ), stub\n", dblIn, puiOut );
4104 dblIn = round( dblIn );
4105 if( dblIn < UI2_MIN || dblIn > UI2_MAX )
4107 return DISP_E_OVERFLOW;
4110 *puiOut = (USHORT) dblIn;
4112 return S_OK;
4115 /******************************************************************************
4116 * VarUI2FromDate [OLEAUT32.262]
4118 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
4120 TRACE("( %f, %p ), stub\n", dateIn, puiOut );
4122 dateIn = round( dateIn );
4123 if( dateIn < UI2_MIN || dateIn > UI2_MAX )
4125 return DISP_E_OVERFLOW;
4128 *puiOut = (USHORT) dateIn;
4130 return S_OK;
4133 /******************************************************************************
4134 * VarUI2FromStr [OLEAUT32.264]
4136 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
4138 double dValue = 0.0;
4139 LPSTR pNewString = NULL;
4141 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
4143 /* Check if we have a valid argument
4145 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4146 RemoveCharacterFromString( pNewString, "," );
4147 if( IsValidRealString( pNewString ) == FALSE )
4149 return DISP_E_TYPEMISMATCH;
4152 /* Convert the valid string to a floating point number.
4154 dValue = atof( pNewString );
4156 /* We don't need the string anymore so free it.
4158 HeapFree( GetProcessHeap(), 0, pNewString );
4160 /* Check range of value.
4162 dValue = round( dValue );
4163 if( dValue < UI2_MIN || dValue > UI2_MAX )
4165 return DISP_E_OVERFLOW;
4168 *puiOut = (USHORT) dValue;
4170 return S_OK;
4173 /******************************************************************************
4174 * VarUI2FromBool [OLEAUT32.266]
4176 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
4178 TRACE("( %d, %p ), stub\n", boolIn, puiOut );
4180 *puiOut = (USHORT) boolIn;
4182 return S_OK;
4185 /******************************************************************************
4186 * VarUI2FromI1 [OLEAUT32.267]
4188 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* puiOut)
4190 TRACE("( %c, %p ), stub\n", cIn, puiOut );
4192 *puiOut = (USHORT) cIn;
4194 return S_OK;
4197 /******************************************************************************
4198 * VarUI2FromUI4 [OLEAUT32.268]
4200 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
4202 TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
4204 if( ulIn > UI2_MAX )
4206 return DISP_E_OVERFLOW;
4209 *puiOut = (USHORT) ulIn;
4211 return S_OK;
4214 /******************************************************************************
4215 * VarUI4FromStr [OLEAUT32.277]
4217 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
4219 double dValue = 0.0;
4220 LPSTR pNewString = NULL;
4222 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
4224 /* Check if we have a valid argument
4226 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4227 RemoveCharacterFromString( pNewString, "," );
4228 if( IsValidRealString( pNewString ) == FALSE )
4230 return DISP_E_TYPEMISMATCH;
4233 /* Convert the valid string to a floating point number.
4235 dValue = atof( pNewString );
4237 /* We don't need the string anymore so free it.
4239 HeapFree( GetProcessHeap(), 0, pNewString );
4241 /* Check range of value.
4243 dValue = round( dValue );
4244 if( dValue < UI4_MIN || dValue > UI4_MAX )
4246 return DISP_E_OVERFLOW;
4249 *pulOut = (ULONG) dValue;
4251 return S_OK;
4254 /**********************************************************************
4255 * VarUI2FromCy [OLEAUT32.263]
4256 * Convert currency to unsigned short
4258 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
4259 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4261 if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
4263 *pusOut = (USHORT)t;
4265 return S_OK;
4268 /******************************************************************************
4269 * VarUI4FromUI1 [OLEAUT32.270]
4271 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
4273 TRACE("( %d, %p ), stub\n", bIn, pulOut );
4275 *pulOut = (USHORT) bIn;
4277 return S_OK;
4280 /******************************************************************************
4281 * VarUI4FromI2 [OLEAUT32.271]
4283 HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
4285 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4287 if( uiIn < UI4_MIN )
4289 return DISP_E_OVERFLOW;
4292 *pulOut = (ULONG) uiIn;
4294 return S_OK;
4297 /******************************************************************************
4298 * VarUI4FromI4 [OLEAUT32.272]
4300 HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
4302 TRACE("( %ld, %p ), stub\n", lIn, pulOut );
4304 if( lIn < 0 )
4306 return DISP_E_OVERFLOW;
4309 *pulOut = (ULONG) lIn;
4311 return S_OK;
4314 /******************************************************************************
4315 * VarUI4FromR4 [OLEAUT32.273]
4317 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
4319 fltIn = round( fltIn );
4320 if( fltIn < UI4_MIN || fltIn > UI4_MAX )
4322 return DISP_E_OVERFLOW;
4325 *pulOut = (ULONG) fltIn;
4327 return S_OK;
4330 /******************************************************************************
4331 * VarUI4FromR8 [OLEAUT32.274]
4333 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
4335 TRACE("( %f, %p ), stub\n", dblIn, pulOut );
4337 dblIn = round( dblIn );
4338 if( dblIn < UI4_MIN || dblIn > UI4_MAX )
4340 return DISP_E_OVERFLOW;
4343 *pulOut = (ULONG) dblIn;
4345 return S_OK;
4348 /******************************************************************************
4349 * VarUI4FromDate [OLEAUT32.275]
4351 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
4353 TRACE("( %f, %p ), stub\n", dateIn, pulOut );
4355 dateIn = round( dateIn );
4356 if( dateIn < UI4_MIN || dateIn > UI4_MAX )
4358 return DISP_E_OVERFLOW;
4361 *pulOut = (ULONG) dateIn;
4363 return S_OK;
4366 /******************************************************************************
4367 * VarUI4FromBool [OLEAUT32.279]
4369 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
4371 TRACE("( %d, %p ), stub\n", boolIn, pulOut );
4373 *pulOut = (ULONG) boolIn;
4375 return S_OK;
4378 /******************************************************************************
4379 * VarUI4FromI1 [OLEAUT32.280]
4381 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG* pulOut)
4383 TRACE("( %c, %p ), stub\n", cIn, pulOut );
4385 *pulOut = (ULONG) cIn;
4387 return S_OK;
4390 /******************************************************************************
4391 * VarUI4FromUI2 [OLEAUT32.281]
4393 HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4395 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4397 *pulOut = (ULONG) uiIn;
4399 return S_OK;
4402 /**********************************************************************
4403 * VarUI4FromCy [OLEAUT32.276]
4404 * Convert currency to unsigned long
4406 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
4407 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4409 if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4411 *pulOut = (ULONG)t;
4413 return S_OK;
4416 /**********************************************************************
4417 * VarCyFromUI1 [OLEAUT32.98]
4418 * Convert unsigned char to currency
4420 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
4421 pcyOut->s.Hi = 0;
4422 pcyOut->s.Lo = ((ULONG)bIn) * 10000;
4424 return S_OK;
4427 /**********************************************************************
4428 * VarCyFromI2 [OLEAUT32.99]
4429 * Convert signed short to currency
4431 HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
4432 if (sIn < 0) pcyOut->s.Hi = -1;
4433 else pcyOut->s.Hi = 0;
4434 pcyOut->s.Lo = ((ULONG)sIn) * 10000;
4436 return S_OK;
4439 /**********************************************************************
4440 * VarCyFromI4 [OLEAUT32.100]
4441 * Convert signed long to currency
4443 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4444 double t = (double)lIn * (double)10000;
4445 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4446 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4447 if (lIn < 0) pcyOut->s.Hi--;
4449 return S_OK;
4452 /**********************************************************************
4453 * VarCyFromR4 [OLEAUT32.101]
4454 * Convert float to currency
4456 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
4457 double t = round((double)fltIn * (double)10000);
4458 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4459 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4460 if (fltIn < 0) pcyOut->s.Hi--;
4462 return S_OK;
4465 /**********************************************************************
4466 * VarCyFromR8 [OLEAUT32.102]
4467 * Convert double to currency
4469 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
4470 double t = round(dblIn * (double)10000);
4471 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4472 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4473 if (dblIn < 0) pcyOut->s.Hi--;
4475 return S_OK;
4478 /**********************************************************************
4479 * VarCyFromDate [OLEAUT32.103]
4480 * Convert date to currency
4482 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
4483 double t = round((double)dateIn * (double)10000);
4484 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4485 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4486 if (dateIn < 0) pcyOut->s.Hi--;
4488 return S_OK;
4491 /**********************************************************************
4492 * VarCyFromStr [OLEAUT32.104]
4493 * FIXME: Never tested with decimal separator other than '.'
4495 HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
4497 LPSTR pNewString = NULL;
4498 char *decSep = NULL;
4499 char *strPtr,*curPtr = NULL;
4500 int size, rc;
4501 double currencyVal = 0.0;
4504 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4505 TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString, lcid, dwFlags, pcyOut );
4507 /* Get locale information - Decimal Separator (size includes 0x00) */
4508 size = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, NULL, 0);
4509 decSep = (char *) malloc(size);
4510 rc = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, decSep, size);
4511 TRACE("Decimal Separator is '%s'\n", decSep);
4513 /* Now copy to temporary buffer, skipping any character except 0-9 and
4514 the decimal separator */
4515 curPtr = pBuffer; /* Current position in string being built */
4516 strPtr = pNewString; /* Current position in supplied currenct string */
4518 while (*strPtr) {
4519 /* If decimal separator, skip it and put '.' in string */
4520 if (strncmp(strPtr, decSep, (size-1)) == 0) {
4521 strPtr = strPtr + (size-1);
4522 *curPtr = '.';
4523 curPtr++;
4524 } else if ((*strPtr == '+' || *strPtr == '-') ||
4525 (*strPtr >= '0' && *strPtr <= '9')) {
4526 *curPtr = *strPtr;
4527 strPtr++;
4528 curPtr++;
4529 } else strPtr++;
4531 *curPtr = 0x00;
4533 /* Try to get currency into a double */
4534 currencyVal = atof(pBuffer);
4535 TRACE("Converted string '%s' to %f\n", pBuffer, currencyVal);
4537 /* Free allocated storage */
4538 HeapFree( GetProcessHeap(), 0, pNewString );
4539 free(decSep);
4541 /* Convert double -> currency using internal routine */
4542 return VarCyFromR8(currencyVal, pcyOut);
4546 /**********************************************************************
4547 * VarCyFromBool [OLEAUT32.106]
4548 * Convert boolean to currency
4550 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
4551 if (boolIn < 0) pcyOut->s.Hi = -1;
4552 else pcyOut->s.Hi = 0;
4553 pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
4555 return S_OK;
4558 /**********************************************************************
4559 * VarCyFromI1 [OLEAUT32.225]
4560 * Convert signed char to currency
4562 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
4563 if (cIn < 0) pcyOut->s.Hi = -1;
4564 else pcyOut->s.Hi = 0;
4565 pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
4567 return S_OK;
4570 /**********************************************************************
4571 * VarCyFromUI2 [OLEAUT32.226]
4572 * Convert unsigned short to currency
4574 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
4575 pcyOut->s.Hi = 0;
4576 pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
4578 return S_OK;
4581 /**********************************************************************
4582 * VarCyFromUI4 [OLEAUT32.227]
4583 * Convert unsigned long to currency
4585 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4586 double t = (double)ulIn * (double)10000;
4587 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4588 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4590 return S_OK;
4593 /**********************************************************************
4594 * VarDecFromStr [OLEAUT32.@]
4596 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags,
4597 DECIMAL* pdecOut)
4598 { WCHAR *p=strIn;
4599 ULONGLONG t;
4600 ULONG cy;
4602 DECIMAL_SETZERO(pdecOut);
4604 if(*p == (WCHAR)'-')pdecOut->u.s.sign= DECIMAL_NEG;
4605 if((*p == (WCHAR)'-') || (*p == (WCHAR)'+')) p++;
4606 for(;*p != (WCHAR)0; p++) {
4607 if((*p < (WCHAR)'0')||(*p > (WCHAR)'9')) goto error ;
4608 t = (ULONGLONG)pdecOut->u1.s1.Lo32 *(ULONGLONG)10
4609 + (ULONGLONG)(*p -(WCHAR)'0');
4610 cy = (ULONG)(t >> 32);
4611 pdecOut->u1.s1.Lo32 = (ULONG)(t & (ULONGLONG)UI4_MAX);
4612 t = (ULONGLONG)pdecOut->u1.s1.Mid32 * (ULONGLONG)10
4613 + (ULONGLONG)cy;
4614 cy = (ULONG)(t >> 32);
4615 pdecOut->u1.s1.Mid32 = (ULONG)(t & (ULONGLONG)UI4_MAX);
4616 t = (ULONGLONG)pdecOut->Hi32 * (ULONGLONG)10
4617 + (ULONGLONG)cy;
4618 cy = (ULONG)(t >> 32);
4619 pdecOut->Hi32 = (ULONG)(t & (ULONGLONG)UI4_MAX);
4620 if(cy) goto overflow ;
4622 TRACE("%s -> sign %02x,hi %08lx,mid %08lx, lo%08lx, scale %08x\n",
4623 debugstr_w(strIn),
4624 pdecOut->u.s.sign, pdecOut->Hi32, pdecOut->u1.s1.Mid32,
4625 pdecOut->u1.s1.Lo32, pdecOut->u.s.scale);
4626 return S_OK;
4628 overflow:
4629 /* like NT4 SP5 */
4630 pdecOut->Hi32 = pdecOut->u1.s1.Mid32 = pdecOut->u1.s1.Lo32 = 0xffffffff;
4631 return DISP_E_OVERFLOW;
4633 error:
4634 ERR("%s: unknown char at pos %d\n",
4635 debugstr_w(strIn), p - strIn + 1);
4636 return DISP_E_TYPEMISMATCH;
4639 /**********************************************************************
4640 * DosDateTimeToVariantTime [OLEAUT32.14]
4641 * Convert dos representation of time to the date and time representation
4642 * stored in a variant.
4644 INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4645 DATE *pvtime)
4647 struct tm t;
4649 TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
4651 t.tm_sec = (wDosTime & 0x001f) * 2;
4652 t.tm_min = (wDosTime & 0x07e0) >> 5;
4653 t.tm_hour = (wDosTime & 0xf800) >> 11;
4655 t.tm_mday = (wDosDate & 0x001f);
4656 t.tm_mon = (wDosDate & 0x01e0) >> 5;
4657 t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
4659 return TmToDATE( &t, pvtime );
4663 /**********************************************************************
4664 * VarParseNumFromStr [OLEAUT32.46]
4666 HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
4667 NUMPARSE * pnumprs, BYTE * rgbDig)
4669 int i,lastent=0;
4670 int cDig;
4671 BOOL foundNum=FALSE;
4673 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
4674 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
4676 /* The other struct components are to be set by us */
4677 memset(rgbDig,0,pnumprs->cDig);
4679 /* FIXME: Just patching some values in */
4680 pnumprs->nPwr10 = 0;
4681 pnumprs->nBaseShift = 0;
4682 pnumprs->cchUsed = lastent;
4683 pnumprs->dwOutFlags = NUMPRS_DECIMAL;
4685 cDig = 0;
4686 for (i=0; strIn[i] ;i++) {
4687 if ((strIn[i]>='0') && (strIn[i]<='9')) {
4688 foundNum = TRUE;
4689 if (pnumprs->cDig > cDig) {
4690 *(rgbDig++)=strIn[i]-'0';
4691 cDig++;
4692 lastent = i;
4694 } else if ((strIn[i]=='-') && (foundNum==FALSE)) {
4695 pnumprs->dwOutFlags |= NUMPRS_NEG;
4698 pnumprs->cDig = cDig;
4699 TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags);
4700 return S_OK;
4704 /**********************************************************************
4705 * VarNumFromParseNum [OLEAUT32.47]
4707 HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
4708 ULONG dwVtBits, VARIANT * pvar)
4710 DWORD xint;
4711 int i;
4712 FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
4714 xint = 0;
4715 for (i=0;i<pnumprs->cDig;i++)
4716 xint = xint*10 + rgbDig[i];
4718 if (pnumprs->dwOutFlags & NUMPRS_NEG) {
4719 xint = xint * -1;
4722 VariantInit(pvar);
4723 if (dwVtBits & VTBIT_I4) {
4724 V_VT(pvar) = VT_I4;
4725 V_UNION(pvar,intVal) = xint;
4726 return S_OK;
4728 if (dwVtBits & VTBIT_R8) {
4729 V_VT(pvar) = VT_R8;
4730 V_UNION(pvar,dblVal) = xint;
4731 return S_OK;
4733 if (dwVtBits & VTBIT_R4) {
4734 V_VT(pvar) = VT_R4;
4735 V_UNION(pvar,fltVal) = xint;
4736 return S_OK;
4738 if (dwVtBits & VTBIT_I2) {
4739 V_VT(pvar) = VT_I2;
4740 V_UNION(pvar,iVal) = xint;
4741 return S_OK;
4743 /* FIXME: Currency should be from a double */
4744 if (dwVtBits & VTBIT_CY) {
4745 V_VT(pvar) = VT_CY;
4746 TRACE("Calculated currency is xint=%ld\n", xint);
4747 VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4748 TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar,cyVal).s.Hi, V_UNION(pvar,cyVal).s.Lo);
4749 return VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4752 FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint);
4753 return E_FAIL;
4757 /**********************************************************************
4758 * VarFormatDateTime [OLEAUT32.97]
4760 HRESULT WINAPI VarFormatDateTime(LPVARIANT var, INT format, ULONG dwFlags, BSTR *out)
4762 FIXME("%p %d %lx %p\n", var, format, dwFlags, out);
4763 return E_NOTIMPL;
4766 /**********************************************************************
4767 * VarFormatCurrency [OLEAUT32.127]
4769 HRESULT WINAPI VarFormatCurrency(LPVARIANT var, INT digits, INT lead, INT paren, INT group, ULONG dwFlags, BSTR *out)
4771 FIXME("%p %d %d %d %d %lx %p\n", var, digits, lead, paren, group, dwFlags, out);
4772 return E_NOTIMPL;
4775 /**********************************************************************
4776 * VariantTimeToDosDateTime [OLEAUT32.13]
4777 * Convert variant representation of time to the date and time representation
4778 * stored in dos.
4780 INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
4782 struct tm t;
4783 *wDosTime = 0;
4784 *wDosDate = 0;
4786 TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate, *wDosTime, &pvtime );
4788 if (DateToTm(pvtime, 0, &t) < 0) return 0;
4790 *wDosTime = *wDosTime | (t.tm_sec / 2);
4791 *wDosTime = *wDosTime | (t.tm_min << 5);
4792 *wDosTime = *wDosTime | (t.tm_hour << 11);
4794 *wDosDate = *wDosDate | t.tm_mday ;
4795 *wDosDate = *wDosDate | t.tm_mon << 5;
4796 *wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
4798 return 1;
4802 /***********************************************************************
4803 * SystemTimeToVariantTime [OLEAUT32.184]
4805 HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime, double *pvtime )
4807 struct tm t;
4809 TRACE(" %d/%d/%d %d:%d:%d\n",
4810 lpSystemTime->wMonth, lpSystemTime->wDay,
4811 lpSystemTime->wYear, lpSystemTime->wHour,
4812 lpSystemTime->wMinute, lpSystemTime->wSecond);
4814 if (lpSystemTime->wYear >= 1900)
4816 t.tm_sec = lpSystemTime->wSecond;
4817 t.tm_min = lpSystemTime->wMinute;
4818 t.tm_hour = lpSystemTime->wHour;
4820 t.tm_mday = lpSystemTime->wDay;
4821 t.tm_mon = lpSystemTime->wMonth - 1; /* tm_mon is 0..11, wMonth is 1..12 */
4822 t.tm_year = lpSystemTime->wYear;
4824 return TmToDATE( &t, pvtime );
4826 else
4828 double tmpDate;
4829 long firstDayOfNextYear;
4830 long thisDay;
4831 long leftInYear;
4832 long result;
4834 double decimalPart = 0.0;
4836 t.tm_sec = lpSystemTime->wSecond;
4837 t.tm_min = lpSystemTime->wMinute;
4838 t.tm_hour = lpSystemTime->wHour;
4840 /* Step year forward the same number of years before 1900 */
4841 t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
4842 t.tm_mon = lpSystemTime->wMonth - 1;
4843 t.tm_mday = lpSystemTime->wDay;
4845 /* Calculate date */
4846 TmToDATE( &t, pvtime );
4848 thisDay = (double) floor( *pvtime );
4849 decimalPart = fmod( *pvtime, thisDay );
4851 /* Now, calculate the same time for the first of Jan that year */
4852 t.tm_mon = 0;
4853 t.tm_mday = 1;
4854 t.tm_sec = 0;
4855 t.tm_min = 0;
4856 t.tm_hour = 0;
4857 t.tm_year = t.tm_year+1;
4858 TmToDATE( &t, &tmpDate );
4859 firstDayOfNextYear = (long) floor(tmpDate);
4861 /* Finally since we know the size of the year, subtract the two to get
4862 remaining time in the year */
4863 leftInYear = firstDayOfNextYear - thisDay;
4865 /* Now we want full years up to the year in question, and remainder of year
4866 of the year in question */
4867 if (isleap(lpSystemTime->wYear) ) {
4868 TRACE("Extra day due to leap year\n");
4869 result = 2.0 - ((firstDayOfNextYear - 366) + leftInYear - 2.0);
4870 } else {
4871 result = 2.0 - ((firstDayOfNextYear - 365) + leftInYear - 2.0);
4873 *pvtime = (double) result + decimalPart;
4874 TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime, firstDayOfNextYear, thisDay, leftInYear);
4876 return 1;
4879 return 0;
4882 /***********************************************************************
4883 * VariantTimeToSystemTime [OLEAUT32.185]
4885 HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME lpSystemTime )
4887 double t = 0, timeofday = 0;
4889 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4890 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4892 /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4893 static const BYTE Month_Code[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4894 static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4896 /* The Century_Code is used to find the Day of the Week */
4897 static const BYTE Century_Code[] = {0, 6, 4, 2};
4899 struct tm r;
4901 TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime);
4903 if (vtime >= 0)
4906 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4908 lpSystemTime->wSecond = r.tm_sec;
4909 lpSystemTime->wMinute = r.tm_min;
4910 lpSystemTime->wHour = r.tm_hour;
4911 lpSystemTime->wDay = r.tm_mday;
4912 lpSystemTime->wMonth = r.tm_mon;
4914 if (lpSystemTime->wMonth == 12)
4915 lpSystemTime->wMonth = 1;
4916 else
4917 lpSystemTime->wMonth++;
4919 lpSystemTime->wYear = r.tm_year;
4921 else
4923 vtime = -1*vtime;
4925 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4927 lpSystemTime->wSecond = r.tm_sec;
4928 lpSystemTime->wMinute = r.tm_min;
4929 lpSystemTime->wHour = r.tm_hour;
4931 lpSystemTime->wMonth = 13 - r.tm_mon;
4933 if (lpSystemTime->wMonth == 1)
4934 lpSystemTime->wMonth = 12;
4935 else
4936 lpSystemTime->wMonth--;
4938 lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
4940 if (!isleap(lpSystemTime->wYear) )
4941 lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
4942 else
4943 lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
4948 if (!isleap(lpSystemTime->wYear))
4951 (Century_Code+Month_Code+Year_Code+Day) % 7
4953 The century code repeats every 400 years , so the array
4954 works out like this,
4956 Century_Code[0] is for 16th/20th Centry
4957 Century_Code[1] is for 17th/21th Centry
4958 Century_Code[2] is for 18th/22th Centry
4959 Century_Code[3] is for 19th/23th Centry
4961 The year code is found with the formula (year + (year / 4))
4962 the "year" must be between 0 and 99 .
4964 The Month Code (Month_Code[1]) starts with January and
4965 ends with December.
4968 lpSystemTime->wDayOfWeek = (
4969 Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
4970 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4971 Month_Code[lpSystemTime->wMonth]+
4972 lpSystemTime->wDay) % 7;
4974 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4975 else lpSystemTime->wDayOfWeek -= 1;
4977 else
4979 lpSystemTime->wDayOfWeek = (
4980 Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
4981 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4982 Month_Code_LY[lpSystemTime->wMonth]+
4983 lpSystemTime->wDay) % 7;
4985 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4986 else lpSystemTime->wDayOfWeek -= 1;
4989 t = floor(vtime);
4990 timeofday = vtime - t;
4992 lpSystemTime->wMilliseconds = (timeofday
4993 - lpSystemTime->wHour*(1/24)
4994 - lpSystemTime->wMinute*(1/1440)
4995 - lpSystemTime->wSecond*(1/86400) )*(1/5184000);
4997 return 1;
5000 /***********************************************************************
5001 * VarUdateFromDate [OLEAUT32.331]
5003 HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
5005 HRESULT i = 0;
5006 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
5007 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
5009 TRACE("DATE = %f\n", (double)datein);
5010 i = VariantTimeToSystemTime(datein, &(pudateout->st) );
5012 if (i)
5014 pudateout->wDayOfYear = 0;
5016 if (isleap(pudateout->st.wYear))
5018 for (i =1; i<pudateout->st.wMonth; i++)
5019 pudateout->wDayOfYear += Days_Per_Month[i];
5021 else
5023 for (i =1; i<pudateout->st.wMonth; i++)
5024 pudateout->wDayOfYear += Days_Per_Month_LY[i];
5027 pudateout->wDayOfYear += pudateout->st.wDay;
5028 dwFlags = 0; /*VAR_VALIDDATE*/
5030 else dwFlags = 0;
5032 return i;
5035 /***********************************************************************
5036 * VarDateFromUdate [OLEAUT32.330]
5038 HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
5039 ULONG dwFlags, DATE *datein)
5041 HRESULT i;
5042 double t = 0;
5043 TRACE(" %d/%d/%d %d:%d:%d\n",
5044 pudateout->st.wMonth, pudateout->st.wDay,
5045 pudateout->st.wYear, pudateout->st.wHour,
5046 pudateout->st.wMinute, pudateout->st.wSecond);
5049 i = SystemTimeToVariantTime(&(pudateout->st), &t);
5050 *datein = t;
5052 if (i) return S_OK;
5053 else return E_INVALIDARG;
5057 /**********************************************************************
5058 * VarBstrCmp [OLEAUT32.314]
5060 * flags can be:
5061 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
5062 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
5065 HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
5067 INT r;
5069 TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
5071 /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
5072 if((!left) || (!right)) {
5074 if (!left && (!right || *right==0)) return VARCMP_EQ;
5075 else if (!right && (!left || *left==0)) return VARCMP_EQ;
5076 else return VARCMP_NULL;
5079 if(flags&NORM_IGNORECASE)
5080 r = lstrcmpiW(left,right);
5081 else
5082 r = lstrcmpW(left,right);
5084 if(r<0)
5085 return VARCMP_LT;
5086 if(r>0)
5087 return VARCMP_GT;
5089 return VARCMP_EQ;
5092 /**********************************************************************
5093 * VarBstrCat [OLEAUT32.313]
5095 HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
5097 BSTR result;
5098 int size = 0;
5100 TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
5102 /* On Windows, NULL parms are still handled (as empty strings) */
5103 if (left) size=size + lstrlenW(left);
5104 if (right) size=size + lstrlenW(right);
5106 if (out) {
5107 result = SysAllocStringLen(NULL, size);
5108 *out = result;
5109 if (left) lstrcatW(result,left);
5110 if (right) lstrcatW(result,right);
5111 TRACE("result = %s, [%p]\n", debugstr_w(result), result);
5113 return S_OK;
5116 /**********************************************************************
5117 * VarCat [OLEAUT32.318]
5119 HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
5121 /* Should we VariantClear out? */
5122 /* Can we handle array, vector, by ref etc. */
5123 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL &&
5124 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
5126 V_VT(out) = VT_NULL;
5127 return S_OK;
5130 if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR)
5132 V_VT(out) = VT_BSTR;
5133 VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out));
5134 return S_OK;
5136 if (V_VT(left) == VT_BSTR) {
5137 VARIANT bstrvar;
5138 HRESULT hres;
5140 V_VT(out) = VT_BSTR;
5141 hres = VariantChangeTypeEx(&bstrvar,right,0,0,VT_BSTR);
5142 if (hres) {
5143 FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right));
5144 return hres;
5146 VarBstrCat (V_BSTR(left), V_BSTR(&bstrvar), &V_BSTR(out));
5147 return S_OK;
5149 if (V_VT(right) == VT_BSTR) {
5150 VARIANT bstrvar;
5151 HRESULT hres;
5153 V_VT(out) = VT_BSTR;
5154 hres = VariantChangeTypeEx(&bstrvar,left,0,0,VT_BSTR);
5155 if (hres) {
5156 FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right));
5157 return hres;
5159 VarBstrCat (V_BSTR(&bstrvar), V_BSTR(right), &V_BSTR(out));
5160 return S_OK;
5162 FIXME ("types %d / %d not supported\n",V_VT(left)&VT_TYPEMASK, V_VT(right)&VT_TYPEMASK);
5163 return S_OK;
5166 /**********************************************************************
5167 * VarCmp [OLEAUT32.176]
5169 * flags can be:
5170 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
5171 * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
5174 HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
5178 BOOL lOk = TRUE;
5179 BOOL rOk = TRUE;
5180 LONGLONG lVal = -1;
5181 LONGLONG rVal = -1;
5182 VARIANT rv,lv;
5183 DWORD xmask;
5184 HRESULT rc;
5186 VariantInit(&lv);VariantInit(&rv);
5187 V_VT(right) &= ~0x8000; /* hack since we sometime get this flag. */
5188 V_VT(left) &= ~0x8000; /* hack since we sometime get this flag. */
5190 TRACE("Left Var:\n");
5191 dump_Variant(left);
5192 TRACE("Right Var:\n");
5193 dump_Variant(right);
5195 /* If either are null, then return VARCMP_NULL */
5196 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL ||
5197 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
5198 return VARCMP_NULL;
5200 /* Strings - use VarBstrCmp */
5201 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
5202 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
5203 return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags);
5206 xmask = (1<<(V_VT(left)&VT_TYPEMASK))|(1<<(V_VT(right)&VT_TYPEMASK));
5207 if (xmask & (1<<VT_R8)) {
5208 rc = VariantChangeType(&lv,left,0,VT_R8);
5209 if (FAILED(rc)) return rc;
5210 rc = VariantChangeType(&rv,right,0,VT_R8);
5211 if (FAILED(rc)) return rc;
5213 if (V_R8(&lv) == V_R8(&rv)) return VARCMP_EQ;
5214 if (V_R8(&lv) < V_R8(&rv)) return VARCMP_LT;
5215 if (V_R8(&lv) > V_R8(&rv)) return VARCMP_GT;
5216 return E_FAIL; /* can't get here */
5218 if (xmask & (1<<VT_R4)) {
5219 rc = VariantChangeType(&lv,left,0,VT_R4);
5220 if (FAILED(rc)) return rc;
5221 rc = VariantChangeType(&rv,right,0,VT_R4);
5222 if (FAILED(rc)) return rc;
5224 if (V_R4(&lv) == V_R4(&rv)) return VARCMP_EQ;
5225 if (V_R4(&lv) < V_R4(&rv)) return VARCMP_LT;
5226 if (V_R4(&lv) > V_R4(&rv)) return VARCMP_GT;
5227 return E_FAIL; /* can't get here */
5230 /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
5231 Use LONGLONG to maximize ranges */
5232 lOk = TRUE;
5233 switch (V_VT(left)&VT_TYPEMASK) {
5234 case VT_I1 : lVal = V_UNION(left,cVal); break;
5235 case VT_I2 : lVal = V_UNION(left,iVal); break;
5236 case VT_I4 : lVal = V_UNION(left,lVal); break;
5237 case VT_INT : lVal = V_UNION(left,lVal); break;
5238 case VT_UI1 : lVal = V_UNION(left,bVal); break;
5239 case VT_UI2 : lVal = V_UNION(left,uiVal); break;
5240 case VT_UI4 : lVal = V_UNION(left,ulVal); break;
5241 case VT_UINT : lVal = V_UNION(left,ulVal); break;
5242 case VT_BOOL : lVal = V_UNION(left,boolVal); break;
5243 default: lOk = FALSE;
5246 rOk = TRUE;
5247 switch (V_VT(right)&VT_TYPEMASK) {
5248 case VT_I1 : rVal = V_UNION(right,cVal); break;
5249 case VT_I2 : rVal = V_UNION(right,iVal); break;
5250 case VT_I4 : rVal = V_UNION(right,lVal); break;
5251 case VT_INT : rVal = V_UNION(right,lVal); break;
5252 case VT_UI1 : rVal = V_UNION(right,bVal); break;
5253 case VT_UI2 : rVal = V_UNION(right,uiVal); break;
5254 case VT_UI4 : rVal = V_UNION(right,ulVal); break;
5255 case VT_UINT : rVal = V_UNION(right,ulVal); break;
5256 case VT_BOOL : rVal = V_UNION(right,boolVal); break;
5257 default: rOk = FALSE;
5260 if (lOk && rOk) {
5261 if (lVal < rVal) {
5262 return VARCMP_LT;
5263 } else if (lVal > rVal) {
5264 return VARCMP_GT;
5265 } else {
5266 return VARCMP_EQ;
5270 /* Strings - use VarBstrCmp */
5271 if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
5272 (V_VT(right)&VT_TYPEMASK) == VT_DATE) {
5274 if (floor(V_UNION(left,date)) == floor(V_UNION(right,date))) {
5275 /* Due to floating point rounding errors, calculate varDate in whole numbers) */
5276 double wholePart = 0.0;
5277 double leftR;
5278 double rightR;
5280 /* Get the fraction * 24*60*60 to make it into whole seconds */
5281 wholePart = (double) floor( V_UNION(left,date) );
5282 if (wholePart == 0) wholePart = 1;
5283 leftR = floor(fmod( V_UNION(left,date), wholePart ) * (24*60*60));
5285 wholePart = (double) floor( V_UNION(right,date) );
5286 if (wholePart == 0) wholePart = 1;
5287 rightR = floor(fmod( V_UNION(right,date), wholePart ) * (24*60*60));
5289 if (leftR < rightR) {
5290 return VARCMP_LT;
5291 } else if (leftR > rightR) {
5292 return VARCMP_GT;
5293 } else {
5294 return VARCMP_EQ;
5297 } else if (V_UNION(left,date) < V_UNION(right,date)) {
5298 return VARCMP_LT;
5299 } else if (V_UNION(left,date) > V_UNION(right,date)) {
5300 return VARCMP_GT;
5303 FIXME("VarCmp partial implementation, doesnt support vt 0x%x / 0x%x\n",V_VT(left), V_VT(right));
5304 return E_FAIL;
5307 /**********************************************************************
5308 * VarAnd [OLEAUT32.142]
5311 HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5313 HRESULT rc = E_FAIL;
5315 TRACE("Left Var:\n");
5316 dump_Variant(left);
5317 TRACE("Right Var:\n");
5318 dump_Variant(right);
5320 if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5321 (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5323 V_VT(result) = VT_BOOL;
5324 if (V_BOOL(left) && V_BOOL(right)) {
5325 V_BOOL(result) = VARIANT_TRUE;
5326 } else {
5327 V_BOOL(result) = VARIANT_FALSE;
5329 rc = S_OK;
5331 } else {
5332 /* Integers */
5333 BOOL lOk = TRUE;
5334 BOOL rOk = TRUE;
5335 LONGLONG lVal = -1;
5336 LONGLONG rVal = -1;
5337 LONGLONG res = -1;
5338 int resT = 0; /* Testing has shown I2 & I2 == I2, all else
5339 becomes I4, even unsigned ints (incl. UI2) */
5341 lOk = TRUE;
5342 switch (V_VT(left)&VT_TYPEMASK) {
5343 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
5344 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
5345 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5346 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5347 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
5348 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5349 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5350 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5351 default: lOk = FALSE;
5354 rOk = TRUE;
5355 switch (V_VT(right)&VT_TYPEMASK) {
5356 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
5357 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
5358 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5359 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5360 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
5361 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5362 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5363 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5364 default: rOk = FALSE;
5367 if (lOk && rOk) {
5368 res = (lVal & rVal);
5369 V_VT(result) = resT;
5370 switch (resT) {
5371 case VT_I2 : V_UNION(result,iVal) = res; break;
5372 case VT_I4 : V_UNION(result,lVal) = res; break;
5373 default:
5374 FIXME("Unexpected result variant type %x\n", resT);
5375 V_UNION(result,lVal) = res;
5377 rc = S_OK;
5379 } else {
5380 FIXME("VarAnd stub\n");
5384 TRACE("rc=%d, Result:\n", (int) rc);
5385 dump_Variant(result);
5386 return rc;
5389 /**********************************************************************
5390 * VarAdd [OLEAUT32.141]
5391 * FIXME: From MSDN: If ... Then
5392 * Both expressions are of the string type Concatenated.
5393 * One expression is a string type and the other a character Addition.
5394 * One expression is numeric and the other is a string Addition.
5395 * Both expressions are numeric Addition.
5396 * Either expression is NULL NULL is returned.
5397 * Both expressions are empty Integer subtype is returned.
5400 HRESULT WINAPI VarAdd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5402 HRESULT rc = E_FAIL;
5404 TRACE("Left Var:\n");
5405 dump_Variant(left);
5406 TRACE("Right Var:\n");
5407 dump_Variant(right);
5409 if ((V_VT(left)&VT_TYPEMASK) == VT_EMPTY)
5410 return VariantCopy(result,right);
5412 if ((V_VT(right)&VT_TYPEMASK) == VT_EMPTY)
5413 return VariantCopy(result,left);
5415 if (((V_VT(left)&VT_TYPEMASK) == VT_R8) || ((V_VT(right)&VT_TYPEMASK) == VT_R8)) {
5416 BOOL lOk = TRUE;
5417 BOOL rOk = TRUE;
5418 double lVal = -1;
5419 double rVal = -1;
5420 double res = -1;
5422 lOk = TRUE;
5423 switch (V_VT(left)&VT_TYPEMASK) {
5424 case VT_I1 : lVal = V_UNION(left,cVal); break;
5425 case VT_I2 : lVal = V_UNION(left,iVal); break;
5426 case VT_I4 : lVal = V_UNION(left,lVal); break;
5427 case VT_INT : lVal = V_UNION(left,lVal); break;
5428 case VT_UI1 : lVal = V_UNION(left,bVal); break;
5429 case VT_UI2 : lVal = V_UNION(left,uiVal); break;
5430 case VT_UI4 : lVal = V_UNION(left,ulVal); break;
5431 case VT_UINT : lVal = V_UNION(left,ulVal); break;
5432 case VT_R4 : lVal = V_UNION(left,fltVal); break;
5433 case VT_R8 : lVal = V_UNION(left,dblVal); break;
5434 case VT_NULL : lVal = 0.0; break;
5435 default: lOk = FALSE;
5438 rOk = TRUE;
5439 switch (V_VT(right)&VT_TYPEMASK) {
5440 case VT_I1 : rVal = V_UNION(right,cVal); break;
5441 case VT_I2 : rVal = V_UNION(right,iVal); break;
5442 case VT_I4 : rVal = V_UNION(right,lVal); break;
5443 case VT_INT : rVal = V_UNION(right,lVal); break;
5444 case VT_UI1 : rVal = V_UNION(right,bVal); break;
5445 case VT_UI2 : rVal = V_UNION(right,uiVal); break;
5446 case VT_UI4 : rVal = V_UNION(right,ulVal); break;
5447 case VT_UINT : rVal = V_UNION(right,ulVal); break;
5448 case VT_R4 : rVal = V_UNION(right,fltVal);break;
5449 case VT_R8 : rVal = V_UNION(right,dblVal);break;
5450 case VT_NULL : rVal = 0.0; break;
5451 default: rOk = FALSE;
5454 if (lOk && rOk) {
5455 res = (lVal + rVal);
5456 V_VT(result) = VT_R8;
5457 V_UNION(result,dblVal) = res;
5458 rc = S_OK;
5459 } else {
5460 FIXME("Unhandled type pair %d / %d in double addition.\n",
5461 (V_VT(left)&VT_TYPEMASK),
5462 (V_VT(right)&VT_TYPEMASK)
5465 return rc;
5468 /* Handle strings as concat */
5469 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
5470 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
5471 V_VT(result) = VT_BSTR;
5472 rc = VarBstrCat(V_BSTR(left), V_BSTR(right), &V_BSTR(result));
5473 } else {
5475 /* Integers */
5476 BOOL lOk = TRUE;
5477 BOOL rOk = TRUE;
5478 LONGLONG lVal = -1;
5479 LONGLONG rVal = -1;
5480 LONGLONG res = -1;
5481 int resT = 0; /* Testing has shown I2 + I2 == I2, all else
5482 becomes I4 */
5484 lOk = TRUE;
5485 switch (V_VT(left)&VT_TYPEMASK) {
5486 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
5487 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
5488 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5489 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5490 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
5491 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5492 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5493 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5494 case VT_NULL : lVal = 0; resT = VT_I4; break;
5495 default: lOk = FALSE;
5498 rOk = TRUE;
5499 switch (V_VT(right)&VT_TYPEMASK) {
5500 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
5501 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
5502 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5503 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5504 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
5505 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5506 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5507 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5508 case VT_NULL : rVal = 0; resT=VT_I4; break;
5509 default: rOk = FALSE;
5512 if (lOk && rOk) {
5513 res = (lVal + rVal);
5514 V_VT(result) = resT;
5515 switch (resT) {
5516 case VT_I2 : V_UNION(result,iVal) = res; break;
5517 case VT_I4 : V_UNION(result,lVal) = res; break;
5518 default:
5519 FIXME("Unexpected result variant type %x\n", resT);
5520 V_UNION(result,lVal) = res;
5522 rc = S_OK;
5524 } else {
5525 FIXME("unimplemented part (0x%x + 0x%x)\n",V_VT(left), V_VT(right));
5529 TRACE("rc=%d, Result:\n", (int) rc);
5530 dump_Variant(result);
5531 return rc;
5534 /**********************************************************************
5535 * VarMul [OLEAUT32.156]
5538 HRESULT WINAPI VarMul(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5540 HRESULT rc = E_FAIL;
5541 VARTYPE lvt,rvt,resvt;
5542 VARIANT lv,rv;
5543 BOOL found;
5545 TRACE("left: ");dump_Variant(left);
5546 TRACE("right: ");dump_Variant(right);
5548 VariantInit(&lv);VariantInit(&rv);
5549 lvt = V_VT(left)&VT_TYPEMASK;
5550 rvt = V_VT(right)&VT_TYPEMASK;
5551 found = FALSE;resvt=VT_VOID;
5552 if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
5553 found = TRUE;
5554 resvt = VT_R8;
5556 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)))) {
5557 found = TRUE;
5558 resvt = VT_I4;
5560 if (!found) {
5561 FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
5562 return E_FAIL;
5564 rc = VariantChangeType(&lv, left, 0, resvt);
5565 if (FAILED(rc)) {
5566 FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
5567 return rc;
5569 rc = VariantChangeType(&rv, right, 0, resvt);
5570 if (FAILED(rc)) {
5571 FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
5572 return rc;
5574 switch (resvt) {
5575 case VT_R8:
5576 V_VT(result) = resvt;
5577 V_R8(result) = V_R8(&lv) * V_R8(&rv);
5578 rc = S_OK;
5579 break;
5580 case VT_I4:
5581 V_VT(result) = resvt;
5582 V_I4(result) = V_I4(&lv) * V_I4(&rv);
5583 rc = S_OK;
5584 break;
5586 TRACE("rc=%d, Result:\n", (int) rc);
5587 dump_Variant(result);
5588 return rc;
5591 /**********************************************************************
5592 * VarDiv [OLEAUT32.143]
5595 HRESULT WINAPI VarDiv(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5597 HRESULT rc = E_FAIL;
5598 VARTYPE lvt,rvt,resvt;
5599 VARIANT lv,rv;
5600 BOOL found;
5602 TRACE("left: ");dump_Variant(left);
5603 TRACE("right: ");dump_Variant(right);
5605 VariantInit(&lv);VariantInit(&rv);
5606 lvt = V_VT(left)&VT_TYPEMASK;
5607 rvt = V_VT(right)&VT_TYPEMASK;
5608 found = FALSE;resvt = VT_VOID;
5609 if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
5610 found = TRUE;
5611 resvt = VT_R8;
5613 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)))) {
5614 found = TRUE;
5615 resvt = VT_I4;
5617 if (!found) {
5618 FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
5619 return E_FAIL;
5621 rc = VariantChangeType(&lv, left, 0, resvt);
5622 if (FAILED(rc)) {
5623 FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
5624 return rc;
5626 rc = VariantChangeType(&rv, right, 0, resvt);
5627 if (FAILED(rc)) {
5628 FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
5629 return rc;
5631 switch (resvt) {
5632 case VT_R8:
5633 V_VT(result) = resvt;
5634 V_R8(result) = V_R8(&lv) / V_R8(&rv);
5635 rc = S_OK;
5636 break;
5637 case VT_I4:
5638 V_VT(result) = resvt;
5639 V_I4(result) = V_I4(&lv) / V_I4(&rv);
5640 rc = S_OK;
5641 break;
5643 TRACE("rc=%d, Result:\n", (int) rc);
5644 dump_Variant(result);
5645 return rc;
5648 /**********************************************************************
5649 * VarSub [OLEAUT32.159]
5652 HRESULT WINAPI VarSub(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5654 HRESULT rc = E_FAIL;
5655 VARTYPE lvt,rvt,resvt;
5656 VARIANT lv,rv;
5657 BOOL found;
5659 TRACE("left: ");dump_Variant(left);
5660 TRACE("right: ");dump_Variant(right);
5662 VariantInit(&lv);VariantInit(&rv);
5663 lvt = V_VT(left)&VT_TYPEMASK;
5664 rvt = V_VT(right)&VT_TYPEMASK;
5665 found = FALSE;resvt = VT_VOID;
5666 if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
5667 found = TRUE;
5668 resvt = VT_R8;
5670 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)))) {
5671 found = TRUE;
5672 resvt = VT_I4;
5674 if (!found) {
5675 FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
5676 return E_FAIL;
5678 rc = VariantChangeType(&lv, left, 0, resvt);
5679 if (FAILED(rc)) {
5680 FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
5681 return rc;
5683 rc = VariantChangeType(&rv, right, 0, resvt);
5684 if (FAILED(rc)) {
5685 FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
5686 return rc;
5688 switch (resvt) {
5689 case VT_R8:
5690 V_VT(result) = resvt;
5691 V_R8(result) = V_R8(&lv) - V_R8(&rv);
5692 rc = S_OK;
5693 break;
5694 case VT_I4:
5695 V_VT(result) = resvt;
5696 V_I4(result) = V_I4(&lv) - V_I4(&rv);
5697 rc = S_OK;
5698 break;
5700 TRACE("rc=%d, Result:\n", (int) rc);
5701 dump_Variant(result);
5702 return rc;
5705 /**********************************************************************
5706 * VarOr [OLEAUT32.157]
5709 HRESULT WINAPI VarOr(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5711 HRESULT rc = E_FAIL;
5713 TRACE("Left Var:\n");
5714 dump_Variant(left);
5715 TRACE("Right Var:\n");
5716 dump_Variant(right);
5718 if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5719 (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5721 V_VT(result) = VT_BOOL;
5722 if (V_BOOL(left) || V_BOOL(right)) {
5723 V_BOOL(result) = VARIANT_TRUE;
5724 } else {
5725 V_BOOL(result) = VARIANT_FALSE;
5727 rc = S_OK;
5729 } else {
5730 /* Integers */
5731 BOOL lOk = TRUE;
5732 BOOL rOk = TRUE;
5733 LONGLONG lVal = -1;
5734 LONGLONG rVal = -1;
5735 LONGLONG res = -1;
5736 int resT = 0; /* Testing has shown I2 & I2 == I2, all else
5737 becomes I4, even unsigned ints (incl. UI2) */
5739 lOk = TRUE;
5740 switch (V_VT(left)&VT_TYPEMASK) {
5741 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
5742 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
5743 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5744 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5745 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
5746 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5747 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5748 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5749 default: lOk = FALSE;
5752 rOk = TRUE;
5753 switch (V_VT(right)&VT_TYPEMASK) {
5754 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
5755 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
5756 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5757 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5758 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
5759 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5760 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5761 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5762 default: rOk = FALSE;
5765 if (lOk && rOk) {
5766 res = (lVal | rVal);
5767 V_VT(result) = resT;
5768 switch (resT) {
5769 case VT_I2 : V_UNION(result,iVal) = res; break;
5770 case VT_I4 : V_UNION(result,lVal) = res; break;
5771 default:
5772 FIXME("Unexpected result variant type %x\n", resT);
5773 V_UNION(result,lVal) = res;
5775 rc = S_OK;
5777 } else {
5778 FIXME("unimplemented part\n");
5782 TRACE("rc=%d, Result:\n", (int) rc);
5783 dump_Variant(result);
5784 return rc;
5787 /**********************************************************************
5788 * VarNot [OLEAUT32.174]
5791 HRESULT WINAPI VarNot(LPVARIANT in, LPVARIANT result)
5793 HRESULT rc = E_FAIL;
5795 TRACE("Var In:\n");
5796 dump_Variant(in);
5798 if ((V_VT(in)&VT_TYPEMASK) == VT_BOOL) {
5800 V_VT(result) = VT_BOOL;
5801 if (V_BOOL(in)) {
5802 V_BOOL(result) = VARIANT_FALSE;
5803 } else {
5804 V_BOOL(result) = VARIANT_TRUE;
5806 rc = S_OK;
5808 } else {
5809 FIXME("VarNot stub\n");
5812 TRACE("rc=%d, Result:\n", (int) rc);
5813 dump_Variant(result);
5814 return rc;
5817 /**********************************************************************
5818 * VarTokenizeFormatString [OLEAUT32.140]
5820 * From investigation on W2K, a list is built up which is:
5822 * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
5823 * <token> - Insert appropriate token
5826 HRESULT WINAPI VarTokenizeFormatString(LPOLESTR format, LPBYTE rgbTok,
5827 int cbTok, int iFirstDay, int iFirstWeek,
5828 LCID lcid, int *pcbActual) {
5830 FORMATHDR *hdr;
5831 int realLen, formatLeft;
5832 BYTE *pData;
5833 LPSTR pFormatA, pStart;
5834 int checkStr;
5835 BOOL insertCopy = FALSE;
5836 LPSTR copyFrom = NULL;
5838 TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format), rgbTok, cbTok,
5839 iFirstDay, iFirstWeek);
5841 /* Big enough for header? */
5842 if (cbTok < sizeof(FORMATHDR)) {
5843 return TYPE_E_BUFFERTOOSMALL;
5846 /* Insert header */
5847 hdr = (FORMATHDR *) rgbTok;
5848 memset(hdr, 0x00, sizeof(FORMATHDR));
5849 hdr->hex3 = 0x03; /* No idea what these are */
5850 hdr->hex6 = 0x06;
5852 /* Start parsing string */
5853 realLen = sizeof(FORMATHDR);
5854 pData = rgbTok + realLen;
5855 pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5856 pStart = pFormatA;
5857 formatLeft = strlen(pFormatA);
5859 /* Work through the format */
5860 while (*pFormatA != 0x00) {
5862 checkStr = 0;
5863 while (checkStr>=0 && (formatTokens[checkStr].tokenSize != 0x00)) {
5864 if (formatLeft >= formatTokens[checkStr].tokenSize &&
5865 strncmp(formatTokens[checkStr].str, pFormatA,
5866 formatTokens[checkStr].tokenSize) == 0) {
5867 TRACE("match on '%s'\n", formatTokens[checkStr].str);
5869 /* Found Match! */
5871 /* If we have skipped chars, insert the copy */
5872 if (insertCopy == TRUE) {
5874 if ((realLen + 3) > cbTok) {
5875 HeapFree( GetProcessHeap(), 0, pFormatA );
5876 return TYPE_E_BUFFERTOOSMALL;
5878 insertCopy = FALSE;
5879 *pData = TOK_COPY;
5880 pData++;
5881 *pData = (BYTE)(copyFrom - pStart);
5882 pData++;
5883 *pData = (BYTE)(pFormatA - copyFrom);
5884 pData++;
5885 realLen = realLen + 3;
5889 /* Now insert the token itself */
5890 if ((realLen + 1) > cbTok) {
5891 HeapFree( GetProcessHeap(), 0, pFormatA );
5892 return TYPE_E_BUFFERTOOSMALL;
5894 *pData = formatTokens[checkStr].tokenId;
5895 pData = pData + 1;
5896 realLen = realLen + 1;
5898 pFormatA = pFormatA + formatTokens[checkStr].tokenSize;
5899 formatLeft = formatLeft - formatTokens[checkStr].tokenSize;
5900 checkStr = -1; /* Flag as found and break out of while loop */
5901 } else {
5902 checkStr++;
5906 /* Did we ever match a token? */
5907 if (checkStr != -1 && insertCopy == FALSE) {
5908 TRACE("No match - need to insert copy from %p [%p]\n", pFormatA, pStart);
5909 insertCopy = TRUE;
5910 copyFrom = pFormatA;
5911 } else if (checkStr != -1) {
5912 pFormatA = pFormatA + 1;
5917 /* Finally, if we have skipped chars, insert the copy */
5918 if (insertCopy == TRUE) {
5920 TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom, pStart, pFormatA);
5921 if ((realLen + 3) > cbTok) {
5922 HeapFree( GetProcessHeap(), 0, pFormatA );
5923 return TYPE_E_BUFFERTOOSMALL;
5925 insertCopy = FALSE;
5926 *pData = TOK_COPY;
5927 pData++;
5928 *pData = (BYTE)(copyFrom - pStart);
5929 pData++;
5930 *pData = (BYTE)(pFormatA - copyFrom);
5931 pData++;
5932 realLen = realLen + 3;
5935 /* Finally insert the terminator */
5936 if ((realLen + 1) > cbTok) {
5937 HeapFree( GetProcessHeap(), 0, pFormatA );
5938 return TYPE_E_BUFFERTOOSMALL;
5940 *pData++ = TOK_END;
5941 realLen = realLen + 1;
5943 /* Finally fill in the length */
5944 hdr->len = realLen;
5945 *pcbActual = realLen;
5947 #if 0
5948 { int i,j;
5949 for (i=0; i<realLen; i=i+0x10) {
5950 printf(" %4.4x : ", i);
5951 for (j=0; j<0x10 && (i+j < realLen); j++) {
5952 printf("%2.2x ", rgbTok[i+j]);
5954 printf("\n");
5957 #endif
5958 HeapFree( GetProcessHeap(), 0, pFormatA );
5960 return S_OK;
5963 /**********************************************************************
5964 * VarFormatFromTokens [OLEAUT32.139]
5965 * FIXME: No account of flags or iFirstDay etc
5967 HRESULT WINAPI VarFormatFromTokens(LPVARIANT varIn, LPOLESTR format,
5968 LPBYTE pbTokCur, ULONG dwFlags, BSTR *pbstrOut,
5969 LCID lcid) {
5971 FORMATHDR *hdr = (FORMATHDR *)pbTokCur;
5972 BYTE *pData = pbTokCur + sizeof (FORMATHDR);
5973 LPSTR pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5974 char output[BUFFER_MAX];
5975 char *pNextPos;
5976 int size, whichToken;
5977 VARIANTARG Variant;
5978 struct tm TM;
5982 TRACE("'%s', %p %lx %p only date support\n", pFormatA, pbTokCur, dwFlags, pbstrOut);
5983 TRACE("varIn:\n");
5984 dump_Variant(varIn);
5986 memset(output, 0x00, BUFFER_MAX);
5987 pNextPos = output;
5989 while (*pData != TOK_END && ((pData - pbTokCur) <= (hdr->len))) {
5991 TRACE("Output looks like : '%s'\n", output);
5993 /* Convert varient to appropriate data type */
5994 whichToken = 0;
5995 while ((formatTokens[whichToken].tokenSize != 0x00) &&
5996 (formatTokens[whichToken].tokenId != *pData)) {
5997 whichToken++;
6000 /* Use Variant local from here downwards as always correct type */
6001 if (formatTokens[whichToken].tokenSize > 0 &&
6002 formatTokens[whichToken].varTypeRequired != 0) {
6003 VariantInit( &Variant );
6004 if (Coerce( &Variant, lcid, dwFlags, varIn,
6005 formatTokens[whichToken].varTypeRequired ) != S_OK) {
6006 HeapFree( GetProcessHeap(), 0, pFormatA );
6007 return DISP_E_TYPEMISMATCH;
6008 } else if (formatTokens[whichToken].varTypeRequired == VT_DATE) {
6009 if( DateToTm( V_UNION(&Variant,date), dwFlags, &TM ) == FALSE ) {
6010 HeapFree( GetProcessHeap(), 0, pFormatA );
6011 return E_INVALIDARG;
6016 TRACE("Looking for match on token '%x'\n", *pData);
6017 switch (*pData) {
6018 case TOK_COPY:
6019 TRACE("Copy from %d for %d bytes\n", *(pData+1), *(pData+2));
6020 memcpy(pNextPos, &pFormatA[*(pData+1)], *(pData+2));
6021 pNextPos = pNextPos + *(pData+2);
6022 pData = pData + 3;
6023 break;
6025 case TOK_COLON :
6026 /* Get locale information - Time Separator */
6027 size = GetLocaleInfoA(lcid, LOCALE_STIME, NULL, 0);
6028 GetLocaleInfoA(lcid, LOCALE_STIME, pNextPos, size);
6029 TRACE("TOK_COLON Time separator is '%s'\n", pNextPos);
6030 pNextPos = pNextPos + size;
6031 pData = pData + 1;
6032 break;
6034 case TOK_SLASH :
6035 /* Get locale information - Date Separator */
6036 size = GetLocaleInfoA(lcid, LOCALE_SDATE, NULL, 0);
6037 GetLocaleInfoA(lcid, LOCALE_SDATE, pNextPos, size);
6038 TRACE("TOK_COLON Time separator is '%s'\n", pNextPos);
6039 pNextPos = pNextPos + size;
6040 pData = pData + 1;
6041 break;
6043 case TOK_d :
6044 sprintf(pNextPos, "%d", TM.tm_mday);
6045 pNextPos = pNextPos + strlen(pNextPos);
6046 pData = pData + 1;
6047 break;
6049 case TOK_dd :
6050 sprintf(pNextPos, "%2.2d", TM.tm_mday);
6051 pNextPos = pNextPos + strlen(pNextPos);
6052 pData = pData + 1;
6053 break;
6055 case TOK_w :
6056 sprintf(pNextPos, "%d", TM.tm_wday+1);
6057 pNextPos = pNextPos + strlen(pNextPos);
6058 pData = pData + 1;
6059 break;
6061 case TOK_m :
6062 sprintf(pNextPos, "%d", TM.tm_mon+1);
6063 pNextPos = pNextPos + strlen(pNextPos);
6064 pData = pData + 1;
6065 break;
6067 case TOK_mm :
6068 sprintf(pNextPos, "%2.2d", TM.tm_mon+1);
6069 pNextPos = pNextPos + strlen(pNextPos);
6070 pData = pData + 1;
6071 break;
6073 case TOK_q :
6074 sprintf(pNextPos, "%d", ((TM.tm_mon+1)/4)+1);
6075 pNextPos = pNextPos + strlen(pNextPos);
6076 pData = pData + 1;
6077 break;
6079 case TOK_y :
6080 sprintf(pNextPos, "%2.2d", TM.tm_yday+1);
6081 pNextPos = pNextPos + strlen(pNextPos);
6082 pData = pData + 1;
6083 break;
6085 case TOK_yy :
6086 sprintf(pNextPos, "%2.2d", TM.tm_year);
6087 pNextPos = pNextPos + strlen(pNextPos);
6088 pData = pData + 1;
6089 break;
6091 case TOK_yyyy :
6092 sprintf(pNextPos, "%4.4d", TM.tm_year);
6093 pNextPos = pNextPos + strlen(pNextPos);
6094 pData = pData + 1;
6095 break;
6097 case TOK_h :
6098 sprintf(pNextPos, "%d", TM.tm_hour);
6099 pNextPos = pNextPos + strlen(pNextPos);
6100 pData = pData + 1;
6101 break;
6103 case TOK_Hh :
6104 sprintf(pNextPos, "%2.2d", TM.tm_hour);
6105 pNextPos = pNextPos + strlen(pNextPos);
6106 pData = pData + 1;
6107 break;
6109 case TOK_N :
6110 sprintf(pNextPos, "%d", TM.tm_min);
6111 pNextPos = pNextPos + strlen(pNextPos);
6112 pData = pData + 1;
6113 break;
6115 case TOK_Nn :
6116 sprintf(pNextPos, "%2.2d", TM.tm_min);
6117 pNextPos = pNextPos + strlen(pNextPos);
6118 pData = pData + 1;
6119 break;
6121 case TOK_S :
6122 sprintf(pNextPos, "%d", TM.tm_sec);
6123 pNextPos = pNextPos + strlen(pNextPos);
6124 pData = pData + 1;
6125 break;
6127 case TOK_Ss :
6128 sprintf(pNextPos, "%2.2d", TM.tm_sec);
6129 pNextPos = pNextPos + strlen(pNextPos);
6130 pData = pData + 1;
6131 break;
6133 /* FIXME: To Do! */
6134 case TOK_ttttt :
6135 case TOK_AMsPM :
6136 case TOK_amspm :
6137 case TOK_AsP :
6138 case TOK_asp :
6139 case TOK_AMPM :
6140 case TOK_c :
6141 case TOK_ddd :
6142 case TOK_dddd :
6143 case TOK_ddddd :
6144 case TOK_dddddd :
6145 case TOK_ww :
6146 case TOK_mmm :
6147 case TOK_mmmm :
6148 default:
6149 FIXME("Unhandled token for VarFormat %d\n", *pData);
6150 HeapFree( GetProcessHeap(), 0, pFormatA );
6151 return E_INVALIDARG;
6156 *pbstrOut = StringDupAtoBstr( output );
6157 HeapFree( GetProcessHeap(), 0, pFormatA );
6158 return S_OK;
6161 /**********************************************************************
6162 * VarFormat [OLEAUT32.87]
6165 HRESULT WINAPI VarFormat(LPVARIANT varIn, LPOLESTR format,
6166 int firstDay, int firstWeek, ULONG dwFlags,
6167 BSTR *pbstrOut) {
6169 LPSTR pNewString = NULL;
6170 HRESULT rc = S_OK;
6172 TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
6173 debugstr_w(format), firstDay, firstWeek, dwFlags);
6174 TRACE("varIn:\n");
6175 dump_Variant(varIn);
6177 /* Note: Must Handle references type Variants (contain ptrs
6178 to values rather than values */
6180 /* Get format string */
6181 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
6183 /* FIXME: Handle some simple pre-definted format strings : */
6184 if (((V_VT(varIn)&VT_TYPEMASK) == VT_CY) && (lstrcmpiA(pNewString, "Currency") == 0)) {
6186 /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
6187 double curVal;
6190 /* Handle references type Variants (contain ptrs to values rather than values */
6191 if (V_VT(varIn)&VT_BYREF) {
6192 rc = VarR8FromCy(*(CY *)V_UNION(varIn,byref), &curVal);
6193 } else {
6194 rc = VarR8FromCy(V_UNION(varIn,cyVal), &curVal);
6197 if (rc == S_OK) {
6198 char tmpStr[BUFFER_MAX];
6199 sprintf(tmpStr, "%f", curVal);
6200 if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags, tmpStr, NULL, pBuffer, BUFFER_MAX) == 0) {
6201 return E_FAIL;
6202 } else {
6203 *pbstrOut = StringDupAtoBstr( pBuffer );
6207 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_DATE) {
6209 /* Attempt to do proper formatting! */
6210 int firstToken = -1;
6212 rc = VarTokenizeFormatString(format, pBuffer, sizeof(pBuffer), firstDay,
6213 firstWeek, GetUserDefaultLCID(), &firstToken);
6214 if (rc==S_OK) {
6215 rc = VarFormatFromTokens(varIn, format, pBuffer, dwFlags, pbstrOut, GetUserDefaultLCID());
6218 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_R8) {
6219 if (V_VT(varIn)&VT_BYREF) {
6220 sprintf(pBuffer, "%f", *V_UNION(varIn,pdblVal));
6221 } else {
6222 sprintf(pBuffer, "%f", V_UNION(varIn,dblVal));
6224 *pbstrOut = StringDupAtoBstr( pBuffer );
6225 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_I2) {
6226 if (V_VT(varIn)&VT_BYREF) {
6227 sprintf(pBuffer, "%d", *V_UNION(varIn,piVal));
6228 } else {
6229 sprintf(pBuffer, "%d", V_UNION(varIn,iVal));
6231 *pbstrOut = StringDupAtoBstr( pBuffer );
6232 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_BSTR) {
6233 if (V_VT(varIn)&VT_BYREF)
6234 *pbstrOut = SysAllocString( *V_UNION(varIn,pbstrVal) );
6235 else
6236 *pbstrOut = SysAllocString( V_UNION(varIn,bstrVal) );
6237 } else {
6238 FIXME("VarFormat: Unsupported format %d!\n", V_VT(varIn)&VT_TYPEMASK);
6239 *pbstrOut = StringDupAtoBstr( "??" );
6242 /* Free allocated storage */
6243 HeapFree( GetProcessHeap(), 0, pNewString );
6244 TRACE("result: '%s'\n", debugstr_w(*pbstrOut));
6245 return rc;
6248 /**********************************************************************
6249 * VarCyMulI4 [OLEAUT32.304]
6250 * Multiply currency value by integer
6252 HRESULT WINAPI VarCyMulI4(CY cyIn, LONG mulBy, CY *pcyOut) {
6254 double cyVal = 0;
6255 HRESULT rc = S_OK;
6257 rc = VarR8FromCy(cyIn, &cyVal);
6258 if (rc == S_OK) {
6259 rc = VarCyFromR8((cyVal * (double) mulBy), pcyOut);
6260 TRACE("Multiply %f by %ld = %f [%ld,%lu]\n", cyVal, mulBy, (cyVal * (double) mulBy),
6261 pcyOut->s.Hi, pcyOut->s.Lo);
6263 return rc;