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
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.
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.
49 #define NONAMELESSUNION
50 #define NONAMELESSSTRUCT
54 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(ole);
62 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
66 # define FLT_MAX MAXFLOAT
68 # error "Can't find #define for MAXFLOAT/FLT_MAX"
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
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
135 #define TOK_dddd 0x0b
136 #define TOK_ddddd 0x0c
137 #define TOK_dddddd 0x0d
143 #define TOK_mmmm 0x14
147 #define TOK_yyyy 0x18
154 #define TOK_ttttt 0x07
155 #define TOK_AMsPM 0x2f
156 #define TOK_amspm 0x32
159 #define TOK_AMPM 0x2e
161 typedef struct tagFORMATTOKEN {
168 typedef struct tagFORMATHDR {
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 )
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.
269 if( dwFlags & VAR_TIMEVALUEONLY )
271 /* Get time information only.
273 if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
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 )
292 HeapFree( GetProcessHeap(), 0, strDateTime );
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:
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]
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
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
336 * Returns TRUE if successful.
338 static BOOL TmToDATE( struct tm* pTm, DATE *pDateOut )
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.
352 if( (pTm->tm_year - 1900) >= 0 ) {
354 /* Add the number of days corresponding to
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
374 if( isleap( pTm->tm_year ) )
377 /* Add the number of days corresponding to
378 * the month. (remember tm_mon is 0..11)
380 switch( pTm->tm_mon )
386 *pDateOut += ( 59 + leapYear );
389 *pDateOut += ( 90 + leapYear );
392 *pDateOut += ( 120 + leapYear );
395 *pDateOut += ( 151 + leapYear );
398 *pDateOut += ( 181 + leapYear );
401 *pDateOut += ( 212 + leapYear );
404 *pDateOut += ( 243 + leapYear );
407 *pDateOut += ( 273 + leapYear );
410 *pDateOut += ( 304 + leapYear );
413 *pDateOut += ( 334 + leapYear );
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 fracionnal part
422 * of the DATE so seconds / number of seconds in a day.
428 *pDateOut += pTm->tm_hour / 24.0;
429 *pDateOut += pTm->tm_min / 1440.0;
430 *pDateOut += pTm->tm_sec / 86400.0;
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 */
464 wholePart = (double) floor( dateIn );
466 if( !(dwFlags & VAR_TIMEVALUEONLY) )
468 unsigned int nDay = 0;
470 double yearsSince1900 = 0;
472 /* Hard code dates smaller than January 1, 1900. */
475 pTm->tm_mon = 11; /* December as tm_mon is 0..11 */
478 dateIn = dateIn * -1.0; /* Ensure +ve for time calculation */
479 decimalPart = decimalPart * -1.0; /* Ensure +ve for time calculation */
486 /* Start at 1900, this is where the DATE time 0.0 starts.
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 ) )
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.
528 else if( nDay <= ( 59 + leapYear ) )
530 pTm->tm_mday = nDay - 31;
533 else if( nDay <= ( 90 + leapYear ) )
535 pTm->tm_mday = nDay - ( 59 + leapYear );
538 else if( nDay <= ( 120 + leapYear ) )
540 pTm->tm_mday = nDay - ( 90 + leapYear );
543 else if( nDay <= ( 151 + leapYear ) )
545 pTm->tm_mday = nDay - ( 120 + leapYear );
548 else if( nDay <= ( 181 + leapYear ) )
550 pTm->tm_mday = nDay - ( 151 + leapYear );
553 else if( nDay <= ( 212 + leapYear ) )
555 pTm->tm_mday = nDay - ( 181 + leapYear );
558 else if( nDay <= ( 243 + leapYear ) )
560 pTm->tm_mday = nDay - ( 212 + leapYear );
563 else if( nDay <= ( 273 + leapYear ) )
565 pTm->tm_mday = nDay - ( 243 + leapYear );
568 else if( nDay <= ( 304 + leapYear ) )
570 pTm->tm_mday = nDay - ( 273 + leapYear );
573 else if( nDay <= ( 334 + leapYear ) )
575 pTm->tm_mday = nDay - ( 304 + leapYear );
578 else if( nDay <= ( 365 + leapYear ) )
580 pTm->tm_mday = nDay - ( 334 + leapYear );
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);
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 )
612 switch( V_VT(parg) & VT_TYPEMASK )
615 size = sizeof(short);
627 size = sizeof(unsigned short);
630 size = sizeof(unsigned int);
633 size = sizeof(unsigned long);
636 size = sizeof(float);
639 size = sizeof(double);
645 size = sizeof(VARIANT_BOOL);
650 size = sizeof(void*);
655 case( VT_DECIMAL ): /* hmm, tricky, DECIMAL is only VT_BYREF */
657 FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK );
663 /******************************************************************************
664 * StringDupAtoBstr [INTERNAL]
667 static BSTR StringDupAtoBstr( char* strIn )
670 OLECHAR* pNewString = NULL;
671 UNICODE_STRING usBuffer;
673 RtlCreateUnicodeStringFromAsciiz( &usBuffer, strIn );
674 pNewString = usBuffer.Buffer;
676 bstr = SysAllocString( pNewString );
677 RtlFreeUnicodeString( &usBuffer );
681 /******************************************************************************
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;
692 /* Save the sign of the number
694 nSign = (d >= 0.0) ? 1 : -1;
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.
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 );
730 /* the decimals are exactly 1/2 so round according to
731 * the bEvenNumber flag.
735 roundedValue = floor( d );
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
760 pNewString = strdup( str );
762 strToken = strtok( pNewString, strOfCharToRemove );
763 while( strToken != NULL ) {
764 strcat( str, strToken );
765 strToken = strtok( NULL, strOfCharToRemove );
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;
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 ) {
819 strToken = strtok( NULL, " " );
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' )
850 if( bWhiteSpaceProcessed ||
851 bFirstSignProcessed ||
852 bFirstDigitsProcessed ||
853 bDecimalPointProcessed ||
854 bSecondDigitsProcessed ||
855 bExponentProcessed ||
856 bSecondSignProcessed ||
857 bThirdDigitsProcessed )
859 bValidRealString = FALSE;
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 ||
889 bValidRealString = FALSE;
891 bFirstSignProcessed = TRUE;
892 bWhiteSpaceProcessed = TRUE;
893 bFirstDigitsProcessed = TRUE;
894 bDecimalPointProcessed = TRUE;
895 bSecondDigitsProcessed = TRUE;
896 bSecondSignProcessed = TRUE;
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.
955 /* If DecimalPoint...
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;
977 if( bExponentProcessed ||
978 bSecondSignProcessed ||
979 bThirdDigitsProcessed ||
982 bValidRealString = FALSE;
984 bFirstSignProcessed = TRUE;
985 bWhiteSpaceProcessed = TRUE;
986 bFirstDigitsProcessed = TRUE;
987 bDecimalPointProcessed = TRUE;
988 bSecondDigitsProcessed = TRUE;
989 bExponentProcessed = TRUE;
992 bValidRealString = FALSE;
995 /* Process next character.
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 /******************************************************************************
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 )
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
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.*/
1037 return VariantCopy(pd,ps);
1039 /* Cases requiring thought*/
1044 res = VariantClear( pd );
1047 res = VariantClear( pd );
1057 res = VarI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,cVal) );
1061 res = VarI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,cVal) );
1064 res = VarI1FromUI1( V_UNION(ps,bVal), &V_UNION(pd,cVal) );
1067 res = VarI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cVal) );
1071 res = VarI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cVal) );
1074 res = VarI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,cVal) );
1077 res = VarI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,cVal) );
1080 res = VarI1FromDate( V_UNION(ps,date), &V_UNION(pd,cVal) );
1083 res = VarI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,cVal) );
1086 res = VarI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cVal) );
1089 res = VarI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,cVal) );
1091 case( VT_DISPATCH ):
1092 /*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
1094 /*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
1097 res = DISP_E_TYPEMISMATCH;
1098 FIXME("Coercion from %d to VT_I1\n", vtFrom );
1107 res = VarI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,iVal) );
1111 res = VarI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,iVal) );
1114 res = VarI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,iVal) );
1117 res = VarI2FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,iVal) );
1121 res = VarI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,iVal) );
1124 res = VarI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,iVal) );
1127 res = VarI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,iVal) );
1130 res = VarI2FromDate( V_UNION(ps,date), &V_UNION(pd,iVal) );
1133 res = VarI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,iVal) );
1136 res = VarI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,iVal) );
1139 res = VarI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,iVal) );
1141 case( VT_DISPATCH ):
1142 /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
1144 /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
1147 res = DISP_E_TYPEMISMATCH;
1148 FIXME("Coercion from %d to VT_I2\n", vtFrom);
1158 V_UNION(pd,lVal) = 0;
1162 res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
1165 res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
1169 V_UNION(pd,lVal) = V_UNION(pd,scode);
1174 res = VariantCopy( pd, ps );
1177 res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
1180 res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
1184 res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
1187 res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
1190 res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
1193 res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
1196 res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
1199 res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
1202 res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
1204 case( VT_DISPATCH ):
1205 /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1207 /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1210 res = DISP_E_TYPEMISMATCH;
1211 FIXME("Coercion from %d to VT_INT/VT_I4\n", vtFrom);
1220 res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
1223 res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
1227 res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
1230 res = VariantCopy( pd, ps );
1233 res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
1237 res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
1240 res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
1243 res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
1246 res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
1249 res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
1252 res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
1255 res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
1257 case( VT_DISPATCH ):
1258 /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1260 /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1263 res = DISP_E_TYPEMISMATCH;
1264 FIXME("Coercion from %d to VT_UI1\n", vtFrom);
1273 res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
1276 res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
1280 res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
1283 res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
1286 res = VariantCopy( pd, ps );
1290 res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
1293 res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
1296 res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
1299 res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
1302 res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
1305 res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
1308 res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
1310 case( VT_DISPATCH ):
1311 /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1313 /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1316 res = DISP_E_TYPEMISMATCH;
1317 FIXME("Coercion from %d to VT_UI2\n", vtFrom);
1327 res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
1330 res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
1334 res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
1337 res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
1340 res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
1343 res = VariantCopy( pd, ps );
1346 res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
1349 res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
1352 res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
1355 res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
1358 res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
1361 res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
1363 case( VT_DISPATCH ):
1364 /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1366 /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1369 res = DISP_E_TYPEMISMATCH;
1370 FIXME("Coercion from %d to VT_UINT/VT_UI4\n", vtFrom);
1379 res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
1382 res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
1386 res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
1389 res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
1392 res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
1396 res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
1399 res = VariantCopy( pd, ps );
1402 res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
1405 res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
1408 res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
1411 res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
1414 res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
1417 V_UNION(pd,fltVal) = V_UNION(ps,scode);
1420 case( VT_DISPATCH ):
1421 /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1423 /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1426 res = DISP_E_TYPEMISMATCH;
1427 FIXME("Coercion from %d to VT_R4\n", vtFrom);
1436 res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
1439 res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
1443 res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
1446 res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
1449 res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
1453 res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
1456 res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
1459 res = VariantCopy( pd, ps );
1462 res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
1465 res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
1468 res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
1471 res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
1473 case( VT_DISPATCH ):
1474 /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1476 /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1479 res = DISP_E_TYPEMISMATCH;
1480 FIXME("Coercion from %d to VT_R8\n", vtFrom);
1489 res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
1492 res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
1495 res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
1498 res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
1501 res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
1504 res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
1507 res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
1510 res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
1513 res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
1516 res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
1519 res = VarDateFromBool( V_UNION(ps,boolVal), &V_UNION(pd,date) );
1522 res = VarDateFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,date) );
1525 res = VarDateFromCy( V_UNION(ps,cyVal), &V_UNION(pd,date) );
1527 case( VT_DISPATCH ):
1528 /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1530 /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1533 res = DISP_E_TYPEMISMATCH;
1534 FIXME("Coercion from %d to VT_DATE\n", vtFrom);
1544 V_UNION(pd,boolVal) = VARIANT_FALSE;
1547 res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
1550 res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
1553 res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
1556 res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
1559 res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
1562 res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
1565 res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
1568 res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
1571 res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
1574 res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
1577 res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
1580 res = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
1583 res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
1585 case( VT_DISPATCH ):
1586 /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1588 /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1591 res = DISP_E_TYPEMISMATCH;
1592 FIXME("Coercion from %d to VT_BOOL\n", vtFrom);
1601 if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
1604 res = E_OUTOFMEMORY;
1607 res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
1610 res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
1613 res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
1616 res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
1619 res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
1622 res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
1625 res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
1628 res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
1631 res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
1634 res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
1637 res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
1640 res = VarBstrFromBool( V_UNION(ps,boolVal), lcid, 0, &V_UNION(pd,bstrVal) );
1643 res = VariantCopy( pd, ps );
1646 res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
1648 case( VT_DISPATCH ):
1649 /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1651 /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1654 res = DISP_E_TYPEMISMATCH;
1655 FIXME("Coercion from %d to VT_BSTR\n", vtFrom);
1664 res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
1667 res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
1670 res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
1673 res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
1676 res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
1679 res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
1682 res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
1685 res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
1688 res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
1691 res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
1694 res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1697 res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1700 res = VariantCopy( pd, ps );
1703 res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
1705 case( VT_DISPATCH ):
1706 /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1708 /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1712 res = DISP_E_TYPEMISMATCH;
1713 FIXME("Coercion from %d to VT_CY\n", vtFrom);
1721 if (V_DISPATCH(ps) == NULL) {
1722 V_UNKNOWN(pd) = NULL;
1724 res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1727 case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4:
1728 case VT_R4: case VT_R8: case VT_CY: case VT_DATE:
1729 case VT_BSTR: case VT_ERROR: case VT_BOOL:
1730 case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1:
1731 case VT_UI2: case VT_UI4: case VT_I8: case VT_UI8: case VT_INT:
1732 case VT_UINT: case VT_VOID: case VT_HRESULT: case VT_PTR:
1733 case VT_SAFEARRAY: case VT_CARRAY: case VT_USERDEFINED:
1734 case VT_LPSTR: case VT_LPWSTR: case VT_RECORD: case VT_FILETIME:
1735 case VT_BLOB: case VT_STREAM: case VT_STORAGE:
1736 case VT_STREAMED_OBJECT: case VT_STORED_OBJECT: case VT_BLOB_OBJECT:
1737 case VT_CF: case VT_CLSID:
1738 res = DISP_E_TYPEMISMATCH;
1741 FIXME("Coercion from %d to VT_UNKNOWN unhandled.\n", vtFrom);
1742 res = DISP_E_BADVARTYPE;
1747 case( VT_DISPATCH ):
1750 if (V_UNION(ps,punkVal) == NULL) {
1751 V_UNION(pd,pdispVal) = NULL;
1753 res = IUnknown_QueryInterface(V_UNION(ps,punkVal), &IID_IDispatch, (LPVOID*)&V_UNION(pd,pdispVal));
1756 case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4:
1757 case VT_R4: case VT_R8: case VT_CY: case VT_DATE:
1758 case VT_BSTR: case VT_ERROR: case VT_BOOL:
1759 case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1:
1760 case VT_UI2: case VT_UI4: case VT_I8: case VT_UI8: case VT_INT:
1761 case VT_UINT: case VT_VOID: case VT_HRESULT: case VT_PTR:
1762 case VT_SAFEARRAY: case VT_CARRAY: case VT_USERDEFINED:
1763 case VT_LPSTR: case VT_LPWSTR: case VT_RECORD: case VT_FILETIME:
1764 case VT_BLOB: case VT_STREAM: case VT_STORAGE:
1765 case VT_STREAMED_OBJECT: case VT_STORED_OBJECT: case VT_BLOB_OBJECT:
1766 case VT_CF: case VT_CLSID:
1767 res = DISP_E_TYPEMISMATCH;
1770 FIXME("Coercion from %d to VT_DISPATCH unhandled.\n", vtFrom);
1771 res = DISP_E_BADVARTYPE;
1777 res = DISP_E_TYPEMISMATCH;
1778 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1785 /******************************************************************************
1786 * ValidateVtRange [INTERNAL]
1788 * Used internally by the hi-level Variant API to determine
1789 * if the vartypes are valid.
1791 static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
1793 /* if by value we must make sure it is in the
1794 * range of the valid types.
1796 if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1798 return DISP_E_BADVARTYPE;
1804 /******************************************************************************
1805 * ValidateVartype [INTERNAL]
1807 * Used internally by the hi-level Variant API to determine
1808 * if the vartypes are valid.
1810 static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
1814 /* check if we have a valid argument.
1818 /* if by reference check that the type is in
1819 * the valid range and that it is not of empty or null type
1821 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1822 ( vt & VT_TYPEMASK ) == VT_NULL ||
1823 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1825 res = DISP_E_BADVARTYPE;
1831 res = ValidateVtRange( vt );
1837 /******************************************************************************
1838 * ValidateVt [INTERNAL]
1840 * Used internally by the hi-level Variant API to determine
1841 * if the vartypes are valid.
1843 static HRESULT WINAPI ValidateVt( VARTYPE vt )
1847 /* check if we have a valid argument.
1851 /* if by reference check that the type is in
1852 * the valid range and that it is not of empty or null type
1854 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1855 ( vt & VT_TYPEMASK ) == VT_NULL ||
1856 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1858 res = DISP_E_BADVARTYPE;
1864 res = ValidateVtRange( vt );
1874 /******************************************************************************
1875 * VariantInit [OLEAUT32.8]
1877 * Initializes the Variant. Unlike VariantClear it does not interpret
1878 * the current contents of the Variant.
1880 void WINAPI VariantInit(VARIANTARG* pvarg)
1882 TRACE("(%p)\n",pvarg);
1884 memset(pvarg, 0, sizeof (VARIANTARG));
1885 V_VT(pvarg) = VT_EMPTY;
1890 /******************************************************************************
1891 * VariantClear [OLEAUT32.9]
1893 * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1894 * sets the wReservedX field to 0. The current contents of the VARIANT are
1895 * freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1896 * released. If VT_ARRAY the array is freed.
1898 HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
1901 TRACE("(%p)\n",pvarg);
1903 res = ValidateVariantType( V_VT(pvarg) );
1906 if( !( V_VT(pvarg) & VT_BYREF ) )
1909 * The VT_ARRAY flag is a special case of a safe array.
1911 if ( (V_VT(pvarg) & VT_ARRAY) != 0)
1913 SafeArrayDestroy(V_UNION(pvarg,parray));
1917 switch( V_VT(pvarg) & VT_TYPEMASK )
1920 SysFreeString( V_UNION(pvarg,bstrVal) );
1922 case( VT_DISPATCH ):
1923 if(V_UNION(pvarg,pdispVal)!=NULL)
1924 IDispatch_Release(V_UNION(pvarg,pdispVal));
1927 VariantClear(V_UNION(pvarg,pvarVal));
1930 if(V_UNION(pvarg,punkVal)!=NULL)
1931 IUnknown_Release(V_UNION(pvarg,punkVal));
1933 case( VT_SAFEARRAY ):
1934 SafeArrayDestroy(V_UNION(pvarg,parray));
1943 * Empty all the fields and mark the type as empty.
1945 memset(pvarg, 0, sizeof (VARIANTARG));
1946 V_VT(pvarg) = VT_EMPTY;
1952 /******************************************************************************
1953 * VariantCopy [OLEAUT32.10]
1955 * Frees up the designation variant and makes a copy of the source.
1957 HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
1961 TRACE("(%p, %p), vt=%d\n", pvargDest, pvargSrc, V_VT(pvargSrc));
1963 res = ValidateVariantType( V_VT(pvargSrc) );
1965 /* If the pointer are to the same variant we don't need
1968 if( pvargDest != pvargSrc && res == S_OK )
1970 VariantClear( pvargDest ); /* result is not checked */
1972 if( V_VT(pvargSrc) & VT_BYREF )
1974 /* In the case of byreference we only need
1975 * to copy the pointer.
1977 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1978 V_VT(pvargDest) = V_VT(pvargSrc);
1983 * The VT_ARRAY flag is another way to designate a safe array.
1985 if (V_VT(pvargSrc) & VT_ARRAY)
1987 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1991 /* In the case of by value we need to
1992 * copy the actual value. In the case of
1993 * VT_BSTR a copy of the string is made,
1994 * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1995 * called to increment the object's reference count.
1997 switch( V_VT(pvargSrc) & VT_TYPEMASK )
2000 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
2002 case( VT_DISPATCH ):
2003 V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
2004 if (V_UNION(pvargDest,pdispVal)!=NULL)
2005 IDispatch_AddRef(V_UNION(pvargDest,pdispVal));
2008 VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
2011 V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
2012 if (V_UNION(pvargDest,pdispVal)!=NULL)
2013 IUnknown_AddRef(V_UNION(pvargDest,punkVal));
2015 case( VT_SAFEARRAY ):
2016 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
2019 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
2023 V_VT(pvargDest) = V_VT(pvargSrc);
2024 dump_Variant(pvargDest);
2032 /******************************************************************************
2033 * VariantCopyInd [OLEAUT32.11]
2035 * Frees up the destination variant and makes a copy of the source. If
2036 * the source is of type VT_BYREF it performs the necessary indirections.
2038 HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
2042 TRACE("(%p, %p)\n", pvargDest, pvargSrc);
2044 res = ValidateVariantType( V_VT(pvargSrc) );
2049 if( V_VT(pvargSrc) & VT_BYREF )
2052 VariantInit( &varg );
2054 /* handle the in place copy.
2056 if( pvargDest == pvargSrc )
2058 /* we will use a copy of the source instead.
2060 res = VariantCopy( &varg, pvargSrc );
2066 res = VariantClear( pvargDest );
2071 * The VT_ARRAY flag is another way to designate a safearray variant.
2073 if ( V_VT(pvargSrc) & VT_ARRAY)
2075 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2079 /* In the case of by reference we need
2080 * to copy the date pointed to by the variant.
2083 /* Get the variant type.
2085 switch( V_VT(pvargSrc) & VT_TYPEMASK )
2088 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
2090 case( VT_DISPATCH ):
2091 V_UNION(pvargDest,pdispVal) = *V_UNION(pvargSrc,ppdispVal);
2092 if (V_UNION(pvargDest,pdispVal)!=NULL)
2093 IDispatch_AddRef(V_UNION(pvargDest,pdispVal));
2097 /* Prevent from cycling. According to tests on
2098 * VariantCopyInd in Windows and the documentation
2099 * this API dereferences the inner Variants to only one depth.
2100 * If the inner Variant itself contains an
2101 * other inner variant the E_INVALIDARG error is
2104 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
2106 /* If we get here we are attempting to deference
2107 * an inner variant that that is itself contained
2108 * in an inner variant so report E_INVALIDARG error.
2114 /* Set the processing inner variant flag.
2115 * We will set this flag in the inner variant
2116 * that will be passed to the VariantCopyInd function.
2118 (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
2120 /* Dereference the inner variant.
2122 res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
2123 /* We must also copy its type, I think.
2125 V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
2130 V_UNION(pvargDest,punkVal) = *V_UNION(pvargSrc,ppunkVal);
2131 if (V_UNION(pvargDest,pdispVal)!=NULL)
2132 IUnknown_AddRef(V_UNION(pvargDest,punkVal));
2134 case( VT_SAFEARRAY ):
2135 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2138 /* This is a by reference Variant which means that the union
2139 * part of the Variant contains a pointer to some data of
2140 * type "V_VT(pvargSrc) & VT_TYPEMASK".
2141 * We will deference this data in a generic fashion using
2142 * the void pointer "Variant.u.byref".
2143 * We will copy this data into the union of the destination
2146 memcpy( &pvargDest->n1.n2.n3, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
2151 if (res == S_OK) V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
2155 /* this should not fail.
2157 VariantClear( &varg );
2161 res = VariantCopy( pvargDest, pvargSrc );
2167 /******************************************************************************
2168 * Coerces a full safearray. Not optimal code.
2172 VARIANTARG* src, VARIANTARG *dst, LCID lcid, USHORT wFlags, VARTYPE vt
2174 SAFEARRAY *sarr = V_ARRAY(src);
2179 SafeArrayGetVartype(sarr,&vartype);
2182 if (sarr->cDims != 1) {
2183 FIXME("Can not coerce array with dim %d into BSTR\n", sarr->cDims);
2186 switch (V_VT(src) & VT_TYPEMASK) {
2188 hres = SafeArrayAccessData(sarr, &data);
2189 if (FAILED(hres)) return hres;
2191 /* Yes, just memcpied apparently. */
2192 V_BSTR(dst) = SysAllocStringByteLen(data, sarr->rgsabound[0].cElements);
2193 hres = SafeArrayUnaccessData(sarr);
2194 if (FAILED(hres)) return hres;
2197 FIXME("Cannot coerce array of %d into BSTR yet. Please report!\n", V_VT(src) & VT_TYPEMASK);
2202 V_VT(dst) = VT_SAFEARRAY;
2203 return SafeArrayCopy(sarr, &V_ARRAY(dst));
2205 FIXME("Cannot coerce array of vt 0x%x/0x%x into vt 0x%x yet. Please report/implement!\n", vartype, V_VT(src), vt);
2211 /******************************************************************************
2212 * VariantChangeType [OLEAUT32.12]
2214 HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2215 USHORT wFlags, VARTYPE vt)
2217 return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
2220 /******************************************************************************
2221 * VariantChangeTypeEx [OLEAUT32.147]
2223 HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2224 LCID lcid, USHORT wFlags, VARTYPE vt)
2228 VariantInit( &varg );
2230 TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
2231 TRACE("Src Var:\n");
2232 dump_Variant(pvargSrc);
2234 /* validate our source argument.
2236 res = ValidateVariantType( V_VT(pvargSrc) );
2238 /* validate the vartype.
2242 res = ValidateVt( vt );
2245 /* if we are doing an in-place conversion make a copy of the source.
2247 if( res == S_OK && pvargDest == pvargSrc )
2249 res = VariantCopy( &varg, pvargSrc );
2255 /* free up the destination variant.
2257 res = VariantClear( pvargDest );
2262 if( V_VT(pvargSrc) & VT_BYREF )
2264 /* Convert the source variant to a "byvalue" variant.
2268 if ((V_VT(pvargSrc) & 0xf000) != VT_BYREF) {
2269 FIXME("VT_TYPEMASK %x is unhandled.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2273 VariantInit( &Variant );
2274 res = VariantCopyInd( &Variant, pvargSrc );
2277 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2278 /* this should not fail.
2280 VariantClear( &Variant );
2283 if (V_VT(pvargSrc) & VT_ARRAY) {
2284 if ((V_VT(pvargSrc) & 0xf000) != VT_ARRAY) {
2285 FIXME("VT_TYPEMASK %x is unhandled in VT_ARRAY.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2288 V_VT(pvargDest) = VT_ARRAY | vt;
2289 res = coerce_array(pvargSrc, pvargDest, lcid, wFlags, vt);
2291 if ((V_VT(pvargSrc) & 0xf000)) {
2292 FIXME("VT_TYPEMASK %x is unhandled in normal case.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2295 /* Use the current "byvalue" source variant.
2297 res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2301 /* this should not fail.
2303 VariantClear( &varg );
2305 /* set the type of the destination
2308 V_VT(pvargDest) = vt;
2310 TRACE("Dest Var:\n");
2311 dump_Variant(pvargDest);
2319 /******************************************************************************
2320 * VarUI1FromI2 [OLEAUT32.130]
2322 HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2324 TRACE("( %d, %p ), stub\n", sIn, pbOut );
2326 /* Check range of value.
2328 if( sIn < UI1_MIN || sIn > UI1_MAX )
2330 return DISP_E_OVERFLOW;
2333 *pbOut = (BYTE) sIn;
2338 /******************************************************************************
2339 * VarUI1FromI4 [OLEAUT32.131]
2341 HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2343 TRACE("( %ld, %p ), stub\n", lIn, pbOut );
2345 /* Check range of value.
2347 if( lIn < UI1_MIN || lIn > UI1_MAX )
2349 return DISP_E_OVERFLOW;
2352 *pbOut = (BYTE) lIn;
2358 /******************************************************************************
2359 * VarUI1FromR4 [OLEAUT32.132]
2361 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2363 TRACE("( %f, %p ), stub\n", fltIn, pbOut );
2365 /* Check range of value.
2367 fltIn = round( fltIn );
2368 if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2370 return DISP_E_OVERFLOW;
2373 *pbOut = (BYTE) fltIn;
2378 /******************************************************************************
2379 * VarUI1FromR8 [OLEAUT32.133]
2381 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2383 TRACE("( %f, %p ), stub\n", dblIn, pbOut );
2385 /* Check range of value.
2387 dblIn = round( dblIn );
2388 if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2390 return DISP_E_OVERFLOW;
2393 *pbOut = (BYTE) dblIn;
2398 /******************************************************************************
2399 * VarUI1FromDate [OLEAUT32.135]
2401 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2403 TRACE("( %f, %p ), stub\n", dateIn, pbOut );
2405 /* Check range of value.
2407 dateIn = round( dateIn );
2408 if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2410 return DISP_E_OVERFLOW;
2413 *pbOut = (BYTE) dateIn;
2418 /******************************************************************************
2419 * VarUI1FromBool [OLEAUT32.138]
2421 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2423 TRACE("( %d, %p ), stub\n", boolIn, pbOut );
2425 *pbOut = (BYTE) boolIn;
2430 /******************************************************************************
2431 * VarUI1FromI1 [OLEAUT32.237]
2433 HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
2435 TRACE("( %c, %p ), stub\n", cIn, pbOut );
2442 /******************************************************************************
2443 * VarUI1FromUI2 [OLEAUT32.238]
2445 HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2447 TRACE("( %d, %p ), stub\n", uiIn, pbOut );
2449 /* Check range of value.
2451 if( uiIn > UI1_MAX )
2453 return DISP_E_OVERFLOW;
2456 *pbOut = (BYTE) uiIn;
2461 /******************************************************************************
2462 * VarUI1FromUI4 [OLEAUT32.239]
2464 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2466 TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
2468 /* Check range of value.
2470 if( ulIn > UI1_MAX )
2472 return DISP_E_OVERFLOW;
2475 *pbOut = (BYTE) ulIn;
2481 /******************************************************************************
2482 * VarUI1FromStr [OLEAUT32.136]
2484 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2486 double dValue = 0.0;
2487 LPSTR pNewString = NULL;
2489 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
2491 /* Check if we have a valid argument
2493 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2494 RemoveCharacterFromString( pNewString, "," );
2495 if( IsValidRealString( pNewString ) == FALSE )
2497 return DISP_E_TYPEMISMATCH;
2500 /* Convert the valid string to a floating point number.
2502 dValue = atof( pNewString );
2504 /* We don't need the string anymore so free it.
2506 HeapFree( GetProcessHeap(), 0 , pNewString );
2508 /* Check range of value.
2510 dValue = round( dValue );
2511 if( dValue < UI1_MIN || dValue > UI1_MAX )
2513 return DISP_E_OVERFLOW;
2516 *pbOut = (BYTE) dValue;
2521 /**********************************************************************
2522 * VarUI1FromCy [OLEAUT32.134]
2523 * Convert currency to unsigned char
2525 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
2526 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2528 if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
2534 /******************************************************************************
2535 * VarI2FromUI1 [OLEAUT32.48]
2537 HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2539 TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
2541 *psOut = (short) bIn;
2546 /******************************************************************************
2547 * VarI2FromI4 [OLEAUT32.49]
2549 HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2551 TRACE("( %lx, %p ), stub\n", lIn, psOut );
2553 /* Check range of value.
2555 if( lIn < I2_MIN || lIn > I2_MAX )
2557 return DISP_E_OVERFLOW;
2560 *psOut = (short) lIn;
2565 /******************************************************************************
2566 * VarI2FromR4 [OLEAUT32.50]
2568 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2570 TRACE("( %f, %p ), stub\n", fltIn, psOut );
2572 /* Check range of value.
2574 fltIn = round( fltIn );
2575 if( fltIn < I2_MIN || fltIn > I2_MAX )
2577 return DISP_E_OVERFLOW;
2580 *psOut = (short) fltIn;
2585 /******************************************************************************
2586 * VarI2FromR8 [OLEAUT32.51]
2588 HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2590 TRACE("( %f, %p ), stub\n", dblIn, psOut );
2592 /* Check range of value.
2594 dblIn = round( dblIn );
2595 if( dblIn < I2_MIN || dblIn > I2_MAX )
2597 return DISP_E_OVERFLOW;
2600 *psOut = (short) dblIn;
2605 /******************************************************************************
2606 * VarI2FromDate [OLEAUT32.53]
2608 HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2610 TRACE("( %f, %p ), stub\n", dateIn, psOut );
2612 /* Check range of value.
2614 dateIn = round( dateIn );
2615 if( dateIn < I2_MIN || dateIn > I2_MAX )
2617 return DISP_E_OVERFLOW;
2620 *psOut = (short) dateIn;
2625 /******************************************************************************
2626 * VarI2FromBool [OLEAUT32.56]
2628 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2630 TRACE("( %d, %p ), stub\n", boolIn, psOut );
2632 *psOut = (short) boolIn;
2637 /******************************************************************************
2638 * VarI2FromI1 [OLEAUT32.205]
2640 HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
2642 TRACE("( %c, %p ), stub\n", cIn, psOut );
2644 *psOut = (short) cIn;
2649 /******************************************************************************
2650 * VarI2FromUI2 [OLEAUT32.206]
2652 HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2654 TRACE("( %d, %p ), stub\n", uiIn, psOut );
2656 /* Check range of value.
2660 return DISP_E_OVERFLOW;
2663 *psOut = (short) uiIn;
2668 /******************************************************************************
2669 * VarI2FromUI4 [OLEAUT32.207]
2671 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2673 TRACE("( %lx, %p ), stub\n", ulIn, psOut );
2675 /* Check range of value.
2677 if( ulIn < I2_MIN || ulIn > I2_MAX )
2679 return DISP_E_OVERFLOW;
2682 *psOut = (short) ulIn;
2687 /******************************************************************************
2688 * VarI2FromStr [OLEAUT32.54]
2690 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2692 double dValue = 0.0;
2693 LPSTR pNewString = NULL;
2695 TRACE("( %s, 0x%08lx, 0x%08lx, %p ), stub\n", debugstr_w(strIn), lcid, dwFlags, psOut );
2697 /* Check if we have a valid argument
2699 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2700 RemoveCharacterFromString( pNewString, "," );
2701 if( IsValidRealString( pNewString ) == FALSE )
2703 return DISP_E_TYPEMISMATCH;
2706 /* Convert the valid string to a floating point number.
2708 dValue = atof( pNewString );
2710 /* We don't need the string anymore so free it.
2712 HeapFree( GetProcessHeap(), 0, pNewString );
2714 /* Check range of value.
2716 dValue = round( dValue );
2717 if( dValue < I2_MIN || dValue > I2_MAX )
2719 return DISP_E_OVERFLOW;
2722 *psOut = (short) dValue;
2727 /**********************************************************************
2728 * VarI2FromCy [OLEAUT32.52]
2729 * Convert currency to signed short
2731 HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
2732 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2734 if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
2740 /******************************************************************************
2741 * VarI4FromUI1 [OLEAUT32.58]
2743 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2745 TRACE("( %X, %p ), stub\n", bIn, plOut );
2747 *plOut = (LONG) bIn;
2753 /******************************************************************************
2754 * VarI4FromR4 [OLEAUT32.60]
2756 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2758 TRACE("( %f, %p ), stub\n", fltIn, plOut );
2760 /* Check range of value.
2762 fltIn = round( fltIn );
2763 if( fltIn < I4_MIN || fltIn > I4_MAX )
2765 return DISP_E_OVERFLOW;
2768 *plOut = (LONG) fltIn;
2773 /******************************************************************************
2774 * VarI4FromR8 [OLEAUT32.61]
2776 HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2778 TRACE("( %f, %p ), stub\n", dblIn, plOut );
2780 /* Check range of value.
2782 dblIn = round( dblIn );
2783 if( dblIn < I4_MIN || dblIn > I4_MAX )
2785 return DISP_E_OVERFLOW;
2788 *plOut = (LONG) dblIn;
2793 /******************************************************************************
2794 * VarI4FromDate [OLEAUT32.63]
2796 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2798 TRACE("( %f, %p ), stub\n", dateIn, plOut );
2800 /* Check range of value.
2802 dateIn = round( dateIn );
2803 if( dateIn < I4_MIN || dateIn > I4_MAX )
2805 return DISP_E_OVERFLOW;
2808 *plOut = (LONG) dateIn;
2813 /******************************************************************************
2814 * VarI4FromBool [OLEAUT32.66]
2816 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2818 TRACE("( %d, %p ), stub\n", boolIn, plOut );
2820 *plOut = (LONG) boolIn;
2825 /******************************************************************************
2826 * VarI4FromI1 [OLEAUT32.209]
2828 HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
2830 TRACE("( %c, %p ), stub\n", cIn, plOut );
2832 *plOut = (LONG) cIn;
2837 /******************************************************************************
2838 * VarI4FromUI2 [OLEAUT32.210]
2840 HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2842 TRACE("( %d, %p ), stub\n", uiIn, plOut );
2844 *plOut = (LONG) uiIn;
2849 /******************************************************************************
2850 * VarI4FromUI4 [OLEAUT32.211]
2852 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2854 TRACE("( %lx, %p ), stub\n", ulIn, plOut );
2856 /* Check range of value.
2858 if( ulIn < I4_MIN || ulIn > I4_MAX )
2860 return DISP_E_OVERFLOW;
2863 *plOut = (LONG) ulIn;
2868 /******************************************************************************
2869 * VarI4FromI2 [OLEAUT32.59]
2871 HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2873 TRACE("( %d, %p ), stub\n", sIn, plOut );
2875 *plOut = (LONG) sIn;
2880 /******************************************************************************
2881 * VarI4FromStr [OLEAUT32.64]
2883 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2885 double dValue = 0.0;
2886 LPSTR pNewString = NULL;
2888 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
2890 /* Check if we have a valid argument
2892 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2893 RemoveCharacterFromString( pNewString, "," );
2894 if( IsValidRealString( pNewString ) == FALSE )
2896 return DISP_E_TYPEMISMATCH;
2899 /* Convert the valid string to a floating point number.
2901 dValue = atof( pNewString );
2903 /* We don't need the string anymore so free it.
2905 HeapFree( GetProcessHeap(), 0, pNewString );
2907 /* Check range of value.
2909 dValue = round( dValue );
2910 if( dValue < I4_MIN || dValue > I4_MAX )
2912 return DISP_E_OVERFLOW;
2915 *plOut = (LONG) dValue;
2920 /**********************************************************************
2921 * VarI4FromCy [OLEAUT32.62]
2922 * Convert currency to signed long
2924 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
2925 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2927 if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
2933 /******************************************************************************
2934 * VarR4FromUI1 [OLEAUT32.68]
2936 HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
2938 TRACE("( %X, %p ), stub\n", bIn, pfltOut );
2940 *pfltOut = (FLOAT) bIn;
2945 /******************************************************************************
2946 * VarR4FromI2 [OLEAUT32.69]
2948 HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
2950 TRACE("( %d, %p ), stub\n", sIn, pfltOut );
2952 *pfltOut = (FLOAT) sIn;
2957 /******************************************************************************
2958 * VarR4FromI4 [OLEAUT32.70]
2960 HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
2962 TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
2964 *pfltOut = (FLOAT) lIn;
2969 /******************************************************************************
2970 * VarR4FromR8 [OLEAUT32.71]
2972 HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
2974 TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
2976 /* Check range of value.
2978 if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
2980 return DISP_E_OVERFLOW;
2983 *pfltOut = (FLOAT) dblIn;
2988 /******************************************************************************
2989 * VarR4FromDate [OLEAUT32.73]
2991 HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
2993 TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
2995 /* Check range of value.
2997 if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
2999 return DISP_E_OVERFLOW;
3002 *pfltOut = (FLOAT) dateIn;
3007 /******************************************************************************
3008 * VarR4FromBool [OLEAUT32.76]
3010 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
3012 TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
3014 *pfltOut = (FLOAT) boolIn;
3019 /******************************************************************************
3020 * VarR4FromI1 [OLEAUT32.213]
3022 HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
3024 TRACE("( %c, %p ), stub\n", cIn, pfltOut );
3026 *pfltOut = (FLOAT) cIn;
3031 /******************************************************************************
3032 * VarR4FromUI2 [OLEAUT32.214]
3034 HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
3036 TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
3038 *pfltOut = (FLOAT) uiIn;
3043 /******************************************************************************
3044 * VarR4FromUI4 [OLEAUT32.215]
3046 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
3048 TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
3050 *pfltOut = (FLOAT) ulIn;
3055 /******************************************************************************
3056 * VarR4FromStr [OLEAUT32.74]
3058 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
3060 double dValue = 0.0;
3061 LPSTR pNewString = NULL;
3063 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
3065 /* Check if we have a valid argument
3067 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3068 RemoveCharacterFromString( pNewString, "," );
3069 if( IsValidRealString( pNewString ) == FALSE )
3071 return DISP_E_TYPEMISMATCH;
3074 /* Convert the valid string to a floating point number.
3076 dValue = atof( pNewString );
3078 /* We don't need the string anymore so free it.
3080 HeapFree( GetProcessHeap(), 0, pNewString );
3082 /* Check range of value.
3084 if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
3086 return DISP_E_OVERFLOW;
3089 *pfltOut = (FLOAT) dValue;
3094 /**********************************************************************
3095 * VarR4FromCy [OLEAUT32.72]
3096 * Convert currency to float
3098 HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
3099 *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3104 /******************************************************************************
3105 * VarR8FromUI1 [OLEAUT32.78]
3107 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
3109 TRACE("( %d, %p ), stub\n", bIn, pdblOut );
3111 *pdblOut = (double) bIn;
3116 /******************************************************************************
3117 * VarR8FromI2 [OLEAUT32.79]
3119 HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
3121 TRACE("( %d, %p ), stub\n", sIn, pdblOut );
3123 *pdblOut = (double) sIn;
3128 /******************************************************************************
3129 * VarR8FromI4 [OLEAUT32.80]
3131 HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
3133 TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
3135 *pdblOut = (double) lIn;
3140 /******************************************************************************
3141 * VarR8FromR4 [OLEAUT32.81]
3143 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
3145 TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
3147 *pdblOut = (double) fltIn;
3152 /******************************************************************************
3153 * VarR8FromDate [OLEAUT32.83]
3155 HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
3157 TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
3159 *pdblOut = (double) dateIn;
3164 /******************************************************************************
3165 * VarR8FromBool [OLEAUT32.86]
3167 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
3169 TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
3171 *pdblOut = (double) boolIn;
3176 /******************************************************************************
3177 * VarR8FromI1 [OLEAUT32.217]
3179 HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
3181 TRACE("( %c, %p ), stub\n", cIn, pdblOut );
3183 *pdblOut = (double) cIn;
3188 /******************************************************************************
3189 * VarR8FromUI2 [OLEAUT32.218]
3191 HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
3193 TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
3195 *pdblOut = (double) uiIn;
3200 /******************************************************************************
3201 * VarR8FromUI4 [OLEAUT32.219]
3203 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
3205 TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
3207 *pdblOut = (double) ulIn;
3212 /******************************************************************************
3213 * VarR8FromStr [OLEAUT32.84]
3215 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
3217 double dValue = 0.0;
3218 LPSTR pNewString = NULL;
3220 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3221 TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString, lcid, dwFlags, pdblOut );
3223 /* Check if we have a valid argument
3225 RemoveCharacterFromString( pNewString, "," );
3226 if( IsValidRealString( pNewString ) == FALSE )
3228 return DISP_E_TYPEMISMATCH;
3231 /* Convert the valid string to a floating point number.
3233 dValue = atof( pNewString );
3235 /* We don't need the string anymore so free it.
3237 HeapFree( GetProcessHeap(), 0, pNewString );
3244 /**********************************************************************
3245 * VarR8FromCy [OLEAUT32.82]
3246 * Convert currency to double
3248 HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
3249 *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3250 TRACE("%lu %ld -> %f\n", cyIn.s.Hi, cyIn.s.Lo, *pdblOut);
3254 /******************************************************************************
3255 * VarDateFromUI1 [OLEAUT32.88]
3257 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
3259 TRACE("( %d, %p ), stub\n", bIn, pdateOut );
3261 *pdateOut = (DATE) bIn;
3266 /******************************************************************************
3267 * VarDateFromI2 [OLEAUT32.89]
3269 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
3271 TRACE("( %d, %p ), stub\n", sIn, pdateOut );
3273 *pdateOut = (DATE) sIn;
3278 /******************************************************************************
3279 * VarDateFromI4 [OLEAUT32.90]
3281 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3283 TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
3285 if( lIn < DATE_MIN || lIn > DATE_MAX )
3287 return DISP_E_OVERFLOW;
3290 *pdateOut = (DATE) lIn;
3295 /******************************************************************************
3296 * VarDateFromR4 [OLEAUT32.91]
3298 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3300 TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3302 if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
3304 return DISP_E_OVERFLOW;
3307 *pdateOut = (DATE) fltIn;
3312 /******************************************************************************
3313 * VarDateFromR8 [OLEAUT32.92]
3315 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3317 TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3319 if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3321 return DISP_E_OVERFLOW;
3324 *pdateOut = (DATE) dblIn;
3329 /******************************************************************************
3330 * VarDateFromStr [OLEAUT32.94]
3331 * The string representing the date is composed of two parts, a date and time.
3333 * The format of the time is has follows:
3334 * hh[:mm][:ss][AM|PM]
3335 * Whitespace can be inserted anywhere between these tokens. A whitespace consists
3336 * of space and/or tab characters, which are ignored.
3338 * The formats for the date part are has follows:
3342 * January dd[,] [yy]yy
3345 * Whitespace can be inserted anywhere between these tokens.
3347 * The formats for the date and time string are has follows.
3348 * date[whitespace][time]
3349 * [time][whitespace]date
3351 * These are the only characters allowed in a string representing a date and time:
3352 * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3354 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3359 memset( &TM, 0, sizeof(TM) );
3361 TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3363 if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
3365 if( TmToDATE( &TM, pdateOut ) == FALSE )
3372 ret = DISP_E_TYPEMISMATCH;
3374 TRACE("Return value %f\n", *pdateOut);
3378 /******************************************************************************
3379 * VarDateFromI1 [OLEAUT32.221]
3381 HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
3383 TRACE("( %c, %p ), stub\n", cIn, pdateOut );
3385 *pdateOut = (DATE) cIn;
3390 /******************************************************************************
3391 * VarDateFromUI2 [OLEAUT32.222]
3393 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3395 TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
3397 if( uiIn > DATE_MAX )
3399 return DISP_E_OVERFLOW;
3402 *pdateOut = (DATE) uiIn;
3407 /******************************************************************************
3408 * VarDateFromUI4 [OLEAUT32.223]
3410 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3412 TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
3414 if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3416 return DISP_E_OVERFLOW;
3419 *pdateOut = (DATE) ulIn;
3424 /******************************************************************************
3425 * VarDateFromBool [OLEAUT32.96]
3427 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3429 TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
3431 *pdateOut = (DATE) boolIn;
3436 /**********************************************************************
3437 * VarDateFromCy [OLEAUT32.93]
3438 * Convert currency to date
3440 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
3441 *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3443 if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3447 /******************************************************************************
3448 * VarBstrFromUI1 [OLEAUT32.108]
3450 HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3452 TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3453 sprintf( pBuffer, "%d", bVal );
3455 *pbstrOut = StringDupAtoBstr( pBuffer );
3460 /******************************************************************************
3461 * VarBstrFromI2 [OLEAUT32.109]
3463 HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3465 TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3466 sprintf( pBuffer, "%d", iVal );
3467 *pbstrOut = StringDupAtoBstr( pBuffer );
3472 /******************************************************************************
3473 * VarBstrFromI4 [OLEAUT32.110]
3475 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3477 TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
3479 sprintf( pBuffer, "%ld", lIn );
3480 *pbstrOut = StringDupAtoBstr( pBuffer );
3485 /******************************************************************************
3486 * VarBstrFromR4 [OLEAUT32.111]
3488 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3490 TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
3492 sprintf( pBuffer, "%.7G", fltIn );
3493 *pbstrOut = StringDupAtoBstr( pBuffer );
3498 /******************************************************************************
3499 * VarBstrFromR8 [OLEAUT32.112]
3501 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3503 TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
3505 sprintf( pBuffer, "%.15G", dblIn );
3506 *pbstrOut = StringDupAtoBstr( pBuffer );
3511 /******************************************************************************
3512 * VarBstrFromCy [OLEAUT32.113]
3514 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
3516 double curVal = 0.0;
3518 TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid, dwFlags, pbstrOut);
3520 /* Firstly get the currency in a double, then put it in a buffer */
3521 rc = VarR8FromCy(cyIn, &curVal);
3523 sprintf(pBuffer, "%G", curVal);
3524 *pbstrOut = StringDupAtoBstr( pBuffer );
3530 /******************************************************************************
3531 * VarBstrFromDate [OLEAUT32.114]
3533 * The date is implemented using an 8 byte floating-point number.
3534 * Days are represented by whole numbers increments starting with 0.00 as
3535 * being December 30 1899, midnight.
3536 * The hours are expressed as the fractional part of the number.
3537 * December 30 1899 at midnight = 0.00
3538 * January 1 1900 at midnight = 2.00
3539 * January 4 1900 at 6 AM = 5.25
3540 * January 4 1900 at noon = 5.50
3541 * December 29 1899 at midnight = -1.00
3542 * December 18 1899 at midnight = -12.00
3543 * December 18 1899 at 6AM = -12.25
3544 * December 18 1899 at 6PM = -12.75
3545 * December 19 1899 at midnight = -11.00
3546 * The tm structure is as follows:
3548 * int tm_sec; seconds after the minute - [0,59]
3549 * int tm_min; minutes after the hour - [0,59]
3550 * int tm_hour; hours since midnight - [0,23]
3551 * int tm_mday; day of the month - [1,31]
3552 * int tm_mon; months since January - [0,11]
3553 * int tm_year; years
3554 * int tm_wday; days since Sunday - [0,6]
3555 * int tm_yday; days since January 1 - [0,365]
3556 * int tm_isdst; daylight savings time flag
3559 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3562 memset( &TM, 0, sizeof(TM) );
3564 TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
3566 if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
3568 return E_INVALIDARG;
3571 if( dwFlags & VAR_DATEVALUEONLY )
3572 strftime( pBuffer, BUFFER_MAX, "%x", &TM );
3573 else if( dwFlags & VAR_TIMEVALUEONLY )
3574 strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3576 strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3578 TRACE("result: %s\n", pBuffer);
3579 *pbstrOut = StringDupAtoBstr( pBuffer );
3583 /******************************************************************************
3584 * VarBstrFromBool [OLEAUT32.116]
3586 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3588 TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
3590 sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
3592 *pbstrOut = StringDupAtoBstr( pBuffer );
3597 /******************************************************************************
3598 * VarBstrFromI1 [OLEAUT32.229]
3600 HRESULT WINAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3602 TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3603 sprintf( pBuffer, "%d", cIn );
3604 *pbstrOut = StringDupAtoBstr( pBuffer );
3609 /******************************************************************************
3610 * VarBstrFromUI2 [OLEAUT32.230]
3612 HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3614 TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3615 sprintf( pBuffer, "%d", uiIn );
3616 *pbstrOut = StringDupAtoBstr( pBuffer );
3621 /******************************************************************************
3622 * VarBstrFromUI4 [OLEAUT32.231]
3624 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3626 TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3627 sprintf( pBuffer, "%ld", ulIn );
3628 *pbstrOut = StringDupAtoBstr( pBuffer );
3633 /******************************************************************************
3634 * VarBoolFromUI1 [OLEAUT32.118]
3636 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3638 TRACE("( %d, %p ), stub\n", bIn, pboolOut );
3642 *pboolOut = VARIANT_FALSE;
3646 *pboolOut = VARIANT_TRUE;
3652 /******************************************************************************
3653 * VarBoolFromI2 [OLEAUT32.119]
3655 HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3657 TRACE("( %d, %p ), stub\n", sIn, pboolOut );
3659 *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
3664 /******************************************************************************
3665 * VarBoolFromI4 [OLEAUT32.120]
3667 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3669 TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
3671 *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
3676 /******************************************************************************
3677 * VarBoolFromR4 [OLEAUT32.121]
3679 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3681 TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
3683 *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3688 /******************************************************************************
3689 * VarBoolFromR8 [OLEAUT32.122]
3691 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3693 TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
3695 *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3700 /******************************************************************************
3701 * VarBoolFromDate [OLEAUT32.123]
3703 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3705 TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
3707 *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3712 /******************************************************************************
3713 * VarBoolFromStr [OLEAUT32.125]
3715 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3718 char* pNewString = NULL;
3720 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
3722 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3724 if( pNewString == NULL || strlen( pNewString ) == 0 )
3726 ret = DISP_E_TYPEMISMATCH;
3731 if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
3733 *pboolOut = VARIANT_TRUE;
3735 else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
3737 *pboolOut = VARIANT_FALSE;
3741 /* Try converting the string to a floating point number.
3743 double dValue = 0.0;
3744 HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3747 ret = DISP_E_TYPEMISMATCH;
3750 *pboolOut = (dValue == 0.0) ?
3751 VARIANT_FALSE : VARIANT_TRUE;
3755 HeapFree( GetProcessHeap(), 0, pNewString );
3760 /******************************************************************************
3761 * VarBoolFromI1 [OLEAUT32.233]
3763 HRESULT WINAPI VarBoolFromI1(CHAR cIn, VARIANT_BOOL* pboolOut)
3765 TRACE("( %c, %p ), stub\n", cIn, pboolOut );
3767 *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3772 /******************************************************************************
3773 * VarBoolFromUI2 [OLEAUT32.234]
3775 HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3777 TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
3779 *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3784 /******************************************************************************
3785 * VarBoolFromUI4 [OLEAUT32.235]
3787 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3789 TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
3791 *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3796 /**********************************************************************
3797 * VarBoolFromCy [OLEAUT32.124]
3798 * Convert currency to boolean
3800 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
3801 if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
3807 /******************************************************************************
3808 * VarI1FromUI1 [OLEAUT32.244]
3810 HRESULT WINAPI VarI1FromUI1(BYTE bIn, CHAR* pcOut)
3812 TRACE("( %d, %p ), stub\n", bIn, pcOut );
3814 /* Check range of value.
3816 if( bIn > CHAR_MAX )
3818 return DISP_E_OVERFLOW;
3821 *pcOut = (CHAR) bIn;
3826 /******************************************************************************
3827 * VarI1FromI2 [OLEAUT32.245]
3829 HRESULT WINAPI VarI1FromI2(short uiIn, CHAR* pcOut)
3831 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3833 if( uiIn > CHAR_MAX )
3835 return DISP_E_OVERFLOW;
3838 *pcOut = (CHAR) uiIn;
3843 /******************************************************************************
3844 * VarI1FromI4 [OLEAUT32.246]
3846 HRESULT WINAPI VarI1FromI4(LONG lIn, CHAR* pcOut)
3848 TRACE("( %ld, %p ), stub\n", lIn, pcOut );
3850 if( lIn < CHAR_MIN || lIn > CHAR_MAX )
3852 return DISP_E_OVERFLOW;
3855 *pcOut = (CHAR) lIn;
3860 /******************************************************************************
3861 * VarI1FromR4 [OLEAUT32.247]
3863 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, CHAR* pcOut)
3865 TRACE("( %f, %p ), stub\n", fltIn, pcOut );
3867 fltIn = round( fltIn );
3868 if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
3870 return DISP_E_OVERFLOW;
3873 *pcOut = (CHAR) fltIn;
3878 /******************************************************************************
3879 * VarI1FromR8 [OLEAUT32.248]
3881 HRESULT WINAPI VarI1FromR8(double dblIn, CHAR* pcOut)
3883 TRACE("( %f, %p ), stub\n", dblIn, pcOut );
3885 dblIn = round( dblIn );
3886 if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
3888 return DISP_E_OVERFLOW;
3891 *pcOut = (CHAR) dblIn;
3896 /******************************************************************************
3897 * VarI1FromDate [OLEAUT32.249]
3899 HRESULT WINAPI VarI1FromDate(DATE dateIn, CHAR* pcOut)
3901 TRACE("( %f, %p ), stub\n", dateIn, pcOut );
3903 dateIn = round( dateIn );
3904 if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
3906 return DISP_E_OVERFLOW;
3909 *pcOut = (CHAR) dateIn;
3914 /******************************************************************************
3915 * VarI1FromStr [OLEAUT32.251]
3917 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CHAR* pcOut)
3919 double dValue = 0.0;
3920 LPSTR pNewString = NULL;
3922 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
3924 /* Check if we have a valid argument
3926 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3927 RemoveCharacterFromString( pNewString, "," );
3928 if( IsValidRealString( pNewString ) == FALSE )
3930 return DISP_E_TYPEMISMATCH;
3933 /* Convert the valid string to a floating point number.
3935 dValue = atof( pNewString );
3937 /* We don't need the string anymore so free it.
3939 HeapFree( GetProcessHeap(), 0, pNewString );
3941 /* Check range of value.
3943 dValue = round( dValue );
3944 if( dValue < CHAR_MIN || dValue > CHAR_MAX )
3946 return DISP_E_OVERFLOW;
3949 *pcOut = (CHAR) dValue;
3954 /******************************************************************************
3955 * VarI1FromBool [OLEAUT32.253]
3957 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
3959 TRACE("( %d, %p ), stub\n", boolIn, pcOut );
3961 *pcOut = (CHAR) boolIn;
3966 /******************************************************************************
3967 * VarI1FromUI2 [OLEAUT32.254]
3969 HRESULT WINAPI VarI1FromUI2(USHORT uiIn, CHAR* pcOut)
3971 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3973 if( uiIn > CHAR_MAX )
3975 return DISP_E_OVERFLOW;
3978 *pcOut = (CHAR) uiIn;
3983 /******************************************************************************
3984 * VarI1FromUI4 [OLEAUT32.255]
3986 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, CHAR* pcOut)
3988 TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
3990 if( ulIn > CHAR_MAX )
3992 return DISP_E_OVERFLOW;
3995 *pcOut = (CHAR) ulIn;
4000 /**********************************************************************
4001 * VarI1FromCy [OLEAUT32.250]
4002 * Convert currency to signed char
4004 HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
4005 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4007 if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
4013 /******************************************************************************
4014 * VarUI2FromUI1 [OLEAUT32.257]
4016 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
4018 TRACE("( %d, %p ), stub\n", bIn, puiOut );
4020 *puiOut = (USHORT) bIn;
4025 /******************************************************************************
4026 * VarUI2FromI2 [OLEAUT32.258]
4028 HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
4030 TRACE("( %d, %p ), stub\n", uiIn, puiOut );
4032 if( uiIn < UI2_MIN )
4034 return DISP_E_OVERFLOW;
4037 *puiOut = (USHORT) uiIn;
4042 /******************************************************************************
4043 * VarUI2FromI4 [OLEAUT32.259]
4045 HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
4047 TRACE("( %ld, %p ), stub\n", lIn, puiOut );
4049 if( lIn < UI2_MIN || lIn > UI2_MAX )
4051 return DISP_E_OVERFLOW;
4054 *puiOut = (USHORT) lIn;
4059 /******************************************************************************
4060 * VarUI2FromR4 [OLEAUT32.260]
4062 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
4064 TRACE("( %f, %p ), stub\n", fltIn, puiOut );
4066 fltIn = round( fltIn );
4067 if( fltIn < UI2_MIN || fltIn > UI2_MAX )
4069 return DISP_E_OVERFLOW;
4072 *puiOut = (USHORT) fltIn;
4077 /******************************************************************************
4078 * VarUI2FromR8 [OLEAUT32.261]
4080 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
4082 TRACE("( %f, %p ), stub\n", dblIn, puiOut );
4084 dblIn = round( dblIn );
4085 if( dblIn < UI2_MIN || dblIn > UI2_MAX )
4087 return DISP_E_OVERFLOW;
4090 *puiOut = (USHORT) dblIn;
4095 /******************************************************************************
4096 * VarUI2FromDate [OLEAUT32.262]
4098 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
4100 TRACE("( %f, %p ), stub\n", dateIn, puiOut );
4102 dateIn = round( dateIn );
4103 if( dateIn < UI2_MIN || dateIn > UI2_MAX )
4105 return DISP_E_OVERFLOW;
4108 *puiOut = (USHORT) dateIn;
4113 /******************************************************************************
4114 * VarUI2FromStr [OLEAUT32.264]
4116 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
4118 double dValue = 0.0;
4119 LPSTR pNewString = NULL;
4121 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
4123 /* Check if we have a valid argument
4125 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4126 RemoveCharacterFromString( pNewString, "," );
4127 if( IsValidRealString( pNewString ) == FALSE )
4129 return DISP_E_TYPEMISMATCH;
4132 /* Convert the valid string to a floating point number.
4134 dValue = atof( pNewString );
4136 /* We don't need the string anymore so free it.
4138 HeapFree( GetProcessHeap(), 0, pNewString );
4140 /* Check range of value.
4142 dValue = round( dValue );
4143 if( dValue < UI2_MIN || dValue > UI2_MAX )
4145 return DISP_E_OVERFLOW;
4148 *puiOut = (USHORT) dValue;
4153 /******************************************************************************
4154 * VarUI2FromBool [OLEAUT32.266]
4156 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
4158 TRACE("( %d, %p ), stub\n", boolIn, puiOut );
4160 *puiOut = (USHORT) boolIn;
4165 /******************************************************************************
4166 * VarUI2FromI1 [OLEAUT32.267]
4168 HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
4170 TRACE("( %c, %p ), stub\n", cIn, puiOut );
4172 *puiOut = (USHORT) cIn;
4177 /******************************************************************************
4178 * VarUI2FromUI4 [OLEAUT32.268]
4180 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
4182 TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
4184 if( ulIn > UI2_MAX )
4186 return DISP_E_OVERFLOW;
4189 *puiOut = (USHORT) ulIn;
4194 /******************************************************************************
4195 * VarUI4FromStr [OLEAUT32.277]
4197 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
4199 double dValue = 0.0;
4200 LPSTR pNewString = NULL;
4202 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
4204 /* Check if we have a valid argument
4206 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4207 RemoveCharacterFromString( pNewString, "," );
4208 if( IsValidRealString( pNewString ) == FALSE )
4210 return DISP_E_TYPEMISMATCH;
4213 /* Convert the valid string to a floating point number.
4215 dValue = atof( pNewString );
4217 /* We don't need the string anymore so free it.
4219 HeapFree( GetProcessHeap(), 0, pNewString );
4221 /* Check range of value.
4223 dValue = round( dValue );
4224 if( dValue < UI4_MIN || dValue > UI4_MAX )
4226 return DISP_E_OVERFLOW;
4229 *pulOut = (ULONG) dValue;
4234 /**********************************************************************
4235 * VarUI2FromCy [OLEAUT32.263]
4236 * Convert currency to unsigned short
4238 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
4239 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4241 if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
4243 *pusOut = (USHORT)t;
4248 /******************************************************************************
4249 * VarUI4FromUI1 [OLEAUT32.270]
4251 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
4253 TRACE("( %d, %p ), stub\n", bIn, pulOut );
4255 *pulOut = (USHORT) bIn;
4260 /******************************************************************************
4261 * VarUI4FromI2 [OLEAUT32.271]
4263 HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
4265 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4267 if( uiIn < UI4_MIN )
4269 return DISP_E_OVERFLOW;
4272 *pulOut = (ULONG) uiIn;
4277 /******************************************************************************
4278 * VarUI4FromI4 [OLEAUT32.272]
4280 HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
4282 TRACE("( %ld, %p ), stub\n", lIn, pulOut );
4286 return DISP_E_OVERFLOW;
4289 *pulOut = (ULONG) lIn;
4294 /******************************************************************************
4295 * VarUI4FromR4 [OLEAUT32.273]
4297 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
4299 fltIn = round( fltIn );
4300 if( fltIn < UI4_MIN || fltIn > UI4_MAX )
4302 return DISP_E_OVERFLOW;
4305 *pulOut = (ULONG) fltIn;
4310 /******************************************************************************
4311 * VarUI4FromR8 [OLEAUT32.274]
4313 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
4315 TRACE("( %f, %p ), stub\n", dblIn, pulOut );
4317 dblIn = round( dblIn );
4318 if( dblIn < UI4_MIN || dblIn > UI4_MAX )
4320 return DISP_E_OVERFLOW;
4323 *pulOut = (ULONG) dblIn;
4328 /******************************************************************************
4329 * VarUI4FromDate [OLEAUT32.275]
4331 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
4333 TRACE("( %f, %p ), stub\n", dateIn, pulOut );
4335 dateIn = round( dateIn );
4336 if( dateIn < UI4_MIN || dateIn > UI4_MAX )
4338 return DISP_E_OVERFLOW;
4341 *pulOut = (ULONG) dateIn;
4346 /******************************************************************************
4347 * VarUI4FromBool [OLEAUT32.279]
4349 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
4351 TRACE("( %d, %p ), stub\n", boolIn, pulOut );
4353 *pulOut = (ULONG) boolIn;
4358 /******************************************************************************
4359 * VarUI4FromI1 [OLEAUT32.280]
4361 HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
4363 TRACE("( %c, %p ), stub\n", cIn, pulOut );
4365 *pulOut = (ULONG) cIn;
4370 /******************************************************************************
4371 * VarUI4FromUI2 [OLEAUT32.281]
4373 HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4375 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4377 *pulOut = (ULONG) uiIn;
4382 /**********************************************************************
4383 * VarUI4FromCy [OLEAUT32.276]
4384 * Convert currency to unsigned long
4386 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
4387 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4389 if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4396 /**********************************************************************
4397 * VarCyFromUI1 [OLEAUT32.98]
4398 * Convert unsigned char to currency
4400 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
4402 pcyOut->s.Lo = ((ULONG)bIn) * 10000;
4407 /**********************************************************************
4408 * VarCyFromI2 [OLEAUT32.99]
4409 * Convert signed short to currency
4411 HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
4412 if (sIn < 0) pcyOut->s.Hi = -1;
4413 else pcyOut->s.Hi = 0;
4414 pcyOut->s.Lo = ((ULONG)sIn) * 10000;
4419 /**********************************************************************
4420 * VarCyFromI4 [OLEAUT32.100]
4421 * Convert signed long to currency
4423 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4424 double t = (double)lIn * (double)10000;
4425 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4426 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4427 if (lIn < 0) pcyOut->s.Hi--;
4432 /**********************************************************************
4433 * VarCyFromR4 [OLEAUT32.101]
4434 * Convert float to currency
4436 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
4437 double t = round((double)fltIn * (double)10000);
4438 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4439 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4440 if (fltIn < 0) pcyOut->s.Hi--;
4445 /**********************************************************************
4446 * VarCyFromR8 [OLEAUT32.102]
4447 * Convert double to currency
4449 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
4450 double t = round(dblIn * (double)10000);
4451 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4452 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4453 if (dblIn < 0) pcyOut->s.Hi--;
4458 /**********************************************************************
4459 * VarCyFromDate [OLEAUT32.103]
4460 * Convert date to currency
4462 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
4463 double t = round((double)dateIn * (double)10000);
4464 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4465 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4466 if (dateIn < 0) pcyOut->s.Hi--;
4471 /**********************************************************************
4472 * VarCyFromStr [OLEAUT32.104]
4473 * FIXME: Never tested with decimal seperator other than '.'
4475 HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
4477 LPSTR pNewString = NULL;
4478 char *decSep = NULL;
4479 char *strPtr,*curPtr = NULL;
4481 double currencyVal = 0.0;
4484 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4485 TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString, lcid, dwFlags, pcyOut );
4487 /* Get locale information - Decimal Seperator (size includes 0x00) */
4488 size = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, NULL, 0);
4489 decSep = (char *) malloc(size);
4490 rc = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, decSep, size);
4491 TRACE("Decimal Seperator is '%s'\n", decSep);
4493 /* Now copy to temporary buffer, skipping any character except 0-9 and
4494 the decimal seperator */
4495 curPtr = pBuffer; /* Current position in string being built */
4496 strPtr = pNewString; /* Current position in supplied currenct string */
4499 /* If decimal seperator, skip it and put '.' in string */
4500 if (strncmp(strPtr, decSep, (size-1)) == 0) {
4501 strPtr = strPtr + (size-1);
4504 } else if ((*strPtr == '+' || *strPtr == '-') ||
4505 (*strPtr >= '0' && *strPtr <= '9')) {
4513 /* Try to get currency into a double */
4514 currencyVal = atof(pBuffer);
4515 TRACE("Converted string '%s' to %f\n", pBuffer, currencyVal);
4517 /* Free allocated storage */
4518 HeapFree( GetProcessHeap(), 0, pNewString );
4521 /* Convert double -> currency using internal routine */
4522 return VarCyFromR8(currencyVal, pcyOut);
4526 /**********************************************************************
4527 * VarCyFromBool [OLEAUT32.106]
4528 * Convert boolean to currency
4530 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
4531 if (boolIn < 0) pcyOut->s.Hi = -1;
4532 else pcyOut->s.Hi = 0;
4533 pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
4538 /**********************************************************************
4539 * VarCyFromI1 [OLEAUT32.225]
4540 * Convert signed char to currency
4542 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
4543 if (cIn < 0) pcyOut->s.Hi = -1;
4544 else pcyOut->s.Hi = 0;
4545 pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
4550 /**********************************************************************
4551 * VarCyFromUI2 [OLEAUT32.226]
4552 * Convert unsigned short to currency
4554 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
4556 pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
4561 /**********************************************************************
4562 * VarCyFromUI4 [OLEAUT32.227]
4563 * Convert unsigned long to currency
4565 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4566 double t = (double)ulIn * (double)10000;
4567 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4568 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4574 /**********************************************************************
4575 * DosDateTimeToVariantTime [OLEAUT32.14]
4576 * Convert dos representation of time to the date and time representation
4577 * stored in a variant.
4579 INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4584 TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
4586 t.tm_sec = (wDosTime & 0x001f) * 2;
4587 t.tm_min = (wDosTime & 0x07e0) >> 5;
4588 t.tm_hour = (wDosTime & 0xf800) >> 11;
4590 t.tm_mday = (wDosDate & 0x001f);
4591 t.tm_mon = (wDosDate & 0x01e0) >> 5;
4592 t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
4594 return TmToDATE( &t, pvtime );
4598 /**********************************************************************
4599 * VarParseNumFromStr [OLEAUT32.46]
4601 HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
4602 NUMPARSE * pnumprs, BYTE * rgbDig)
4606 BOOL foundNum=FALSE;
4608 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
4609 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
4611 /* The other struct components are to be set by us */
4612 memset(rgbDig,0,pnumprs->cDig);
4614 /* FIXME: Just patching some values in */
4615 pnumprs->nPwr10 = 0;
4616 pnumprs->nBaseShift = 0;
4617 pnumprs->cchUsed = lastent;
4618 pnumprs->dwOutFlags = NUMPRS_DECIMAL;
4621 for (i=0; strIn[i] ;i++) {
4622 if ((strIn[i]>='0') && (strIn[i]<='9')) {
4624 if (pnumprs->cDig > cDig) {
4625 *(rgbDig++)=strIn[i]-'0';
4629 } else if ((strIn[i]=='-') && (foundNum==FALSE)) {
4630 pnumprs->dwOutFlags |= NUMPRS_NEG;
4633 pnumprs->cDig = cDig;
4634 TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags);
4639 /**********************************************************************
4640 * VarNumFromParseNum [OLEAUT32.47]
4642 HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
4643 ULONG dwVtBits, VARIANT * pvar)
4647 FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
4650 for (i=0;i<pnumprs->cDig;i++)
4651 xint = xint*10 + rgbDig[i];
4653 if (pnumprs->dwOutFlags & NUMPRS_NEG) {
4658 if (dwVtBits & VTBIT_I4) {
4660 V_UNION(pvar,intVal) = xint;
4663 if (dwVtBits & VTBIT_R8) {
4665 V_UNION(pvar,dblVal) = xint;
4668 if (dwVtBits & VTBIT_R4) {
4670 V_UNION(pvar,fltVal) = xint;
4673 if (dwVtBits & VTBIT_I2) {
4675 V_UNION(pvar,iVal) = xint;
4678 /* FIXME: Currency should be from a double */
4679 if (dwVtBits & VTBIT_CY) {
4681 TRACE("Calculated currency is xint=%ld\n", xint);
4682 VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4683 TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar,cyVal).s.Hi, V_UNION(pvar,cyVal).s.Lo);
4684 return VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4687 FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint);
4692 /**********************************************************************
4693 * VarFormatDateTime [OLEAUT32.97]
4695 HRESULT WINAPI VarFormatDateTime(LPVARIANT var, INT format, ULONG dwFlags, BSTR *out)
4697 FIXME("%p %d %lx %p\n", var, format, dwFlags, out);
4701 /**********************************************************************
4702 * VarFormatCurrency [OLEAUT32.127]
4704 HRESULT WINAPI VarFormatCurrency(LPVARIANT var, INT digits, INT lead, INT paren, INT group, ULONG dwFlags, BSTR *out)
4706 FIXME("%p %d %d %d %d %lx %p\n", var, digits, lead, paren, group, dwFlags, out);
4710 /**********************************************************************
4711 * VariantTimeToDosDateTime [OLEAUT32.13]
4712 * Convert variant representation of time to the date and time representation
4715 INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
4721 TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate, *wDosTime, &pvtime );
4723 if (DateToTm(pvtime, 0, &t) < 0) return 0;
4725 *wDosTime = *wDosTime | (t.tm_sec / 2);
4726 *wDosTime = *wDosTime | (t.tm_min << 5);
4727 *wDosTime = *wDosTime | (t.tm_hour << 11);
4729 *wDosDate = *wDosDate | t.tm_mday ;
4730 *wDosDate = *wDosDate | t.tm_mon << 5;
4731 *wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
4737 /***********************************************************************
4738 * SystemTimeToVariantTime [OLEAUT32.184]
4740 HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime, double *pvtime )
4744 TRACE(" %d/%d/%d %d:%d:%d\n",
4745 lpSystemTime->wMonth, lpSystemTime->wDay,
4746 lpSystemTime->wYear, lpSystemTime->wHour,
4747 lpSystemTime->wMinute, lpSystemTime->wSecond);
4749 if (lpSystemTime->wYear >= 1900)
4751 t.tm_sec = lpSystemTime->wSecond;
4752 t.tm_min = lpSystemTime->wMinute;
4753 t.tm_hour = lpSystemTime->wHour;
4755 t.tm_mday = lpSystemTime->wDay;
4756 t.tm_mon = lpSystemTime->wMonth - 1; /* tm_mon is 0..11, wMonth is 1..12 */
4757 t.tm_year = lpSystemTime->wYear;
4759 return TmToDATE( &t, pvtime );
4764 long firstDayOfNextYear;
4769 double decimalPart = 0.0;
4771 t.tm_sec = lpSystemTime->wSecond;
4772 t.tm_min = lpSystemTime->wMinute;
4773 t.tm_hour = lpSystemTime->wHour;
4775 /* Step year forward the same number of years before 1900 */
4776 t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
4777 t.tm_mon = lpSystemTime->wMonth - 1;
4778 t.tm_mday = lpSystemTime->wDay;
4780 /* Calculate date */
4781 TmToDATE( &t, pvtime );
4783 thisDay = (double) floor( *pvtime );
4784 decimalPart = fmod( *pvtime, thisDay );
4786 /* Now, calculate the same time for the first of Jan that year */
4792 t.tm_year = t.tm_year+1;
4793 TmToDATE( &t, &tmpDate );
4794 firstDayOfNextYear = (long) floor(tmpDate);
4796 /* Finally since we know the size of the year, subtract the two to get
4797 remaining time in the year */
4798 leftInYear = firstDayOfNextYear - thisDay;
4800 /* Now we want full years up to the year in question, and remainder of year
4801 of the year in question */
4802 if (isleap(lpSystemTime->wYear) ) {
4803 TRACE("Extra day due to leap year\n");
4804 result = 2.0 - ((firstDayOfNextYear - 366) + leftInYear - 2.0);
4806 result = 2.0 - ((firstDayOfNextYear - 365) + leftInYear - 2.0);
4808 *pvtime = (double) result + decimalPart;
4809 TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime, firstDayOfNextYear, thisDay, leftInYear);
4817 /***********************************************************************
4818 * VariantTimeToSystemTime [OLEAUT32.185]
4820 HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME lpSystemTime )
4822 double t = 0, timeofday = 0;
4824 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4825 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4827 /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4828 static const BYTE Month_Code[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4829 static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4831 /* The Century_Code is used to find the Day of the Week */
4832 static const BYTE Century_Code[] = {0, 6, 4, 2};
4836 TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime);
4841 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4843 lpSystemTime->wSecond = r.tm_sec;
4844 lpSystemTime->wMinute = r.tm_min;
4845 lpSystemTime->wHour = r.tm_hour;
4846 lpSystemTime->wDay = r.tm_mday;
4847 lpSystemTime->wMonth = r.tm_mon;
4849 if (lpSystemTime->wMonth == 12)
4850 lpSystemTime->wMonth = 1;
4852 lpSystemTime->wMonth++;
4854 lpSystemTime->wYear = r.tm_year;
4860 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4862 lpSystemTime->wSecond = r.tm_sec;
4863 lpSystemTime->wMinute = r.tm_min;
4864 lpSystemTime->wHour = r.tm_hour;
4866 lpSystemTime->wMonth = 13 - r.tm_mon;
4868 if (lpSystemTime->wMonth == 1)
4869 lpSystemTime->wMonth = 12;
4871 lpSystemTime->wMonth--;
4873 lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
4875 if (!isleap(lpSystemTime->wYear) )
4876 lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
4878 lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
4883 if (!isleap(lpSystemTime->wYear))
4886 (Century_Code+Month_Code+Year_Code+Day) % 7
4888 The century code repeats every 400 years , so the array
4889 works out like this,
4891 Century_Code[0] is for 16th/20th Centry
4892 Century_Code[1] is for 17th/21th Centry
4893 Century_Code[2] is for 18th/22th Centry
4894 Century_Code[3] is for 19th/23th Centry
4896 The year code is found with the formula (year + (year / 4))
4897 the "year" must be between 0 and 99 .
4899 The Month Code (Month_Code[1]) starts with January and
4903 lpSystemTime->wDayOfWeek = (
4904 Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
4905 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4906 Month_Code[lpSystemTime->wMonth]+
4907 lpSystemTime->wDay) % 7;
4909 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4910 else lpSystemTime->wDayOfWeek -= 1;
4914 lpSystemTime->wDayOfWeek = (
4915 Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
4916 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4917 Month_Code_LY[lpSystemTime->wMonth]+
4918 lpSystemTime->wDay) % 7;
4920 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4921 else lpSystemTime->wDayOfWeek -= 1;
4925 timeofday = vtime - t;
4927 lpSystemTime->wMilliseconds = (timeofday
4928 - lpSystemTime->wHour*(1/24)
4929 - lpSystemTime->wMinute*(1/1440)
4930 - lpSystemTime->wSecond*(1/86400) )*(1/5184000);
4935 /***********************************************************************
4936 * VarUdateFromDate [OLEAUT32.331]
4938 HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
4941 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4942 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4944 TRACE("DATE = %f\n", (double)datein);
4945 i = VariantTimeToSystemTime(datein, &(pudateout->st) );
4949 pudateout->wDayOfYear = 0;
4951 if (isleap(pudateout->st.wYear))
4953 for (i =1; i<pudateout->st.wMonth; i++)
4954 pudateout->wDayOfYear += Days_Per_Month[i];
4958 for (i =1; i<pudateout->st.wMonth; i++)
4959 pudateout->wDayOfYear += Days_Per_Month_LY[i];
4962 pudateout->wDayOfYear += pudateout->st.wDay;
4963 dwFlags = 0; /*VAR_VALIDDATE*/
4970 /***********************************************************************
4971 * VarDateFromUdate [OLEAUT32.330]
4973 HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
4974 ULONG dwFlags, DATE *datein)
4978 TRACE(" %d/%d/%d %d:%d:%d\n",
4979 pudateout->st.wMonth, pudateout->st.wDay,
4980 pudateout->st.wYear, pudateout->st.wHour,
4981 pudateout->st.wMinute, pudateout->st.wSecond);
4984 i = SystemTimeToVariantTime(&(pudateout->st), &t);
4988 else return E_INVALIDARG;
4992 /**********************************************************************
4993 * VarBstrCmp [OLEAUT32.314]
4996 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4997 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
5000 HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
5004 TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
5006 /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
5007 if((!left) || (!right)) {
5009 if (!left && (!right || *right==0)) return VARCMP_EQ;
5010 else if (!right && (!left || *left==0)) return VARCMP_EQ;
5011 else return VARCMP_NULL;
5014 if(flags&NORM_IGNORECASE)
5015 r = lstrcmpiW(left,right);
5017 r = lstrcmpW(left,right);
5027 /**********************************************************************
5028 * VarBstrCat [OLEAUT32.313]
5030 HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
5035 TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
5037 /* On Windows, NULL parms are still handled (as empty strings) */
5038 if (left) size=size + lstrlenW(left);
5039 if (right) size=size + lstrlenW(right);
5042 result = SysAllocStringLen(NULL, size);
5044 if (left) lstrcatW(result,left);
5045 if (right) lstrcatW(result,right);
5046 TRACE("result = %s, [%p]\n", debugstr_w(result), result);
5051 /**********************************************************************
5052 * VarCat [OLEAUT32.318]
5054 HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
5056 /* Should we VariantClear out? */
5057 /* Can we handle array, vector, by ref etc. */
5058 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL &&
5059 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
5061 V_VT(out) = VT_NULL;
5065 if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR)
5067 V_VT(out) = VT_BSTR;
5068 VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out));
5071 if (V_VT(left) == VT_BSTR) {
5075 V_VT(out) = VT_BSTR;
5076 hres = VariantChangeTypeEx(&bstrvar,right,0,0,VT_BSTR);
5078 FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right));
5081 VarBstrCat (V_BSTR(left), V_BSTR(&bstrvar), &V_BSTR(out));
5084 if (V_VT(right) == VT_BSTR) {
5088 V_VT(out) = VT_BSTR;
5089 hres = VariantChangeTypeEx(&bstrvar,left,0,0,VT_BSTR);
5091 FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right));
5094 VarBstrCat (V_BSTR(&bstrvar), V_BSTR(right), &V_BSTR(out));
5097 FIXME ("types %d / %d not supported\n",V_VT(left)&VT_TYPEMASK, V_VT(right)&VT_TYPEMASK);
5101 /**********************************************************************
5102 * VarCmp [OLEAUT32.176]
5105 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
5106 * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
5109 HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
5121 VariantInit(&lv);VariantInit(&rv);
5122 V_VT(right) &= ~0x8000; /* hack since we sometime get this flag. */
5123 V_VT(left) &= ~0x8000; /* hack since we sometime get this flag. */
5125 TRACE("Left Var:\n");
5127 TRACE("Right Var:\n");
5128 dump_Variant(right);
5130 /* If either are null, then return VARCMP_NULL */
5131 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL ||
5132 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
5135 /* Strings - use VarBstrCmp */
5136 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
5137 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
5138 return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags);
5141 xmask = (1<<(V_VT(left)&VT_TYPEMASK))|(1<<(V_VT(right)&VT_TYPEMASK));
5142 if (xmask & (1<<VT_R8)) {
5143 rc = VariantChangeType(&lv,left,0,VT_R8);
5144 if (FAILED(rc)) return rc;
5145 rc = VariantChangeType(&rv,right,0,VT_R8);
5146 if (FAILED(rc)) return rc;
5148 if (V_R8(&lv) == V_R8(&rv)) return VARCMP_EQ;
5149 if (V_R8(&lv) < V_R8(&rv)) return VARCMP_LT;
5150 if (V_R8(&lv) > V_R8(&rv)) return VARCMP_GT;
5151 return E_FAIL; /* can't get here */
5153 if (xmask & (1<<VT_R4)) {
5154 rc = VariantChangeType(&lv,left,0,VT_R4);
5155 if (FAILED(rc)) return rc;
5156 rc = VariantChangeType(&rv,right,0,VT_R4);
5157 if (FAILED(rc)) return rc;
5159 if (V_R4(&lv) == V_R4(&rv)) return VARCMP_EQ;
5160 if (V_R4(&lv) < V_R4(&rv)) return VARCMP_LT;
5161 if (V_R4(&lv) > V_R4(&rv)) return VARCMP_GT;
5162 return E_FAIL; /* can't get here */
5165 /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
5166 Use LONGLONG to maximize ranges */
5168 switch (V_VT(left)&VT_TYPEMASK) {
5169 case VT_I1 : lVal = V_UNION(left,cVal); break;
5170 case VT_I2 : lVal = V_UNION(left,iVal); break;
5171 case VT_I4 : lVal = V_UNION(left,lVal); break;
5172 case VT_INT : lVal = V_UNION(left,lVal); break;
5173 case VT_UI1 : lVal = V_UNION(left,bVal); break;
5174 case VT_UI2 : lVal = V_UNION(left,uiVal); break;
5175 case VT_UI4 : lVal = V_UNION(left,ulVal); break;
5176 case VT_UINT : lVal = V_UNION(left,ulVal); break;
5177 case VT_BOOL : lVal = V_UNION(left,boolVal); break;
5178 default: lOk = FALSE;
5182 switch (V_VT(right)&VT_TYPEMASK) {
5183 case VT_I1 : rVal = V_UNION(right,cVal); break;
5184 case VT_I2 : rVal = V_UNION(right,iVal); break;
5185 case VT_I4 : rVal = V_UNION(right,lVal); break;
5186 case VT_INT : rVal = V_UNION(right,lVal); break;
5187 case VT_UI1 : rVal = V_UNION(right,bVal); break;
5188 case VT_UI2 : rVal = V_UNION(right,uiVal); break;
5189 case VT_UI4 : rVal = V_UNION(right,ulVal); break;
5190 case VT_UINT : rVal = V_UNION(right,ulVal); break;
5191 case VT_BOOL : rVal = V_UNION(right,boolVal); break;
5192 default: rOk = FALSE;
5198 } else if (lVal > rVal) {
5205 /* Strings - use VarBstrCmp */
5206 if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
5207 (V_VT(right)&VT_TYPEMASK) == VT_DATE) {
5209 if (floor(V_UNION(left,date)) == floor(V_UNION(right,date))) {
5210 /* Due to floating point rounding errors, calculate varDate in whole numbers) */
5211 double wholePart = 0.0;
5215 /* Get the fraction * 24*60*60 to make it into whole seconds */
5216 wholePart = (double) floor( V_UNION(left,date) );
5217 if (wholePart == 0) wholePart = 1;
5218 leftR = floor(fmod( V_UNION(left,date), wholePart ) * (24*60*60));
5220 wholePart = (double) floor( V_UNION(right,date) );
5221 if (wholePart == 0) wholePart = 1;
5222 rightR = floor(fmod( V_UNION(right,date), wholePart ) * (24*60*60));
5224 if (leftR < rightR) {
5226 } else if (leftR > rightR) {
5232 } else if (V_UNION(left,date) < V_UNION(right,date)) {
5234 } else if (V_UNION(left,date) > V_UNION(right,date)) {
5238 FIXME("VarCmp partial implementation, doesnt support vt 0x%x / 0x%x\n",V_VT(left), V_VT(right));
5242 /**********************************************************************
5243 * VarAnd [OLEAUT32.142]
5246 HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5248 HRESULT rc = E_FAIL;
5250 TRACE("Left Var:\n");
5252 TRACE("Right Var:\n");
5253 dump_Variant(right);
5255 if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5256 (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5258 V_VT(result) = VT_BOOL;
5259 if (V_BOOL(left) && V_BOOL(right)) {
5260 V_BOOL(result) = VARIANT_TRUE;
5262 V_BOOL(result) = VARIANT_FALSE;
5273 int resT = 0; /* Testing has shown I2 & I2 == I2, all else
5274 becomes I4, even unsigned ints (incl. UI2) */
5277 switch (V_VT(left)&VT_TYPEMASK) {
5278 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
5279 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
5280 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5281 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5282 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
5283 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5284 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5285 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5286 default: lOk = FALSE;
5290 switch (V_VT(right)&VT_TYPEMASK) {
5291 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
5292 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
5293 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5294 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5295 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
5296 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5297 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5298 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5299 default: rOk = FALSE;
5303 res = (lVal & rVal);
5304 V_VT(result) = resT;
5306 case VT_I2 : V_UNION(result,iVal) = res; break;
5307 case VT_I4 : V_UNION(result,lVal) = res; break;
5309 FIXME("Unexpected result variant type %x\n", resT);
5310 V_UNION(result,lVal) = res;
5315 FIXME("VarAnd stub\n");
5319 TRACE("rc=%d, Result:\n", (int) rc);
5320 dump_Variant(result);
5324 /**********************************************************************
5325 * VarAdd [OLEAUT32.141]
5326 * FIXME: From MSDN: If ... Then
5327 * Both expressions are of the string type Concatenated.
5328 * One expression is a string type and the other a character Addition.
5329 * One expression is numeric and the other is a string Addition.
5330 * Both expressions are numeric Addition.
5331 * Either expression is NULL NULL is returned.
5332 * Both expressions are empty Integer subtype is returned.
5335 HRESULT WINAPI VarAdd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5337 HRESULT rc = E_FAIL;
5339 TRACE("Left Var:\n");
5341 TRACE("Right Var:\n");
5342 dump_Variant(right);
5344 /* Handle strings as concat */
5345 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
5346 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
5347 V_VT(result) = VT_BSTR;
5348 rc = VarBstrCat(V_BSTR(left), V_BSTR(right), &V_BSTR(result));
5357 int resT = 0; /* Testing has shown I2 + I2 == I2, all else
5361 switch (V_VT(left)&VT_TYPEMASK) {
5362 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
5363 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
5364 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5365 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5366 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
5367 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5368 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5369 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5370 default: lOk = FALSE;
5374 switch (V_VT(right)&VT_TYPEMASK) {
5375 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
5376 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
5377 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5378 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5379 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
5380 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5381 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5382 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5383 default: rOk = FALSE;
5387 res = (lVal + rVal);
5388 V_VT(result) = resT;
5390 case VT_I2 : V_UNION(result,iVal) = res; break;
5391 case VT_I4 : V_UNION(result,lVal) = res; break;
5393 FIXME("Unexpected result variant type %x\n", resT);
5394 V_UNION(result,lVal) = res;
5399 FIXME("unimplemented part\n");
5403 TRACE("rc=%d, Result:\n", (int) rc);
5404 dump_Variant(result);
5408 /**********************************************************************
5409 * VarMul [OLEAUT32.156]
5412 HRESULT WINAPI VarMul(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5414 HRESULT rc = E_FAIL;
5415 VARTYPE lvt,rvt,resvt;
5419 TRACE("left: ");dump_Variant(left);
5420 TRACE("right: ");dump_Variant(right);
5422 VariantInit(&lv);VariantInit(&rv);
5423 lvt = V_VT(left)&VT_TYPEMASK;
5424 rvt = V_VT(right)&VT_TYPEMASK;
5425 found = FALSE;resvt=VT_VOID;
5426 if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
5430 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)))) {
5435 FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
5438 rc = VariantChangeType(&lv, left, 0, resvt);
5440 FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
5443 rc = VariantChangeType(&rv, right, 0, resvt);
5445 FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
5450 V_VT(result) = resvt;
5451 V_R8(result) = V_R8(&lv) * V_R8(&rv);
5455 V_VT(result) = resvt;
5456 V_I4(result) = V_I4(&lv) * V_I4(&rv);
5460 TRACE("rc=%d, Result:\n", (int) rc);
5461 dump_Variant(result);
5465 /**********************************************************************
5466 * VarDiv [OLEAUT32.143]
5469 HRESULT WINAPI VarDiv(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5471 HRESULT rc = E_FAIL;
5472 VARTYPE lvt,rvt,resvt;
5476 TRACE("left: ");dump_Variant(left);
5477 TRACE("right: ");dump_Variant(right);
5479 VariantInit(&lv);VariantInit(&rv);
5480 lvt = V_VT(left)&VT_TYPEMASK;
5481 rvt = V_VT(right)&VT_TYPEMASK;
5482 found = FALSE;resvt = VT_VOID;
5483 if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
5487 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)))) {
5492 FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
5495 rc = VariantChangeType(&lv, left, 0, resvt);
5497 FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
5500 rc = VariantChangeType(&rv, right, 0, resvt);
5502 FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
5507 V_VT(result) = resvt;
5508 V_R8(result) = V_R8(&lv) / V_R8(&rv);
5512 V_VT(result) = resvt;
5513 V_I4(result) = V_I4(&lv) / V_I4(&rv);
5517 TRACE("rc=%d, Result:\n", (int) rc);
5518 dump_Variant(result);
5522 /**********************************************************************
5523 * VarSub [OLEAUT32.159]
5526 HRESULT WINAPI VarSub(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5528 HRESULT rc = E_FAIL;
5529 VARTYPE lvt,rvt,resvt;
5533 TRACE("left: ");dump_Variant(left);
5534 TRACE("right: ");dump_Variant(right);
5536 VariantInit(&lv);VariantInit(&rv);
5537 lvt = V_VT(left)&VT_TYPEMASK;
5538 rvt = V_VT(right)&VT_TYPEMASK;
5539 found = FALSE;resvt = VT_VOID;
5540 if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
5544 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)))) {
5549 FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
5552 rc = VariantChangeType(&lv, left, 0, resvt);
5554 FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
5557 rc = VariantChangeType(&rv, right, 0, resvt);
5559 FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
5564 V_VT(result) = resvt;
5565 V_R8(result) = V_R8(&lv) - V_R8(&rv);
5569 V_VT(result) = resvt;
5570 V_I4(result) = V_I4(&lv) - V_I4(&rv);
5574 TRACE("rc=%d, Result:\n", (int) rc);
5575 dump_Variant(result);
5579 /**********************************************************************
5580 * VarOr [OLEAUT32.157]
5583 HRESULT WINAPI VarOr(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5585 HRESULT rc = E_FAIL;
5587 TRACE("Left Var:\n");
5589 TRACE("Right Var:\n");
5590 dump_Variant(right);
5592 if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5593 (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5595 V_VT(result) = VT_BOOL;
5596 if (V_BOOL(left) || V_BOOL(right)) {
5597 V_BOOL(result) = VARIANT_TRUE;
5599 V_BOOL(result) = VARIANT_FALSE;
5610 int resT = 0; /* Testing has shown I2 & I2 == I2, all else
5611 becomes I4, even unsigned ints (incl. UI2) */
5614 switch (V_VT(left)&VT_TYPEMASK) {
5615 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
5616 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
5617 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5618 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5619 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
5620 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5621 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5622 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5623 default: lOk = FALSE;
5627 switch (V_VT(right)&VT_TYPEMASK) {
5628 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
5629 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
5630 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5631 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5632 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
5633 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5634 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5635 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5636 default: rOk = FALSE;
5640 res = (lVal | rVal);
5641 V_VT(result) = resT;
5643 case VT_I2 : V_UNION(result,iVal) = res; break;
5644 case VT_I4 : V_UNION(result,lVal) = res; break;
5646 FIXME("Unexpected result variant type %x\n", resT);
5647 V_UNION(result,lVal) = res;
5652 FIXME("unimplemented part\n");
5656 TRACE("rc=%d, Result:\n", (int) rc);
5657 dump_Variant(result);
5661 /**********************************************************************
5662 * VarNot [OLEAUT32.174]
5665 HRESULT WINAPI VarNot(LPVARIANT in, LPVARIANT result)
5667 HRESULT rc = E_FAIL;
5672 if ((V_VT(in)&VT_TYPEMASK) == VT_BOOL) {
5674 V_VT(result) = VT_BOOL;
5676 V_BOOL(result) = VARIANT_FALSE;
5678 V_BOOL(result) = VARIANT_TRUE;
5683 FIXME("VarNot stub\n");
5686 TRACE("rc=%d, Result:\n", (int) rc);
5687 dump_Variant(result);
5691 /**********************************************************************
5692 * VarTokenizeFormatString [OLEAUT32.140]
5694 * From investigation on W2K, a list is built up which is:
5696 * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
5697 * <token> - Insert appropriate token
5700 HRESULT WINAPI VarTokenizeFormatString(LPOLESTR format, LPBYTE rgbTok,
5701 int cbTok, int iFirstDay, int iFirstWeek,
5702 LCID lcid, int *pcbActual) {
5705 int realLen, formatLeft;
5707 LPSTR pFormatA, pStart;
5709 BOOL insertCopy = FALSE;
5710 LPSTR copyFrom = NULL;
5712 TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format), rgbTok, cbTok,
5713 iFirstDay, iFirstWeek);
5715 /* Big enough for header? */
5716 if (cbTok < sizeof(FORMATHDR)) {
5717 return TYPE_E_BUFFERTOOSMALL;
5721 hdr = (FORMATHDR *) rgbTok;
5722 memset(hdr, 0x00, sizeof(FORMATHDR));
5723 hdr->hex3 = 0x03; /* No idea what these are */
5726 /* Start parsing string */
5727 realLen = sizeof(FORMATHDR);
5728 pData = rgbTok + realLen;
5729 pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5731 formatLeft = strlen(pFormatA);
5733 /* Work through the format */
5734 while (*pFormatA != 0x00) {
5737 while (checkStr>=0 && (formatTokens[checkStr].tokenSize != 0x00)) {
5738 if (formatLeft >= formatTokens[checkStr].tokenSize &&
5739 strncmp(formatTokens[checkStr].str, pFormatA,
5740 formatTokens[checkStr].tokenSize) == 0) {
5741 TRACE("match on '%s'\n", formatTokens[checkStr].str);
5745 /* If we have skipped chars, insert the copy */
5746 if (insertCopy == TRUE) {
5748 if ((realLen + 3) > cbTok) {
5749 HeapFree( GetProcessHeap(), 0, pFormatA );
5750 return TYPE_E_BUFFERTOOSMALL;
5755 *pData = (BYTE)(copyFrom - pStart);
5757 *pData = (BYTE)(pFormatA - copyFrom);
5759 realLen = realLen + 3;
5763 /* Now insert the token itself */
5764 if ((realLen + 1) > cbTok) {
5765 HeapFree( GetProcessHeap(), 0, pFormatA );
5766 return TYPE_E_BUFFERTOOSMALL;
5768 *pData = formatTokens[checkStr].tokenId;
5770 realLen = realLen + 1;
5772 pFormatA = pFormatA + formatTokens[checkStr].tokenSize;
5773 formatLeft = formatLeft - formatTokens[checkStr].tokenSize;
5774 checkStr = -1; /* Flag as found and break out of while loop */
5780 /* Did we ever match a token? */
5781 if (checkStr != -1 && insertCopy == FALSE) {
5782 TRACE("No match - need to insert copy from %p [%p]\n", pFormatA, pStart);
5784 copyFrom = pFormatA;
5785 } else if (checkStr != -1) {
5786 pFormatA = pFormatA + 1;
5791 /* Finally, if we have skipped chars, insert the copy */
5792 if (insertCopy == TRUE) {
5794 TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom, pStart, pFormatA);
5795 if ((realLen + 3) > cbTok) {
5796 HeapFree( GetProcessHeap(), 0, pFormatA );
5797 return TYPE_E_BUFFERTOOSMALL;
5802 *pData = (BYTE)(copyFrom - pStart);
5804 *pData = (BYTE)(pFormatA - copyFrom);
5806 realLen = realLen + 3;
5809 /* Finally insert the terminator */
5810 if ((realLen + 1) > cbTok) {
5811 HeapFree( GetProcessHeap(), 0, pFormatA );
5812 return TYPE_E_BUFFERTOOSMALL;
5815 realLen = realLen + 1;
5817 /* Finally fill in the length */
5819 *pcbActual = realLen;
5823 for (i=0; i<realLen; i=i+0x10) {
5824 printf(" %4.4x : ", i);
5825 for (j=0; j<0x10 && (i+j < realLen); j++) {
5826 printf("%2.2x ", rgbTok[i+j]);
5832 HeapFree( GetProcessHeap(), 0, pFormatA );
5837 /**********************************************************************
5838 * VarFormatFromTokens [OLEAUT32.139]
5839 * FIXME: No account of flags or iFirstDay etc
5841 HRESULT WINAPI VarFormatFromTokens(LPVARIANT varIn, LPOLESTR format,
5842 LPBYTE pbTokCur, ULONG dwFlags, BSTR *pbstrOut,
5845 FORMATHDR *hdr = (FORMATHDR *)pbTokCur;
5846 BYTE *pData = pbTokCur + sizeof (FORMATHDR);
5847 LPSTR pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5848 char output[BUFFER_MAX];
5850 int size, whichToken;
5856 TRACE("'%s', %p %lx %p only date support\n", pFormatA, pbTokCur, dwFlags, pbstrOut);
5858 dump_Variant(varIn);
5860 memset(output, 0x00, BUFFER_MAX);
5863 while (*pData != TOK_END && ((pData - pbTokCur) <= (hdr->len))) {
5865 TRACE("Output looks like : '%s'\n", output);
5867 /* Convert varient to appropriate data type */
5869 while ((formatTokens[whichToken].tokenSize != 0x00) &&
5870 (formatTokens[whichToken].tokenId != *pData)) {
5874 /* Use Variant local from here downwards as always correct type */
5875 if (formatTokens[whichToken].tokenSize > 0 &&
5876 formatTokens[whichToken].varTypeRequired != 0) {
5877 VariantInit( &Variant );
5878 if (Coerce( &Variant, lcid, dwFlags, varIn,
5879 formatTokens[whichToken].varTypeRequired ) != S_OK) {
5880 HeapFree( GetProcessHeap(), 0, pFormatA );
5881 return DISP_E_TYPEMISMATCH;
5882 } else if (formatTokens[whichToken].varTypeRequired == VT_DATE) {
5883 if( DateToTm( V_UNION(&Variant,date), dwFlags, &TM ) == FALSE ) {
5884 HeapFree( GetProcessHeap(), 0, pFormatA );
5885 return E_INVALIDARG;
5890 TRACE("Looking for match on token '%x'\n", *pData);
5893 TRACE("Copy from %d for %d bytes\n", *(pData+1), *(pData+2));
5894 memcpy(pNextPos, &pFormatA[*(pData+1)], *(pData+2));
5895 pNextPos = pNextPos + *(pData+2);
5900 /* Get locale information - Time Seperator */
5901 size = GetLocaleInfoA(lcid, LOCALE_STIME, NULL, 0);
5902 GetLocaleInfoA(lcid, LOCALE_STIME, pNextPos, size);
5903 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5904 pNextPos = pNextPos + size;
5909 /* Get locale information - Date Seperator */
5910 size = GetLocaleInfoA(lcid, LOCALE_SDATE, NULL, 0);
5911 GetLocaleInfoA(lcid, LOCALE_SDATE, pNextPos, size);
5912 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5913 pNextPos = pNextPos + size;
5918 sprintf(pNextPos, "%d", TM.tm_mday);
5919 pNextPos = pNextPos + strlen(pNextPos);
5924 sprintf(pNextPos, "%2.2d", TM.tm_mday);
5925 pNextPos = pNextPos + strlen(pNextPos);
5930 sprintf(pNextPos, "%d", TM.tm_wday+1);
5931 pNextPos = pNextPos + strlen(pNextPos);
5936 sprintf(pNextPos, "%d", TM.tm_mon+1);
5937 pNextPos = pNextPos + strlen(pNextPos);
5942 sprintf(pNextPos, "%2.2d", TM.tm_mon+1);
5943 pNextPos = pNextPos + strlen(pNextPos);
5948 sprintf(pNextPos, "%d", ((TM.tm_mon+1)/4)+1);
5949 pNextPos = pNextPos + strlen(pNextPos);
5954 sprintf(pNextPos, "%2.2d", TM.tm_yday+1);
5955 pNextPos = pNextPos + strlen(pNextPos);
5960 sprintf(pNextPos, "%2.2d", TM.tm_year);
5961 pNextPos = pNextPos + strlen(pNextPos);
5966 sprintf(pNextPos, "%4.4d", TM.tm_year);
5967 pNextPos = pNextPos + strlen(pNextPos);
5972 sprintf(pNextPos, "%d", TM.tm_hour);
5973 pNextPos = pNextPos + strlen(pNextPos);
5978 sprintf(pNextPos, "%2.2d", TM.tm_hour);
5979 pNextPos = pNextPos + strlen(pNextPos);
5984 sprintf(pNextPos, "%d", TM.tm_min);
5985 pNextPos = pNextPos + strlen(pNextPos);
5990 sprintf(pNextPos, "%2.2d", TM.tm_min);
5991 pNextPos = pNextPos + strlen(pNextPos);
5996 sprintf(pNextPos, "%d", TM.tm_sec);
5997 pNextPos = pNextPos + strlen(pNextPos);
6002 sprintf(pNextPos, "%2.2d", TM.tm_sec);
6003 pNextPos = pNextPos + strlen(pNextPos);
6023 FIXME("Unhandled token for VarFormat %d\n", *pData);
6024 HeapFree( GetProcessHeap(), 0, pFormatA );
6025 return E_INVALIDARG;
6030 *pbstrOut = StringDupAtoBstr( output );
6031 HeapFree( GetProcessHeap(), 0, pFormatA );
6035 /**********************************************************************
6036 * VarFormat [OLEAUT32.87]
6039 HRESULT WINAPI VarFormat(LPVARIANT varIn, LPOLESTR format,
6040 int firstDay, int firstWeek, ULONG dwFlags,
6043 LPSTR pNewString = NULL;
6046 TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
6047 debugstr_w(format), firstDay, firstWeek, dwFlags);
6049 dump_Variant(varIn);
6051 /* Note: Must Handle references type Variants (contain ptrs
6052 to values rather than values */
6054 /* Get format string */
6055 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
6057 /* FIXME: Handle some simple pre-definted format strings : */
6058 if (((V_VT(varIn)&VT_TYPEMASK) == VT_CY) && (lstrcmpiA(pNewString, "Currency") == 0)) {
6060 /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
6064 /* Handle references type Variants (contain ptrs to values rather than values */
6065 if (V_VT(varIn)&VT_BYREF) {
6066 rc = VarR8FromCy(*(CY *)V_UNION(varIn,byref), &curVal);
6068 rc = VarR8FromCy(V_UNION(varIn,cyVal), &curVal);
6072 char tmpStr[BUFFER_MAX];
6073 sprintf(tmpStr, "%f", curVal);
6074 if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags, tmpStr, NULL, pBuffer, BUFFER_MAX) == 0) {
6077 *pbstrOut = StringDupAtoBstr( pBuffer );
6081 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_DATE) {
6083 /* Attempt to do proper formatting! */
6084 int firstToken = -1;
6086 rc = VarTokenizeFormatString(format, pBuffer, sizeof(pBuffer), firstDay,
6087 firstWeek, GetUserDefaultLCID(), &firstToken);
6089 rc = VarFormatFromTokens(varIn, format, pBuffer, dwFlags, pbstrOut, GetUserDefaultLCID());
6092 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_R8) {
6093 if (V_VT(varIn)&VT_BYREF) {
6094 sprintf(pBuffer, "%f", *V_UNION(varIn,pdblVal));
6096 sprintf(pBuffer, "%f", V_UNION(varIn,dblVal));
6098 *pbstrOut = StringDupAtoBstr( pBuffer );
6099 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_I2) {
6100 if (V_VT(varIn)&VT_BYREF) {
6101 sprintf(pBuffer, "%d", *V_UNION(varIn,piVal));
6103 sprintf(pBuffer, "%d", V_UNION(varIn,iVal));
6105 *pbstrOut = StringDupAtoBstr( pBuffer );
6106 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_BSTR) {
6107 if (V_VT(varIn)&VT_BYREF)
6108 *pbstrOut = SysAllocString( *V_UNION(varIn,pbstrVal) );
6110 *pbstrOut = SysAllocString( V_UNION(varIn,bstrVal) );
6112 FIXME("VarFormat: Unsupported format %d!\n", V_VT(varIn)&VT_TYPEMASK);
6113 *pbstrOut = StringDupAtoBstr( "??" );
6116 /* Free allocated storage */
6117 HeapFree( GetProcessHeap(), 0, pNewString );
6118 TRACE("result: '%s'\n", debugstr_w(*pbstrOut));
6122 /**********************************************************************
6123 * VarCyMulI4 [OLEAUT32.304]
6124 * Multiply currency value by integer
6126 HRESULT WINAPI VarCyMulI4(CY cyIn, LONG mulBy, CY *pcyOut) {
6131 rc = VarR8FromCy(cyIn, &cyVal);
6133 rc = VarCyFromR8((cyVal * (double) mulBy), pcyOut);
6134 TRACE("Multiply %f by %ld = %f [%ld,%lu]\n", cyVal, mulBy, (cyVal * (double) mulBy),
6135 pcyOut->s.Hi, pcyOut->s.Lo);