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.
52 #include "wine/debug.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(ole);
59 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
63 # define FLT_MAX MAXFLOAT
65 # error "Can't find #define for MAXFLOAT/FLT_MAX"
71 static const char CHAR_MAX = 127;
72 static const char CHAR_MIN = -128;
73 static const BYTE UI1_MAX = 255;
74 static const BYTE UI1_MIN = 0;
75 static const unsigned short UI2_MAX = 65535;
76 static const unsigned short UI2_MIN = 0;
77 static const short I2_MAX = 32767;
78 static const short I2_MIN = -32768;
79 static const unsigned long UI4_MAX = 4294967295U;
80 static const unsigned long UI4_MIN = 0;
81 static const long I4_MAX = 2147483647;
82 static const long I4_MIN = -(2147483648U);
83 static const DATE DATE_MIN = -657434;
84 static const DATE DATE_MAX = 2958465;
86 /* the largest valid type
88 #define VT_MAXVALIDTYPE VT_CLSID
90 /* This mask is used to set a flag in wReserved1 of
91 * the VARIANTARG structure. The flag indicates if
92 * the API function is using an inner variant or not.
94 #define PROCESSING_INNER_VARIANT 0x0001
96 /* General use buffer.
98 #define BUFFER_MAX 1024
99 static char pBuffer[BUFFER_MAX];
102 * Note a leap year is one that is a multiple of 4
103 * but not of a 100. Except if it is a multiple of
104 * 400 then it is a leap year.
108 * Use 365 days/year and a manual calculation for leap year days
109 * to keep arithmetic simple
111 static const double DAYS_IN_ONE_YEAR = 365.0;
114 * Token definitions for Varient Formatting
115 * Worked out by experimentation on a w2k machine. Doesnt appear to be
116 * documented anywhere obviously so keeping definitions internally
119 /* Pre defined tokens */
120 #define TOK_COPY 0x00
122 #define LARGEST_TOKENID 6
124 /* Mapping of token name to id put into the tokenized form
125 Note testing on W2K shows aaaa and oooo are not parsed??!! */
126 #define TOK_COLON 0x03
127 #define TOK_SLASH 0x04
132 #define TOK_dddd 0x0b
133 #define TOK_ddddd 0x0c
134 #define TOK_dddddd 0x0d
140 #define TOK_mmmm 0x14
144 #define TOK_yyyy 0x18
151 #define TOK_ttttt 0x07
152 #define TOK_AMsPM 0x2f
153 #define TOK_amspm 0x32
156 #define TOK_AMPM 0x2e
158 typedef struct tagFORMATTOKEN {
165 typedef struct tagFORMATHDR {
172 FORMATTOKEN formatTokens[] = { /* FIXME: Only date formats so far */
173 {":" , 1, TOK_COLON , 0},
174 {"/" , 1, TOK_SLASH , 0},
175 {"c" , 1, TOK_c , VT_DATE},
176 {"dddddd", 6, TOK_dddddd , VT_DATE},
177 {"ddddd" , 5, TOK_ddddd , VT_DATE},
178 {"dddd" , 4, TOK_dddd , VT_DATE},
179 {"ddd" , 3, TOK_ddd , VT_DATE},
180 {"dd" , 2, TOK_dd , VT_DATE},
181 {"d" , 1, TOK_d , VT_DATE},
182 {"ww" , 2, TOK_ww , VT_DATE},
183 {"w" , 1, TOK_w , VT_DATE},
184 {"mmmm" , 4, TOK_mmmm , VT_DATE},
185 {"mmm" , 3, TOK_mmm , VT_DATE},
186 {"mm" , 2, TOK_mm , VT_DATE},
187 {"m" , 1, TOK_m , VT_DATE},
188 {"q" , 1, TOK_q , VT_DATE},
189 {"yyyy" , 4, TOK_yyyy , VT_DATE},
190 {"yy" , 2, TOK_yy , VT_DATE},
191 {"y" , 1, TOK_y , VT_DATE},
192 {"h" , 1, TOK_h , VT_DATE},
193 {"Hh" , 2, TOK_Hh , VT_DATE},
194 {"Nn" , 2, TOK_Nn , VT_DATE},
195 {"N" , 1, TOK_N , VT_DATE},
196 {"S" , 1, TOK_S , VT_DATE},
197 {"Ss" , 2, TOK_Ss , VT_DATE},
198 {"ttttt" , 5, TOK_ttttt , VT_DATE},
199 {"AM/PM" , 5, TOK_AMsPM , VT_DATE},
200 {"am/pm" , 5, TOK_amspm , VT_DATE},
201 {"A/P" , 3, TOK_AsP , VT_DATE},
202 {"a/p" , 3, TOK_asp , VT_DATE},
203 {"AMPM" , 4, TOK_AMPM , VT_DATE},
204 {0x00 , 0, 0 , VT_NULL}
207 /******************************************************************************
208 * DateTimeStringToTm [INTERNAL]
210 * Converts a string representation of a date and/or time to a tm structure.
212 * Note this function uses the postgresql date parsing functions found
213 * in the parsedt.c file.
215 * Returns TRUE if successful.
217 * Note: This function does not parse the day of the week,
218 * daylight savings time. It will only fill the followin fields in
219 * the tm struct, tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
221 ******************************************************************************/
222 static BOOL DateTimeStringToTm( OLECHAR* strIn, DWORD dwFlags, struct tm* pTm )
229 char *field[MAXDATEFIELDS];
230 int ftype[MAXDATEFIELDS];
231 char lowstr[MAXDATELEN + 1];
232 char* strDateTime = NULL;
234 /* Convert the string to ASCII since this is the only format
235 * postgesql can handle.
237 strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
239 if( strDateTime != NULL )
241 /* Make sure we don't go over the maximum length
242 * accepted by postgesql.
244 if( strlen( strDateTime ) <= MAXDATELEN )
246 if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
248 if( dwFlags & VAR_DATEVALUEONLY )
250 /* Get the date information.
251 * It returns 0 if date information was
252 * present and 1 if only time information was present.
253 * -1 if an error occures.
255 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
257 /* Eliminate the time information since we
258 * were asked to get date information only.
266 if( dwFlags & VAR_TIMEVALUEONLY )
268 /* Get time information only.
270 if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
277 /* Get both date and time information.
278 * It returns 0 if date information was
279 * present and 1 if only time information was present.
280 * -1 if an error occures.
282 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
289 HeapFree( GetProcessHeap(), 0, strDateTime );
300 /******************************************************************************
301 * TmToDATE [INTERNAL]
303 * The date is implemented using an 8 byte floating-point number.
304 * Days are represented by whole numbers increments starting with 0.00 has
305 * being December 30 1899, midnight.
306 * The hours are expressed as the fractional part of the number.
307 * December 30 1899 at midnight = 0.00
308 * January 1 1900 at midnight = 2.00
309 * January 4 1900 at 6 AM = 5.25
310 * January 4 1900 at noon = 5.50
311 * December 29 1899 at midnight = -1.00
312 * December 18 1899 at midnight = -12.00
313 * December 18 1899 at 6AM = -12.25
314 * December 18 1899 at 6PM = -12.75
315 * December 19 1899 at midnight = -11.00
316 * The tm structure is as follows:
318 * int tm_sec; seconds after the minute - [0,59]
319 * int tm_min; minutes after the hour - [0,59]
320 * int tm_hour; hours since midnight - [0,23]
321 * int tm_mday; day of the month - [1,31]
322 * int tm_mon; months since January - [0,11]
324 * int tm_wday; days since Sunday - [0,6]
325 * int tm_yday; days since January 1 - [0,365]
326 * int tm_isdst; daylight savings time flag
329 * Note: This function does not use the tm_wday, tm_yday, tm_wday,
330 * and tm_isdst fields of the tm structure. And only converts years
333 * Returns TRUE if successful.
335 static BOOL TmToDATE( struct tm* pTm, DATE *pDateOut )
339 /* Hmmm... An uninitialized Date in VB is December 30 1899 so
340 Start at 0. This is the way DATE is defined. */
342 /* Start at 1. This is the way DATE is defined.
343 * January 1, 1900 at Midnight is 1.00.
344 * January 1, 1900 at 6AM is 1.25.
349 if( (pTm->tm_year - 1900) >= 0 ) {
351 /* Add the number of days corresponding to
354 *pDateOut += (pTm->tm_year - 1900) * 365;
356 /* Add the leap days in the previous years between now and 1900.
357 * Note a leap year is one that is a multiple of 4
358 * but not of a 100. Except if it is a multiple of
359 * 400 then it is a leap year.
360 * Copied + reversed functionality into TmToDate
362 *pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
363 *pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
364 *pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
366 /* Set the leap year flag if the
367 * current year specified by tm_year is a
368 * leap year. This will be used to add a day
371 if( isleap( pTm->tm_year ) )
374 /* Add the number of days corresponding to
375 * the month. (remember tm_mon is 0..11)
377 switch( pTm->tm_mon )
383 *pDateOut += ( 59 + leapYear );
386 *pDateOut += ( 90 + leapYear );
389 *pDateOut += ( 120 + leapYear );
392 *pDateOut += ( 151 + leapYear );
395 *pDateOut += ( 181 + leapYear );
398 *pDateOut += ( 212 + leapYear );
401 *pDateOut += ( 243 + leapYear );
404 *pDateOut += ( 273 + leapYear );
407 *pDateOut += ( 304 + leapYear );
410 *pDateOut += ( 334 + leapYear );
413 /* Add the number of days in this month.
415 *pDateOut += pTm->tm_mday;
417 /* Add the number of seconds, minutes, and hours
418 * to the DATE. Note these are the fracionnal part
419 * of the DATE so seconds / number of seconds in a day.
425 *pDateOut += pTm->tm_hour / 24.0;
426 *pDateOut += pTm->tm_min / 1440.0;
427 *pDateOut += pTm->tm_sec / 86400.0;
431 /******************************************************************************
432 * DateToTm [INTERNAL]
434 * This function converts a windows DATE to a tm structure.
436 * It does not fill all the fields of the tm structure.
437 * Here is a list of the fields that are filled:
438 * tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
440 * Note this function does not support dates before the January 1, 1900
441 * or ( dateIn < 2.0 ).
443 * Returns TRUE if successful.
445 BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )
447 double decimalPart = 0.0;
448 double wholePart = 0.0;
450 memset(pTm,0,sizeof(*pTm));
452 /* Because of the nature of DATE format which
453 * associates 2.0 to January 1, 1900. We will
454 * remove 1.0 from the whole part of the DATE
455 * so that in the following code 1.0
456 * will correspond to January 1, 1900.
457 * This simplifies the processing of the DATE value.
459 decimalPart = fmod( dateIn, 1.0 ); /* Do this before the -1, otherwise 0.xx goes negative */
461 wholePart = (double) floor( dateIn );
463 if( !(dwFlags & VAR_TIMEVALUEONLY) )
465 unsigned int nDay = 0;
467 double yearsSince1900 = 0;
469 /* Hard code dates smaller than January 1, 1900. */
472 pTm->tm_mon = 11; /* December as tm_mon is 0..11 */
475 dateIn = dateIn * -1.0; /* Ensure +ve for time calculation */
476 decimalPart = decimalPart * -1.0; /* Ensure +ve for time calculation */
483 /* Start at 1900, this is where the DATE time 0.0 starts.
486 /* find in what year the day in the "wholePart" falls into.
487 * add the value to the year field.
489 yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 );
490 pTm->tm_year += yearsSince1900;
491 /* determine if this is a leap year.
493 if( isleap( pTm->tm_year ) )
499 /* find what day of that year the "wholePart" corresponds to.
500 * Note: nDay is in [1-366] format
502 nDay = (((unsigned int) wholePart) - ((pTm->tm_year-1900) * DAYS_IN_ONE_YEAR ));
504 /* Remove the leap days in the previous years between now and 1900.
505 * Note a leap year is one that is a multiple of 4
506 * but not of a 100. Except if it is a multiple of
507 * 400 then it is a leap year.
508 * Copied + reversed functionality from TmToDate
510 nDay -= ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
511 nDay += ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
512 nDay -= ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
514 /* Set the tm_yday value.
515 * Note: The day must be converted from [1-366] to [0-365]
517 /*pTm->tm_yday = nDay - 1;*/
518 /* find which month this day corresponds to.
525 else if( nDay <= ( 59 + leapYear ) )
527 pTm->tm_mday = nDay - 31;
530 else if( nDay <= ( 90 + leapYear ) )
532 pTm->tm_mday = nDay - ( 59 + leapYear );
535 else if( nDay <= ( 120 + leapYear ) )
537 pTm->tm_mday = nDay - ( 90 + leapYear );
540 else if( nDay <= ( 151 + leapYear ) )
542 pTm->tm_mday = nDay - ( 120 + leapYear );
545 else if( nDay <= ( 181 + leapYear ) )
547 pTm->tm_mday = nDay - ( 151 + leapYear );
550 else if( nDay <= ( 212 + leapYear ) )
552 pTm->tm_mday = nDay - ( 181 + leapYear );
555 else if( nDay <= ( 243 + leapYear ) )
557 pTm->tm_mday = nDay - ( 212 + leapYear );
560 else if( nDay <= ( 273 + leapYear ) )
562 pTm->tm_mday = nDay - ( 243 + leapYear );
565 else if( nDay <= ( 304 + leapYear ) )
567 pTm->tm_mday = nDay - ( 273 + leapYear );
570 else if( nDay <= ( 334 + leapYear ) )
572 pTm->tm_mday = nDay - ( 304 + leapYear );
575 else if( nDay <= ( 365 + leapYear ) )
577 pTm->tm_mday = nDay - ( 334 + leapYear );
582 if( !(dwFlags & VAR_DATEVALUEONLY) )
584 /* find the number of seconds in this day.
585 * fractional part times, hours, minutes, seconds.
586 * Note: 0.1 is hack to ensure figures come out in whole numbers
587 * due to floating point inaccuracies
589 pTm->tm_hour = (int) ( decimalPart * 24 );
590 pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
591 /* Note: 0.1 is hack to ensure seconds come out in whole numbers
592 due to floating point inaccuracies */
593 pTm->tm_sec = (int) (( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 ) + 0.1);
600 /******************************************************************************
601 * SizeOfVariantData [INTERNAL]
603 * This function finds the size of the data referenced by a Variant based
604 * the type "vt" of the Variant.
606 static int SizeOfVariantData( VARIANT* parg )
609 switch( V_VT(parg) & VT_TYPEMASK )
612 size = sizeof(short);
624 size = sizeof(unsigned short);
627 size = sizeof(unsigned int);
630 size = sizeof(unsigned long);
633 size = sizeof(float);
636 size = sizeof(double);
642 size = sizeof(VARIANT_BOOL);
647 size = sizeof(void*);
652 case( VT_DECIMAL ): /* hmm, tricky, DECIMAL is only VT_BYREF */
654 FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK );
660 /******************************************************************************
661 * StringDupAtoBstr [INTERNAL]
664 static BSTR StringDupAtoBstr( char* strIn )
667 OLECHAR* pNewString = NULL;
668 pNewString = HEAP_strdupAtoW( GetProcessHeap(), 0, strIn );
669 bstr = SysAllocString( pNewString );
670 HeapFree( GetProcessHeap(), 0, pNewString );
674 /******************************************************************************
677 * Round the double value to the nearest integer value.
679 static double round( double d )
681 double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
682 BOOL bEvenNumber = FALSE;
685 /* Save the sign of the number
687 nSign = (d >= 0.0) ? 1 : -1;
690 /* Remove the decimals.
692 integerValue = floor( d );
694 /* Set the Even flag. This is used to round the number when
695 * the decimals are exactly 1/2. If the integer part is
696 * odd the number is rounded up. If the integer part
697 * is even the number is rounded down. Using this method
698 * numbers are rounded up|down half the time.
700 bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
702 /* Remove the integral part of the number.
704 decimals = d - integerValue;
706 /* Note: Ceil returns the smallest integer that is greater that x.
707 * and floor returns the largest integer that is less than or equal to x.
711 /* If the decimal part is greater than 1/2
713 roundedValue = ceil( d );
715 else if( decimals < 0.5 )
717 /* If the decimal part is smaller than 1/2
719 roundedValue = floor( d );
723 /* the decimals are exactly 1/2 so round according to
724 * the bEvenNumber flag.
728 roundedValue = floor( d );
732 roundedValue = ceil( d );
736 return roundedValue * nSign;
739 /******************************************************************************
740 * RemoveCharacterFromString [INTERNAL]
742 * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
744 static void RemoveCharacterFromString( LPSTR str, LPSTR strOfCharToRemove )
746 LPSTR pNewString = NULL;
747 LPSTR strToken = NULL;
749 /* Check if we have a valid argument
753 pNewString = strdup( str );
755 strToken = strtok( pNewString, strOfCharToRemove );
756 while( strToken != NULL ) {
757 strcat( str, strToken );
758 strToken = strtok( NULL, strOfCharToRemove );
765 /******************************************************************************
766 * GetValidRealString [INTERNAL]
768 * Checks if the string is of proper format to be converted to a real value.
770 static BOOL IsValidRealString( LPSTR strRealString )
772 /* Real values that have a decimal point are required to either have
773 * digits before or after the decimal point. We will assume that
774 * we do not have any digits at either position. If we do encounter
775 * some we will disable this flag.
777 BOOL bDigitsRequired = TRUE;
778 /* Processed fields in the string representation of the real number.
780 BOOL bWhiteSpaceProcessed = FALSE;
781 BOOL bFirstSignProcessed = FALSE;
782 BOOL bFirstDigitsProcessed = FALSE;
783 BOOL bDecimalPointProcessed = FALSE;
784 BOOL bSecondDigitsProcessed = FALSE;
785 BOOL bExponentProcessed = FALSE;
786 BOOL bSecondSignProcessed = FALSE;
787 BOOL bThirdDigitsProcessed = FALSE;
788 /* Assume string parameter "strRealString" is valid and try to disprove it.
790 BOOL bValidRealString = TRUE;
792 /* Used to count the number of tokens in the "strRealString".
794 LPSTR strToken = NULL;
798 /* Check if we have a valid argument
800 if( strRealString == NULL )
802 bValidRealString = FALSE;
805 if( bValidRealString == TRUE )
807 /* Make sure we only have ONE token in the string.
809 strToken = strtok( strRealString, " " );
810 while( strToken != NULL ) {
812 strToken = strtok( NULL, " " );
817 bValidRealString = FALSE;
822 /* Make sure this token contains only valid characters.
823 * The string argument to atof has the following form:
824 * [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
825 * Whitespace consists of space and|or <TAB> characters, which are ignored.
826 * Sign is either plus '+' or minus '-'.
827 * Digits are one or more decimal digits.
828 * Note: If no digits appear before the decimal point, at least one must
829 * appear after the decimal point.
830 * The decimal digits may be followed by an exponent.
831 * An Exponent consists of an introductory letter ( D, d, E, or e) and
832 * an optionally signed decimal integer.
834 pChar = strRealString;
835 while( bValidRealString == TRUE && *pChar != '\0' )
843 if( bWhiteSpaceProcessed ||
844 bFirstSignProcessed ||
845 bFirstDigitsProcessed ||
846 bDecimalPointProcessed ||
847 bSecondDigitsProcessed ||
848 bExponentProcessed ||
849 bSecondSignProcessed ||
850 bThirdDigitsProcessed )
852 bValidRealString = FALSE;
859 if( bFirstSignProcessed == FALSE )
861 if( bFirstDigitsProcessed ||
862 bDecimalPointProcessed ||
863 bSecondDigitsProcessed ||
864 bExponentProcessed ||
865 bSecondSignProcessed ||
866 bThirdDigitsProcessed )
868 bValidRealString = FALSE;
870 bWhiteSpaceProcessed = TRUE;
871 bFirstSignProcessed = TRUE;
873 else if( bSecondSignProcessed == FALSE )
875 /* Note: The exponent must be present in
876 * order to accept the second sign...
878 if( bExponentProcessed == FALSE ||
879 bThirdDigitsProcessed ||
882 bValidRealString = FALSE;
884 bFirstSignProcessed = TRUE;
885 bWhiteSpaceProcessed = TRUE;
886 bFirstDigitsProcessed = TRUE;
887 bDecimalPointProcessed = TRUE;
888 bSecondDigitsProcessed = TRUE;
889 bSecondSignProcessed = TRUE;
905 if( bFirstDigitsProcessed == FALSE )
907 if( bDecimalPointProcessed ||
908 bSecondDigitsProcessed ||
909 bExponentProcessed ||
910 bSecondSignProcessed ||
911 bThirdDigitsProcessed )
913 bValidRealString = FALSE;
915 bFirstSignProcessed = TRUE;
916 bWhiteSpaceProcessed = TRUE;
917 /* We have found some digits before the decimal point
918 * so disable the "Digits required" flag.
920 bDigitsRequired = FALSE;
922 else if( bSecondDigitsProcessed == FALSE )
924 if( bExponentProcessed ||
925 bSecondSignProcessed ||
926 bThirdDigitsProcessed )
928 bValidRealString = FALSE;
930 bFirstSignProcessed = TRUE;
931 bWhiteSpaceProcessed = TRUE;
932 bFirstDigitsProcessed = TRUE;
933 bDecimalPointProcessed = TRUE;
934 /* We have found some digits after the decimal point
935 * so disable the "Digits required" flag.
937 bDigitsRequired = FALSE;
939 else if( bThirdDigitsProcessed == FALSE )
941 /* Getting here means everything else should be processed.
942 * If we get anything else than a decimal following this
943 * digit it will be flagged by the other cases, so
944 * we do not really need to do anything in here.
948 /* If DecimalPoint...
951 if( bDecimalPointProcessed ||
952 bSecondDigitsProcessed ||
953 bExponentProcessed ||
954 bSecondSignProcessed ||
955 bThirdDigitsProcessed )
957 bValidRealString = FALSE;
959 bFirstSignProcessed = TRUE;
960 bWhiteSpaceProcessed = TRUE;
961 bFirstDigitsProcessed = TRUE;
962 bDecimalPointProcessed = TRUE;
970 if( bExponentProcessed ||
971 bSecondSignProcessed ||
972 bThirdDigitsProcessed ||
975 bValidRealString = FALSE;
977 bFirstSignProcessed = TRUE;
978 bWhiteSpaceProcessed = TRUE;
979 bFirstDigitsProcessed = TRUE;
980 bDecimalPointProcessed = TRUE;
981 bSecondDigitsProcessed = TRUE;
982 bExponentProcessed = TRUE;
985 bValidRealString = FALSE;
988 /* Process next character.
993 /* If the required digits were not present we have an invalid
994 * string representation of a real number.
996 if( bDigitsRequired == TRUE )
998 bValidRealString = FALSE;
1001 return bValidRealString;
1005 /******************************************************************************
1008 * This function dispatches execution to the proper conversion API
1009 * to do the necessary coercion.
1011 * FIXME: Passing down dwFlags to the conversion functions is wrong, this
1012 * is a different flagmask. Check MSDN.
1014 static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
1017 unsigned short vtFrom = 0;
1018 vtFrom = V_VT(ps) & VT_TYPEMASK;
1021 /* Note: Since "long" and "int" values both have 4 bytes and are
1022 * both signed integers "int" will be treated as "long" in the
1024 * The same goes for their unsigned versions.
1027 /* Trivial Case: If the coercion is from two types that are
1028 * identical then we can blindly copy from one argument to another.*/
1031 return VariantCopy(pd,ps);
1034 /* Cases requiring thought*/
1039 res = VariantClear( pd );
1042 res = VariantClear( pd );
1052 res = VariantCopy( pd, ps );
1055 res = VarI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,cVal) );
1059 res = VarI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,cVal) );
1062 res = VarI1FromUI1( V_UNION(ps,bVal), &V_UNION(pd,cVal) );
1065 res = VarI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cVal) );
1069 res = VarI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cVal) );
1072 res = VarI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,cVal) );
1075 res = VarI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,cVal) );
1078 res = VarI1FromDate( V_UNION(ps,date), &V_UNION(pd,cVal) );
1081 res = VarI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,cVal) );
1084 res = VarI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cVal) );
1087 res = VarI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,cVal) );
1089 case( VT_DISPATCH ):
1090 /*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
1092 /*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
1095 res = DISP_E_TYPEMISMATCH;
1096 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1105 res = VarI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,iVal) );
1108 res = VariantCopy( pd, ps );
1112 res = VarI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,iVal) );
1115 res = VarI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,iVal) );
1118 res = VarI2FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,iVal) );
1122 res = VarI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,iVal) );
1125 res = VarI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,iVal) );
1128 res = VarI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,iVal) );
1131 res = VarI2FromDate( V_UNION(ps,date), &V_UNION(pd,iVal) );
1134 res = VarI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,iVal) );
1137 res = VarI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,iVal) );
1140 res = VarI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,iVal) );
1142 case( VT_DISPATCH ):
1143 /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
1145 /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
1148 res = DISP_E_TYPEMISMATCH;
1149 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1159 V_UNION(pd,lVal) = 0;
1163 res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
1166 res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
1170 res = VariantCopy( pd, ps );
1173 res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
1176 res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
1180 res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
1183 res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
1186 res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
1189 res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
1192 res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
1195 res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
1198 res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
1200 case( VT_DISPATCH ):
1201 /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1203 /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1206 res = DISP_E_TYPEMISMATCH;
1207 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1216 res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
1219 res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
1223 res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
1226 res = VariantCopy( pd, ps );
1229 res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
1233 res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
1236 res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
1239 res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
1242 res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
1245 res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
1248 res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
1251 res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
1253 case( VT_DISPATCH ):
1254 /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1256 /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1259 res = DISP_E_TYPEMISMATCH;
1260 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1269 res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
1272 res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
1276 res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
1279 res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
1282 res = VariantCopy( pd, ps );
1286 res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
1289 res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
1292 res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
1295 res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
1298 res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
1301 res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
1304 res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
1306 case( VT_DISPATCH ):
1307 /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1309 /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1312 res = DISP_E_TYPEMISMATCH;
1313 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1323 res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
1326 res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
1330 res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
1333 res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
1336 res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
1339 res = VariantCopy( pd, ps );
1342 res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
1345 res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
1348 res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
1351 res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
1354 res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
1357 res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
1359 case( VT_DISPATCH ):
1360 /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1362 /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1365 res = DISP_E_TYPEMISMATCH;
1366 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1375 res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
1378 res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
1382 res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
1385 res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
1388 res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
1392 res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
1395 res = VariantCopy( pd, ps );
1398 res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
1401 res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
1404 res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
1407 res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
1410 res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
1412 case( VT_DISPATCH ):
1413 /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1415 /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1418 res = DISP_E_TYPEMISMATCH;
1419 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1428 res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
1431 res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
1435 res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
1438 res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
1441 res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
1445 res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
1448 res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
1451 res = VariantCopy( pd, ps );
1454 res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
1457 res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
1460 res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
1463 res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
1465 case( VT_DISPATCH ):
1466 /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1468 /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1471 res = DISP_E_TYPEMISMATCH;
1472 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1481 res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
1484 res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
1487 res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
1490 res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
1493 res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
1496 res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
1499 res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
1502 res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
1505 res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
1508 res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
1511 res = VariantCopy( pd, ps );
1514 res = VarDateFromBool( V_UNION(ps,boolVal), &V_UNION(pd,date) );
1517 res = VarDateFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,date) );
1520 res = VarDateFromCy( V_UNION(ps,cyVal), &V_UNION(pd,date) );
1522 case( VT_DISPATCH ):
1523 /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1525 /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1528 res = DISP_E_TYPEMISMATCH;
1529 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1539 V_UNION(pd,boolVal) = VARIANT_FALSE;
1542 res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
1545 res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
1548 res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
1551 res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
1554 res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
1557 res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
1560 res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
1563 res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
1566 res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
1569 res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
1572 res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
1575 res = VariantCopy( pd, ps );
1578 res = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
1581 res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
1583 case( VT_DISPATCH ):
1584 /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1586 /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1589 res = DISP_E_TYPEMISMATCH;
1590 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1599 if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
1602 res = E_OUTOFMEMORY;
1605 res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
1608 res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
1611 res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
1614 res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
1617 res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
1620 res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
1623 res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
1626 res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
1629 res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
1632 res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
1635 res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
1638 res = VarBstrFromBool( V_UNION(ps,boolVal), lcid, 0, &V_UNION(pd,bstrVal) );
1641 res = VariantCopy( pd, ps );
1644 res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
1646 case( VT_DISPATCH ):
1647 /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1649 /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1652 res = DISP_E_TYPEMISMATCH;
1653 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1662 res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
1665 res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
1668 res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
1671 res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
1674 res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
1677 res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
1680 res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
1683 res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
1686 res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
1689 res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
1692 res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1695 res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1698 res = VariantCopy( pd, ps );
1701 res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
1703 case( VT_DISPATCH ):
1704 /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1706 /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1710 res = DISP_E_TYPEMISMATCH;
1711 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1717 if (vtFrom == VT_DISPATCH)
1719 res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1723 res = DISP_E_TYPEMISMATCH;
1724 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1729 res = DISP_E_TYPEMISMATCH;
1730 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1737 /******************************************************************************
1738 * ValidateVtRange [INTERNAL]
1740 * Used internally by the hi-level Variant API to determine
1741 * if the vartypes are valid.
1743 static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
1745 /* if by value we must make sure it is in the
1746 * range of the valid types.
1748 if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1750 return DISP_E_BADVARTYPE;
1756 /******************************************************************************
1757 * ValidateVartype [INTERNAL]
1759 * Used internally by the hi-level Variant API to determine
1760 * if the vartypes are valid.
1762 static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
1766 /* check if we have a valid argument.
1770 /* if by reference check that the type is in
1771 * the valid range and that it is not of empty or null type
1773 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1774 ( vt & VT_TYPEMASK ) == VT_NULL ||
1775 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1777 res = DISP_E_BADVARTYPE;
1783 res = ValidateVtRange( vt );
1789 /******************************************************************************
1790 * ValidateVt [INTERNAL]
1792 * Used internally by the hi-level Variant API to determine
1793 * if the vartypes are valid.
1795 static HRESULT WINAPI ValidateVt( VARTYPE vt )
1799 /* check if we have a valid argument.
1803 /* if by reference check that the type is in
1804 * the valid range and that it is not of empty or null type
1806 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1807 ( vt & VT_TYPEMASK ) == VT_NULL ||
1808 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1810 res = DISP_E_BADVARTYPE;
1816 res = ValidateVtRange( vt );
1826 /******************************************************************************
1827 * VariantInit [OLEAUT32.8]
1829 * Initializes the Variant. Unlike VariantClear it does not interpret
1830 * the current contents of the Variant.
1832 void WINAPI VariantInit(VARIANTARG* pvarg)
1834 TRACE("(%p)\n",pvarg);
1836 memset(pvarg, 0, sizeof (VARIANTARG));
1837 V_VT(pvarg) = VT_EMPTY;
1842 /******************************************************************************
1843 * VariantClear [OLEAUT32.9]
1845 * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1846 * sets the wReservedX field to 0. The current contents of the VARIANT are
1847 * freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1848 * released. If VT_ARRAY the array is freed.
1850 HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
1853 TRACE("(%p)\n",pvarg);
1855 res = ValidateVariantType( V_VT(pvarg) );
1858 if( !( V_VT(pvarg) & VT_BYREF ) )
1861 * The VT_ARRAY flag is a special case of a safe array.
1863 if ( (V_VT(pvarg) & VT_ARRAY) != 0)
1865 SafeArrayDestroy(V_UNION(pvarg,parray));
1869 switch( V_VT(pvarg) & VT_TYPEMASK )
1872 SysFreeString( V_UNION(pvarg,bstrVal) );
1874 case( VT_DISPATCH ):
1875 if(V_UNION(pvarg,pdispVal)!=NULL)
1876 ICOM_CALL(Release,V_UNION(pvarg,pdispVal));
1879 VariantClear(V_UNION(pvarg,pvarVal));
1882 if(V_UNION(pvarg,punkVal)!=NULL)
1883 ICOM_CALL(Release,V_UNION(pvarg,punkVal));
1885 case( VT_SAFEARRAY ):
1886 SafeArrayDestroy(V_UNION(pvarg,parray));
1895 * Empty all the fields and mark the type as empty.
1897 memset(pvarg, 0, sizeof (VARIANTARG));
1898 V_VT(pvarg) = VT_EMPTY;
1904 /******************************************************************************
1905 * VariantCopy [OLEAUT32.10]
1907 * Frees up the designation variant and makes a copy of the source.
1909 HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
1913 TRACE("(%p, %p), vt=%d\n", pvargDest, pvargSrc, V_VT(pvargSrc));
1915 res = ValidateVariantType( V_VT(pvargSrc) );
1917 /* If the pointer are to the same variant we don't need
1920 if( pvargDest != pvargSrc && res == S_OK )
1922 res = VariantClear( pvargDest );
1926 if( V_VT(pvargSrc) & VT_BYREF )
1928 /* In the case of byreference we only need
1929 * to copy the pointer.
1931 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1932 V_VT(pvargDest) = V_VT(pvargSrc);
1937 * The VT_ARRAY flag is another way to designate a safe array.
1939 if (V_VT(pvargSrc) & VT_ARRAY)
1941 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1945 /* In the case of by value we need to
1946 * copy the actual value. In the case of
1947 * VT_BSTR a copy of the string is made,
1948 * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1949 * called to increment the object's reference count.
1951 switch( V_VT(pvargSrc) & VT_TYPEMASK )
1954 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
1956 case( VT_DISPATCH ):
1957 V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
1958 if (V_UNION(pvargDest,pdispVal)!=NULL)
1959 ICOM_CALL(AddRef,V_UNION(pvargDest,pdispVal));
1962 VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
1965 V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
1966 if (V_UNION(pvargDest,pdispVal)!=NULL)
1967 ICOM_CALL(AddRef,V_UNION(pvargDest,punkVal));
1969 case( VT_SAFEARRAY ):
1970 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1973 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1978 V_VT(pvargDest) = V_VT(pvargSrc);
1987 /******************************************************************************
1988 * VariantCopyInd [OLEAUT32.11]
1990 * Frees up the destination variant and makes a copy of the source. If
1991 * the source is of type VT_BYREF it performs the necessary indirections.
1993 HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
1997 TRACE("(%p, %p)\n", pvargDest, pvargSrc);
1999 res = ValidateVariantType( V_VT(pvargSrc) );
2004 if( V_VT(pvargSrc) & VT_BYREF )
2007 VariantInit( &varg );
2009 /* handle the in place copy.
2011 if( pvargDest == pvargSrc )
2013 /* we will use a copy of the source instead.
2015 res = VariantCopy( &varg, pvargSrc );
2021 res = VariantClear( pvargDest );
2026 * The VT_ARRAY flag is another way to designate a safearray variant.
2028 if ( V_VT(pvargSrc) & VT_ARRAY)
2030 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2034 /* In the case of by reference we need
2035 * to copy the date pointed to by the variant.
2038 /* Get the variant type.
2040 switch( V_VT(pvargSrc) & VT_TYPEMASK )
2043 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
2045 case( VT_DISPATCH ):
2049 /* Prevent from cycling. According to tests on
2050 * VariantCopyInd in Windows and the documentation
2051 * this API dereferences the inner Variants to only one depth.
2052 * If the inner Variant itself contains an
2053 * other inner variant the E_INVALIDARG error is
2056 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
2058 /* If we get here we are attempting to deference
2059 * an inner variant that that is itself contained
2060 * in an inner variant so report E_INVALIDARG error.
2066 /* Set the processing inner variant flag.
2067 * We will set this flag in the inner variant
2068 * that will be passed to the VariantCopyInd function.
2070 (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
2072 /* Dereference the inner variant.
2074 res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
2075 /* We must also copy its type, I think.
2077 V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
2083 case( VT_SAFEARRAY ):
2084 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2087 /* This is a by reference Variant which means that the union
2088 * part of the Variant contains a pointer to some data of
2089 * type "V_VT(pvargSrc) & VT_TYPEMASK".
2090 * We will deference this data in a generic fashion using
2091 * the void pointer "Variant.u.byref".
2092 * We will copy this data into the union of the destination
2095 memcpy( &pvargDest->n1.n2.n3, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
2100 if (res == S_OK) V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
2104 /* this should not fail.
2106 VariantClear( &varg );
2110 res = VariantCopy( pvargDest, pvargSrc );
2116 /******************************************************************************
2117 * VariantChangeType [OLEAUT32.12]
2119 HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2120 USHORT wFlags, VARTYPE vt)
2122 return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
2125 /******************************************************************************
2126 * VariantChangeTypeEx [OLEAUT32.147]
2128 HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2129 LCID lcid, USHORT wFlags, VARTYPE vt)
2133 VariantInit( &varg );
2135 TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
2136 TRACE("Src Var:\n");
2137 dump_Variant(pvargSrc);
2139 /* validate our source argument.
2141 res = ValidateVariantType( V_VT(pvargSrc) );
2143 /* validate the vartype.
2147 res = ValidateVt( vt );
2150 /* if we are doing an in-place conversion make a copy of the source.
2152 if( res == S_OK && pvargDest == pvargSrc )
2154 res = VariantCopy( &varg, pvargSrc );
2160 /* free up the destination variant.
2162 res = VariantClear( pvargDest );
2167 if( V_VT(pvargSrc) & VT_BYREF )
2169 /* Convert the source variant to a "byvalue" variant.
2172 VariantInit( &Variant );
2173 res = VariantCopyInd( &Variant, pvargSrc );
2176 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2177 /* this should not fail.
2179 VariantClear( &Variant );
2185 /* Use the current "byvalue" source variant.
2187 res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2190 /* this should not fail.
2192 VariantClear( &varg );
2194 /* set the type of the destination
2197 V_VT(pvargDest) = vt;
2199 TRACE("Dest Var:\n");
2200 dump_Variant(pvargDest);
2208 /******************************************************************************
2209 * VarUI1FromI2 [OLEAUT32.130]
2211 HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2213 TRACE("( %d, %p ), stub\n", sIn, pbOut );
2215 /* Check range of value.
2217 if( sIn < UI1_MIN || sIn > UI1_MAX )
2219 return DISP_E_OVERFLOW;
2222 *pbOut = (BYTE) sIn;
2227 /******************************************************************************
2228 * VarUI1FromI4 [OLEAUT32.131]
2230 HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2232 TRACE("( %ld, %p ), stub\n", lIn, pbOut );
2234 /* Check range of value.
2236 if( lIn < UI1_MIN || lIn > UI1_MAX )
2238 return DISP_E_OVERFLOW;
2241 *pbOut = (BYTE) lIn;
2247 /******************************************************************************
2248 * VarUI1FromR4 [OLEAUT32.132]
2250 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2252 TRACE("( %f, %p ), stub\n", fltIn, pbOut );
2254 /* Check range of value.
2256 fltIn = round( fltIn );
2257 if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2259 return DISP_E_OVERFLOW;
2262 *pbOut = (BYTE) fltIn;
2267 /******************************************************************************
2268 * VarUI1FromR8 [OLEAUT32.133]
2270 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2272 TRACE("( %f, %p ), stub\n", dblIn, pbOut );
2274 /* Check range of value.
2276 dblIn = round( dblIn );
2277 if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2279 return DISP_E_OVERFLOW;
2282 *pbOut = (BYTE) dblIn;
2287 /******************************************************************************
2288 * VarUI1FromDate [OLEAUT32.135]
2290 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2292 TRACE("( %f, %p ), stub\n", dateIn, pbOut );
2294 /* Check range of value.
2296 dateIn = round( dateIn );
2297 if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2299 return DISP_E_OVERFLOW;
2302 *pbOut = (BYTE) dateIn;
2307 /******************************************************************************
2308 * VarUI1FromBool [OLEAUT32.138]
2310 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2312 TRACE("( %d, %p ), stub\n", boolIn, pbOut );
2314 *pbOut = (BYTE) boolIn;
2319 /******************************************************************************
2320 * VarUI1FromI1 [OLEAUT32.237]
2322 HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
2324 TRACE("( %c, %p ), stub\n", cIn, pbOut );
2331 /******************************************************************************
2332 * VarUI1FromUI2 [OLEAUT32.238]
2334 HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2336 TRACE("( %d, %p ), stub\n", uiIn, pbOut );
2338 /* Check range of value.
2340 if( uiIn > UI1_MAX )
2342 return DISP_E_OVERFLOW;
2345 *pbOut = (BYTE) uiIn;
2350 /******************************************************************************
2351 * VarUI1FromUI4 [OLEAUT32.239]
2353 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2355 TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
2357 /* Check range of value.
2359 if( ulIn > UI1_MAX )
2361 return DISP_E_OVERFLOW;
2364 *pbOut = (BYTE) ulIn;
2370 /******************************************************************************
2371 * VarUI1FromStr [OLEAUT32.136]
2373 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2375 double dValue = 0.0;
2376 LPSTR pNewString = NULL;
2378 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
2380 /* Check if we have a valid argument
2382 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2383 RemoveCharacterFromString( pNewString, "," );
2384 if( IsValidRealString( pNewString ) == FALSE )
2386 return DISP_E_TYPEMISMATCH;
2389 /* Convert the valid string to a floating point number.
2391 dValue = atof( pNewString );
2393 /* We don't need the string anymore so free it.
2395 HeapFree( GetProcessHeap(), 0 , pNewString );
2397 /* Check range of value.
2399 dValue = round( dValue );
2400 if( dValue < UI1_MIN || dValue > UI1_MAX )
2402 return DISP_E_OVERFLOW;
2405 *pbOut = (BYTE) dValue;
2410 /**********************************************************************
2411 * VarUI1FromCy [OLEAUT32.134]
2412 * Convert currency to unsigned char
2414 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
2415 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2417 if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
2423 /******************************************************************************
2424 * VarI2FromUI1 [OLEAUT32.48]
2426 HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2428 TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
2430 *psOut = (short) bIn;
2435 /******************************************************************************
2436 * VarI2FromI4 [OLEAUT32.49]
2438 HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2440 TRACE("( %lx, %p ), stub\n", lIn, psOut );
2442 /* Check range of value.
2444 if( lIn < I2_MIN || lIn > I2_MAX )
2446 return DISP_E_OVERFLOW;
2449 *psOut = (short) lIn;
2454 /******************************************************************************
2455 * VarI2FromR4 [OLEAUT32.50]
2457 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2459 TRACE("( %f, %p ), stub\n", fltIn, psOut );
2461 /* Check range of value.
2463 fltIn = round( fltIn );
2464 if( fltIn < I2_MIN || fltIn > I2_MAX )
2466 return DISP_E_OVERFLOW;
2469 *psOut = (short) fltIn;
2474 /******************************************************************************
2475 * VarI2FromR8 [OLEAUT32.51]
2477 HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2479 TRACE("( %f, %p ), stub\n", dblIn, psOut );
2481 /* Check range of value.
2483 dblIn = round( dblIn );
2484 if( dblIn < I2_MIN || dblIn > I2_MAX )
2486 return DISP_E_OVERFLOW;
2489 *psOut = (short) dblIn;
2494 /******************************************************************************
2495 * VarI2FromDate [OLEAUT32.53]
2497 HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2499 TRACE("( %f, %p ), stub\n", dateIn, psOut );
2501 /* Check range of value.
2503 dateIn = round( dateIn );
2504 if( dateIn < I2_MIN || dateIn > I2_MAX )
2506 return DISP_E_OVERFLOW;
2509 *psOut = (short) dateIn;
2514 /******************************************************************************
2515 * VarI2FromBool [OLEAUT32.56]
2517 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2519 TRACE("( %d, %p ), stub\n", boolIn, psOut );
2521 *psOut = (short) boolIn;
2526 /******************************************************************************
2527 * VarI2FromI1 [OLEAUT32.205]
2529 HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
2531 TRACE("( %c, %p ), stub\n", cIn, psOut );
2533 *psOut = (short) cIn;
2538 /******************************************************************************
2539 * VarI2FromUI2 [OLEAUT32.206]
2541 HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2543 TRACE("( %d, %p ), stub\n", uiIn, psOut );
2545 /* Check range of value.
2549 return DISP_E_OVERFLOW;
2552 *psOut = (short) uiIn;
2557 /******************************************************************************
2558 * VarI2FromUI4 [OLEAUT32.207]
2560 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2562 TRACE("( %lx, %p ), stub\n", ulIn, psOut );
2564 /* Check range of value.
2566 if( ulIn < I2_MIN || ulIn > I2_MAX )
2568 return DISP_E_OVERFLOW;
2571 *psOut = (short) ulIn;
2576 /******************************************************************************
2577 * VarI2FromStr [OLEAUT32.54]
2579 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2581 double dValue = 0.0;
2582 LPSTR pNewString = NULL;
2584 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, psOut );
2586 /* Check if we have a valid argument
2588 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2589 RemoveCharacterFromString( pNewString, "," );
2590 if( IsValidRealString( pNewString ) == FALSE )
2592 return DISP_E_TYPEMISMATCH;
2595 /* Convert the valid string to a floating point number.
2597 dValue = atof( pNewString );
2599 /* We don't need the string anymore so free it.
2601 HeapFree( GetProcessHeap(), 0, pNewString );
2603 /* Check range of value.
2605 dValue = round( dValue );
2606 if( dValue < I2_MIN || dValue > I2_MAX )
2608 return DISP_E_OVERFLOW;
2611 *psOut = (short) dValue;
2616 /**********************************************************************
2617 * VarI2FromCy [OLEAUT32.52]
2618 * Convert currency to signed short
2620 HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
2621 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2623 if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
2629 /******************************************************************************
2630 * VarI4FromUI1 [OLEAUT32.58]
2632 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2634 TRACE("( %X, %p ), stub\n", bIn, plOut );
2636 *plOut = (LONG) bIn;
2642 /******************************************************************************
2643 * VarI4FromR4 [OLEAUT32.60]
2645 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2647 TRACE("( %f, %p ), stub\n", fltIn, plOut );
2649 /* Check range of value.
2651 fltIn = round( fltIn );
2652 if( fltIn < I4_MIN || fltIn > I4_MAX )
2654 return DISP_E_OVERFLOW;
2657 *plOut = (LONG) fltIn;
2662 /******************************************************************************
2663 * VarI4FromR8 [OLEAUT32.61]
2665 HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2667 TRACE("( %f, %p ), stub\n", dblIn, plOut );
2669 /* Check range of value.
2671 dblIn = round( dblIn );
2672 if( dblIn < I4_MIN || dblIn > I4_MAX )
2674 return DISP_E_OVERFLOW;
2677 *plOut = (LONG) dblIn;
2682 /******************************************************************************
2683 * VarI4FromDate [OLEAUT32.63]
2685 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2687 TRACE("( %f, %p ), stub\n", dateIn, plOut );
2689 /* Check range of value.
2691 dateIn = round( dateIn );
2692 if( dateIn < I4_MIN || dateIn > I4_MAX )
2694 return DISP_E_OVERFLOW;
2697 *plOut = (LONG) dateIn;
2702 /******************************************************************************
2703 * VarI4FromBool [OLEAUT32.66]
2705 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2707 TRACE("( %d, %p ), stub\n", boolIn, plOut );
2709 *plOut = (LONG) boolIn;
2714 /******************************************************************************
2715 * VarI4FromI1 [OLEAUT32.209]
2717 HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
2719 TRACE("( %c, %p ), stub\n", cIn, plOut );
2721 *plOut = (LONG) cIn;
2726 /******************************************************************************
2727 * VarI4FromUI2 [OLEAUT32.210]
2729 HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2731 TRACE("( %d, %p ), stub\n", uiIn, plOut );
2733 *plOut = (LONG) uiIn;
2738 /******************************************************************************
2739 * VarI4FromUI4 [OLEAUT32.211]
2741 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2743 TRACE("( %lx, %p ), stub\n", ulIn, plOut );
2745 /* Check range of value.
2747 if( ulIn < I4_MIN || ulIn > I4_MAX )
2749 return DISP_E_OVERFLOW;
2752 *plOut = (LONG) ulIn;
2757 /******************************************************************************
2758 * VarI4FromI2 [OLEAUT32.59]
2760 HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2762 TRACE("( %d, %p ), stub\n", sIn, plOut );
2764 *plOut = (LONG) sIn;
2769 /******************************************************************************
2770 * VarI4FromStr [OLEAUT32.64]
2772 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2774 double dValue = 0.0;
2775 LPSTR pNewString = NULL;
2777 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
2779 /* Check if we have a valid argument
2781 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2782 RemoveCharacterFromString( pNewString, "," );
2783 if( IsValidRealString( pNewString ) == FALSE )
2785 return DISP_E_TYPEMISMATCH;
2788 /* Convert the valid string to a floating point number.
2790 dValue = atof( pNewString );
2792 /* We don't need the string anymore so free it.
2794 HeapFree( GetProcessHeap(), 0, pNewString );
2796 /* Check range of value.
2798 dValue = round( dValue );
2799 if( dValue < I4_MIN || dValue > I4_MAX )
2801 return DISP_E_OVERFLOW;
2804 *plOut = (LONG) dValue;
2809 /**********************************************************************
2810 * VarI4FromCy [OLEAUT32.62]
2811 * Convert currency to signed long
2813 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
2814 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2816 if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
2822 /******************************************************************************
2823 * VarR4FromUI1 [OLEAUT32.68]
2825 HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
2827 TRACE("( %X, %p ), stub\n", bIn, pfltOut );
2829 *pfltOut = (FLOAT) bIn;
2834 /******************************************************************************
2835 * VarR4FromI2 [OLEAUT32.69]
2837 HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
2839 TRACE("( %d, %p ), stub\n", sIn, pfltOut );
2841 *pfltOut = (FLOAT) sIn;
2846 /******************************************************************************
2847 * VarR4FromI4 [OLEAUT32.70]
2849 HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
2851 TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
2853 *pfltOut = (FLOAT) lIn;
2858 /******************************************************************************
2859 * VarR4FromR8 [OLEAUT32.71]
2861 HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
2863 TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
2865 /* Check range of value.
2867 if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
2869 return DISP_E_OVERFLOW;
2872 *pfltOut = (FLOAT) dblIn;
2877 /******************************************************************************
2878 * VarR4FromDate [OLEAUT32.73]
2880 HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
2882 TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
2884 /* Check range of value.
2886 if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
2888 return DISP_E_OVERFLOW;
2891 *pfltOut = (FLOAT) dateIn;
2896 /******************************************************************************
2897 * VarR4FromBool [OLEAUT32.76]
2899 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
2901 TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
2903 *pfltOut = (FLOAT) boolIn;
2908 /******************************************************************************
2909 * VarR4FromI1 [OLEAUT32.213]
2911 HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
2913 TRACE("( %c, %p ), stub\n", cIn, pfltOut );
2915 *pfltOut = (FLOAT) cIn;
2920 /******************************************************************************
2921 * VarR4FromUI2 [OLEAUT32.214]
2923 HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
2925 TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
2927 *pfltOut = (FLOAT) uiIn;
2932 /******************************************************************************
2933 * VarR4FromUI4 [OLEAUT32.215]
2935 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
2937 TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
2939 *pfltOut = (FLOAT) ulIn;
2944 /******************************************************************************
2945 * VarR4FromStr [OLEAUT32.74]
2947 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
2949 double dValue = 0.0;
2950 LPSTR pNewString = NULL;
2952 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
2954 /* Check if we have a valid argument
2956 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2957 RemoveCharacterFromString( pNewString, "," );
2958 if( IsValidRealString( pNewString ) == FALSE )
2960 return DISP_E_TYPEMISMATCH;
2963 /* Convert the valid string to a floating point number.
2965 dValue = atof( pNewString );
2967 /* We don't need the string anymore so free it.
2969 HeapFree( GetProcessHeap(), 0, pNewString );
2971 /* Check range of value.
2973 if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
2975 return DISP_E_OVERFLOW;
2978 *pfltOut = (FLOAT) dValue;
2983 /**********************************************************************
2984 * VarR4FromCy [OLEAUT32.72]
2985 * Convert currency to float
2987 HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
2988 *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2993 /******************************************************************************
2994 * VarR8FromUI1 [OLEAUT32.78]
2996 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
2998 TRACE("( %d, %p ), stub\n", bIn, pdblOut );
3000 *pdblOut = (double) bIn;
3005 /******************************************************************************
3006 * VarR8FromI2 [OLEAUT32.79]
3008 HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
3010 TRACE("( %d, %p ), stub\n", sIn, pdblOut );
3012 *pdblOut = (double) sIn;
3017 /******************************************************************************
3018 * VarR8FromI4 [OLEAUT32.80]
3020 HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
3022 TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
3024 *pdblOut = (double) lIn;
3029 /******************************************************************************
3030 * VarR8FromR4 [OLEAUT32.81]
3032 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
3034 TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
3036 *pdblOut = (double) fltIn;
3041 /******************************************************************************
3042 * VarR8FromDate [OLEAUT32.83]
3044 HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
3046 TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
3048 *pdblOut = (double) dateIn;
3053 /******************************************************************************
3054 * VarR8FromBool [OLEAUT32.86]
3056 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
3058 TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
3060 *pdblOut = (double) boolIn;
3065 /******************************************************************************
3066 * VarR8FromI1 [OLEAUT32.217]
3068 HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
3070 TRACE("( %c, %p ), stub\n", cIn, pdblOut );
3072 *pdblOut = (double) cIn;
3077 /******************************************************************************
3078 * VarR8FromUI2 [OLEAUT32.218]
3080 HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
3082 TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
3084 *pdblOut = (double) uiIn;
3089 /******************************************************************************
3090 * VarR8FromUI4 [OLEAUT32.219]
3092 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
3094 TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
3096 *pdblOut = (double) ulIn;
3101 /******************************************************************************
3102 * VarR8FromStr [OLEAUT32.84]
3104 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
3106 double dValue = 0.0;
3107 LPSTR pNewString = NULL;
3109 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3110 TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString, lcid, dwFlags, pdblOut );
3112 /* Check if we have a valid argument
3114 RemoveCharacterFromString( pNewString, "," );
3115 if( IsValidRealString( pNewString ) == FALSE )
3117 return DISP_E_TYPEMISMATCH;
3120 /* Convert the valid string to a floating point number.
3122 dValue = atof( pNewString );
3124 /* We don't need the string anymore so free it.
3126 HeapFree( GetProcessHeap(), 0, pNewString );
3133 /**********************************************************************
3134 * VarR8FromCy [OLEAUT32.82]
3135 * Convert currency to double
3137 HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
3138 *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3139 TRACE("%lu %ld -> %f\n", cyIn.s.Hi, cyIn.s.Lo, *pdblOut);
3143 /******************************************************************************
3144 * VarDateFromUI1 [OLEAUT32.88]
3146 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
3148 TRACE("( %d, %p ), stub\n", bIn, pdateOut );
3150 *pdateOut = (DATE) bIn;
3155 /******************************************************************************
3156 * VarDateFromI2 [OLEAUT32.89]
3158 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
3160 TRACE("( %d, %p ), stub\n", sIn, pdateOut );
3162 *pdateOut = (DATE) sIn;
3167 /******************************************************************************
3168 * VarDateFromI4 [OLEAUT32.90]
3170 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3172 TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
3174 if( lIn < DATE_MIN || lIn > DATE_MAX )
3176 return DISP_E_OVERFLOW;
3179 *pdateOut = (DATE) lIn;
3184 /******************************************************************************
3185 * VarDateFromR4 [OLEAUT32.91]
3187 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3189 TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3191 if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
3193 return DISP_E_OVERFLOW;
3196 *pdateOut = (DATE) fltIn;
3201 /******************************************************************************
3202 * VarDateFromR8 [OLEAUT32.92]
3204 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3206 TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3208 if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3210 return DISP_E_OVERFLOW;
3213 *pdateOut = (DATE) dblIn;
3218 /******************************************************************************
3219 * VarDateFromStr [OLEAUT32.94]
3220 * The string representing the date is composed of two parts, a date and time.
3222 * The format of the time is has follows:
3223 * hh[:mm][:ss][AM|PM]
3224 * Whitespace can be inserted anywhere between these tokens. A whitespace consists
3225 * of space and/or tab characters, which are ignored.
3227 * The formats for the date part are has follows:
3231 * January dd[,] [yy]yy
3234 * Whitespace can be inserted anywhere between these tokens.
3236 * The formats for the date and time string are has follows.
3237 * date[whitespace][time]
3238 * [time][whitespace]date
3240 * These are the only characters allowed in a string representing a date and time:
3241 * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3243 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3248 memset( &TM, 0, sizeof(TM) );
3250 TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3252 if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
3254 if( TmToDATE( &TM, pdateOut ) == FALSE )
3261 ret = DISP_E_TYPEMISMATCH;
3263 TRACE("Return value %f\n", *pdateOut);
3267 /******************************************************************************
3268 * VarDateFromI1 [OLEAUT32.221]
3270 HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
3272 TRACE("( %c, %p ), stub\n", cIn, pdateOut );
3274 *pdateOut = (DATE) cIn;
3279 /******************************************************************************
3280 * VarDateFromUI2 [OLEAUT32.222]
3282 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3284 TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
3286 if( uiIn > DATE_MAX )
3288 return DISP_E_OVERFLOW;
3291 *pdateOut = (DATE) uiIn;
3296 /******************************************************************************
3297 * VarDateFromUI4 [OLEAUT32.223]
3299 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3301 TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
3303 if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3305 return DISP_E_OVERFLOW;
3308 *pdateOut = (DATE) ulIn;
3313 /******************************************************************************
3314 * VarDateFromBool [OLEAUT32.96]
3316 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3318 TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
3320 *pdateOut = (DATE) boolIn;
3325 /**********************************************************************
3326 * VarDateFromCy [OLEAUT32.93]
3327 * Convert currency to date
3329 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
3330 *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3332 if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3336 /******************************************************************************
3337 * VarBstrFromUI1 [OLEAUT32.108]
3339 HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3341 TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3342 sprintf( pBuffer, "%d", bVal );
3344 *pbstrOut = StringDupAtoBstr( pBuffer );
3349 /******************************************************************************
3350 * VarBstrFromI2 [OLEAUT32.109]
3352 HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3354 TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3355 sprintf( pBuffer, "%d", iVal );
3356 *pbstrOut = StringDupAtoBstr( pBuffer );
3361 /******************************************************************************
3362 * VarBstrFromI4 [OLEAUT32.110]
3364 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3366 TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
3368 sprintf( pBuffer, "%ld", lIn );
3369 *pbstrOut = StringDupAtoBstr( pBuffer );
3374 /******************************************************************************
3375 * VarBstrFromR4 [OLEAUT32.111]
3377 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3379 TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
3381 sprintf( pBuffer, "%.7g", fltIn );
3382 *pbstrOut = StringDupAtoBstr( pBuffer );
3387 /******************************************************************************
3388 * VarBstrFromR8 [OLEAUT32.112]
3390 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3392 TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
3394 sprintf( pBuffer, "%.15g", dblIn );
3395 *pbstrOut = StringDupAtoBstr( pBuffer );
3400 /******************************************************************************
3401 * VarBstrFromCy [OLEAUT32.113]
3403 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
3405 double curVal = 0.0;
3407 TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid, dwFlags, pbstrOut);
3409 /* Firstly get the currency in a double, then put it in a buffer */
3410 rc = VarR8FromCy(cyIn, &curVal);
3412 sprintf(pBuffer, "%g", curVal);
3413 *pbstrOut = StringDupAtoBstr( pBuffer );
3419 /******************************************************************************
3420 * VarBstrFromDate [OLEAUT32.114]
3422 * The date is implemented using an 8 byte floating-point number.
3423 * Days are represented by whole numbers increments starting with 0.00 as
3424 * being December 30 1899, midnight.
3425 * The hours are expressed as the fractional part of the number.
3426 * December 30 1899 at midnight = 0.00
3427 * January 1 1900 at midnight = 2.00
3428 * January 4 1900 at 6 AM = 5.25
3429 * January 4 1900 at noon = 5.50
3430 * December 29 1899 at midnight = -1.00
3431 * December 18 1899 at midnight = -12.00
3432 * December 18 1899 at 6AM = -12.25
3433 * December 18 1899 at 6PM = -12.75
3434 * December 19 1899 at midnight = -11.00
3435 * The tm structure is as follows:
3437 * int tm_sec; seconds after the minute - [0,59]
3438 * int tm_min; minutes after the hour - [0,59]
3439 * int tm_hour; hours since midnight - [0,23]
3440 * int tm_mday; day of the month - [1,31]
3441 * int tm_mon; months since January - [0,11]
3442 * int tm_year; years
3443 * int tm_wday; days since Sunday - [0,6]
3444 * int tm_yday; days since January 1 - [0,365]
3445 * int tm_isdst; daylight savings time flag
3448 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3451 memset( &TM, 0, sizeof(TM) );
3453 TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
3455 if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
3457 return E_INVALIDARG;
3460 if( dwFlags & VAR_DATEVALUEONLY )
3461 strftime( pBuffer, BUFFER_MAX, "%x", &TM );
3462 else if( dwFlags & VAR_TIMEVALUEONLY )
3463 strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3465 strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3467 TRACE("result: %s\n", pBuffer);
3468 *pbstrOut = StringDupAtoBstr( pBuffer );
3472 /******************************************************************************
3473 * VarBstrFromBool [OLEAUT32.116]
3475 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3477 TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
3479 sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
3481 *pbstrOut = StringDupAtoBstr( pBuffer );
3486 /******************************************************************************
3487 * VarBstrFromI1 [OLEAUT32.229]
3489 HRESULT WINAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3491 TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3492 sprintf( pBuffer, "%d", cIn );
3493 *pbstrOut = StringDupAtoBstr( pBuffer );
3498 /******************************************************************************
3499 * VarBstrFromUI2 [OLEAUT32.230]
3501 HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3503 TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3504 sprintf( pBuffer, "%d", uiIn );
3505 *pbstrOut = StringDupAtoBstr( pBuffer );
3510 /******************************************************************************
3511 * VarBstrFromUI4 [OLEAUT32.231]
3513 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3515 TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3516 sprintf( pBuffer, "%ld", ulIn );
3517 *pbstrOut = StringDupAtoBstr( pBuffer );
3522 /******************************************************************************
3523 * VarBoolFromUI1 [OLEAUT32.118]
3525 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3527 TRACE("( %d, %p ), stub\n", bIn, pboolOut );
3531 *pboolOut = VARIANT_FALSE;
3535 *pboolOut = VARIANT_TRUE;
3541 /******************************************************************************
3542 * VarBoolFromI2 [OLEAUT32.119]
3544 HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3546 TRACE("( %d, %p ), stub\n", sIn, pboolOut );
3548 *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
3553 /******************************************************************************
3554 * VarBoolFromI4 [OLEAUT32.120]
3556 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3558 TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
3560 *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
3565 /******************************************************************************
3566 * VarBoolFromR4 [OLEAUT32.121]
3568 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3570 TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
3572 *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3577 /******************************************************************************
3578 * VarBoolFromR8 [OLEAUT32.122]
3580 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3582 TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
3584 *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3589 /******************************************************************************
3590 * VarBoolFromDate [OLEAUT32.123]
3592 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3594 TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
3596 *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3601 /******************************************************************************
3602 * VarBoolFromStr [OLEAUT32.125]
3604 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3607 char* pNewString = NULL;
3609 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
3611 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3613 if( pNewString == NULL || strlen( pNewString ) == 0 )
3615 ret = DISP_E_TYPEMISMATCH;
3620 if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
3622 *pboolOut = VARIANT_TRUE;
3624 else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
3626 *pboolOut = VARIANT_FALSE;
3630 /* Try converting the string to a floating point number.
3632 double dValue = 0.0;
3633 HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3636 ret = DISP_E_TYPEMISMATCH;
3639 *pboolOut = (dValue == 0.0) ?
3640 VARIANT_FALSE : VARIANT_TRUE;
3644 HeapFree( GetProcessHeap(), 0, pNewString );
3649 /******************************************************************************
3650 * VarBoolFromI1 [OLEAUT32.233]
3652 HRESULT WINAPI VarBoolFromI1(CHAR cIn, VARIANT_BOOL* pboolOut)
3654 TRACE("( %c, %p ), stub\n", cIn, pboolOut );
3656 *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3661 /******************************************************************************
3662 * VarBoolFromUI2 [OLEAUT32.234]
3664 HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3666 TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
3668 *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3673 /******************************************************************************
3674 * VarBoolFromUI4 [OLEAUT32.235]
3676 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3678 TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
3680 *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3685 /**********************************************************************
3686 * VarBoolFromCy [OLEAUT32.124]
3687 * Convert currency to boolean
3689 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
3690 if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
3696 /******************************************************************************
3697 * VarI1FromUI1 [OLEAUT32.244]
3699 HRESULT WINAPI VarI1FromUI1(BYTE bIn, CHAR* pcOut)
3701 TRACE("( %d, %p ), stub\n", bIn, pcOut );
3703 /* Check range of value.
3705 if( bIn > CHAR_MAX )
3707 return DISP_E_OVERFLOW;
3710 *pcOut = (CHAR) bIn;
3715 /******************************************************************************
3716 * VarI1FromI2 [OLEAUT32.245]
3718 HRESULT WINAPI VarI1FromI2(short uiIn, CHAR* pcOut)
3720 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3722 if( uiIn > CHAR_MAX )
3724 return DISP_E_OVERFLOW;
3727 *pcOut = (CHAR) uiIn;
3732 /******************************************************************************
3733 * VarI1FromI4 [OLEAUT32.246]
3735 HRESULT WINAPI VarI1FromI4(LONG lIn, CHAR* pcOut)
3737 TRACE("( %ld, %p ), stub\n", lIn, pcOut );
3739 if( lIn < CHAR_MIN || lIn > CHAR_MAX )
3741 return DISP_E_OVERFLOW;
3744 *pcOut = (CHAR) lIn;
3749 /******************************************************************************
3750 * VarI1FromR4 [OLEAUT32.247]
3752 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, CHAR* pcOut)
3754 TRACE("( %f, %p ), stub\n", fltIn, pcOut );
3756 fltIn = round( fltIn );
3757 if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
3759 return DISP_E_OVERFLOW;
3762 *pcOut = (CHAR) fltIn;
3767 /******************************************************************************
3768 * VarI1FromR8 [OLEAUT32.248]
3770 HRESULT WINAPI VarI1FromR8(double dblIn, CHAR* pcOut)
3772 TRACE("( %f, %p ), stub\n", dblIn, pcOut );
3774 dblIn = round( dblIn );
3775 if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
3777 return DISP_E_OVERFLOW;
3780 *pcOut = (CHAR) dblIn;
3785 /******************************************************************************
3786 * VarI1FromDate [OLEAUT32.249]
3788 HRESULT WINAPI VarI1FromDate(DATE dateIn, CHAR* pcOut)
3790 TRACE("( %f, %p ), stub\n", dateIn, pcOut );
3792 dateIn = round( dateIn );
3793 if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
3795 return DISP_E_OVERFLOW;
3798 *pcOut = (CHAR) dateIn;
3803 /******************************************************************************
3804 * VarI1FromStr [OLEAUT32.251]
3806 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CHAR* pcOut)
3808 double dValue = 0.0;
3809 LPSTR pNewString = NULL;
3811 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
3813 /* Check if we have a valid argument
3815 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3816 RemoveCharacterFromString( pNewString, "," );
3817 if( IsValidRealString( pNewString ) == FALSE )
3819 return DISP_E_TYPEMISMATCH;
3822 /* Convert the valid string to a floating point number.
3824 dValue = atof( pNewString );
3826 /* We don't need the string anymore so free it.
3828 HeapFree( GetProcessHeap(), 0, pNewString );
3830 /* Check range of value.
3832 dValue = round( dValue );
3833 if( dValue < CHAR_MIN || dValue > CHAR_MAX )
3835 return DISP_E_OVERFLOW;
3838 *pcOut = (CHAR) dValue;
3843 /******************************************************************************
3844 * VarI1FromBool [OLEAUT32.253]
3846 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
3848 TRACE("( %d, %p ), stub\n", boolIn, pcOut );
3850 *pcOut = (CHAR) boolIn;
3855 /******************************************************************************
3856 * VarI1FromUI2 [OLEAUT32.254]
3858 HRESULT WINAPI VarI1FromUI2(USHORT uiIn, CHAR* pcOut)
3860 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3862 if( uiIn > CHAR_MAX )
3864 return DISP_E_OVERFLOW;
3867 *pcOut = (CHAR) uiIn;
3872 /******************************************************************************
3873 * VarI1FromUI4 [OLEAUT32.255]
3875 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, CHAR* pcOut)
3877 TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
3879 if( ulIn > CHAR_MAX )
3881 return DISP_E_OVERFLOW;
3884 *pcOut = (CHAR) ulIn;
3889 /**********************************************************************
3890 * VarI1FromCy [OLEAUT32.250]
3891 * Convert currency to signed char
3893 HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
3894 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3896 if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
3902 /******************************************************************************
3903 * VarUI2FromUI1 [OLEAUT32.257]
3905 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
3907 TRACE("( %d, %p ), stub\n", bIn, puiOut );
3909 *puiOut = (USHORT) bIn;
3914 /******************************************************************************
3915 * VarUI2FromI2 [OLEAUT32.258]
3917 HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
3919 TRACE("( %d, %p ), stub\n", uiIn, puiOut );
3921 if( uiIn < UI2_MIN )
3923 return DISP_E_OVERFLOW;
3926 *puiOut = (USHORT) uiIn;
3931 /******************************************************************************
3932 * VarUI2FromI4 [OLEAUT32.259]
3934 HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
3936 TRACE("( %ld, %p ), stub\n", lIn, puiOut );
3938 if( lIn < UI2_MIN || lIn > UI2_MAX )
3940 return DISP_E_OVERFLOW;
3943 *puiOut = (USHORT) lIn;
3948 /******************************************************************************
3949 * VarUI2FromR4 [OLEAUT32.260]
3951 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
3953 TRACE("( %f, %p ), stub\n", fltIn, puiOut );
3955 fltIn = round( fltIn );
3956 if( fltIn < UI2_MIN || fltIn > UI2_MAX )
3958 return DISP_E_OVERFLOW;
3961 *puiOut = (USHORT) fltIn;
3966 /******************************************************************************
3967 * VarUI2FromR8 [OLEAUT32.261]
3969 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
3971 TRACE("( %f, %p ), stub\n", dblIn, puiOut );
3973 dblIn = round( dblIn );
3974 if( dblIn < UI2_MIN || dblIn > UI2_MAX )
3976 return DISP_E_OVERFLOW;
3979 *puiOut = (USHORT) dblIn;
3984 /******************************************************************************
3985 * VarUI2FromDate [OLEAUT32.262]
3987 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
3989 TRACE("( %f, %p ), stub\n", dateIn, puiOut );
3991 dateIn = round( dateIn );
3992 if( dateIn < UI2_MIN || dateIn > UI2_MAX )
3994 return DISP_E_OVERFLOW;
3997 *puiOut = (USHORT) dateIn;
4002 /******************************************************************************
4003 * VarUI2FromStr [OLEAUT32.264]
4005 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
4007 double dValue = 0.0;
4008 LPSTR pNewString = NULL;
4010 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
4012 /* Check if we have a valid argument
4014 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4015 RemoveCharacterFromString( pNewString, "," );
4016 if( IsValidRealString( pNewString ) == FALSE )
4018 return DISP_E_TYPEMISMATCH;
4021 /* Convert the valid string to a floating point number.
4023 dValue = atof( pNewString );
4025 /* We don't need the string anymore so free it.
4027 HeapFree( GetProcessHeap(), 0, pNewString );
4029 /* Check range of value.
4031 dValue = round( dValue );
4032 if( dValue < UI2_MIN || dValue > UI2_MAX )
4034 return DISP_E_OVERFLOW;
4037 *puiOut = (USHORT) dValue;
4042 /******************************************************************************
4043 * VarUI2FromBool [OLEAUT32.266]
4045 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
4047 TRACE("( %d, %p ), stub\n", boolIn, puiOut );
4049 *puiOut = (USHORT) boolIn;
4054 /******************************************************************************
4055 * VarUI2FromI1 [OLEAUT32.267]
4057 HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
4059 TRACE("( %c, %p ), stub\n", cIn, puiOut );
4061 *puiOut = (USHORT) cIn;
4066 /******************************************************************************
4067 * VarUI2FromUI4 [OLEAUT32.268]
4069 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
4071 TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
4073 if( ulIn > UI2_MAX )
4075 return DISP_E_OVERFLOW;
4078 *puiOut = (USHORT) ulIn;
4083 /******************************************************************************
4084 * VarUI4FromStr [OLEAUT32.277]
4086 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
4088 double dValue = 0.0;
4089 LPSTR pNewString = NULL;
4091 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
4093 /* Check if we have a valid argument
4095 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4096 RemoveCharacterFromString( pNewString, "," );
4097 if( IsValidRealString( pNewString ) == FALSE )
4099 return DISP_E_TYPEMISMATCH;
4102 /* Convert the valid string to a floating point number.
4104 dValue = atof( pNewString );
4106 /* We don't need the string anymore so free it.
4108 HeapFree( GetProcessHeap(), 0, pNewString );
4110 /* Check range of value.
4112 dValue = round( dValue );
4113 if( dValue < UI4_MIN || dValue > UI4_MAX )
4115 return DISP_E_OVERFLOW;
4118 *pulOut = (ULONG) dValue;
4123 /**********************************************************************
4124 * VarUI2FromCy [OLEAUT32.263]
4125 * Convert currency to unsigned short
4127 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
4128 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4130 if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
4132 *pusOut = (USHORT)t;
4137 /******************************************************************************
4138 * VarUI4FromUI1 [OLEAUT32.270]
4140 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
4142 TRACE("( %d, %p ), stub\n", bIn, pulOut );
4144 *pulOut = (USHORT) bIn;
4149 /******************************************************************************
4150 * VarUI4FromI2 [OLEAUT32.271]
4152 HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
4154 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4156 if( uiIn < UI4_MIN )
4158 return DISP_E_OVERFLOW;
4161 *pulOut = (ULONG) uiIn;
4166 /******************************************************************************
4167 * VarUI4FromI4 [OLEAUT32.272]
4169 HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
4171 TRACE("( %ld, %p ), stub\n", lIn, pulOut );
4175 return DISP_E_OVERFLOW;
4178 *pulOut = (ULONG) lIn;
4183 /******************************************************************************
4184 * VarUI4FromR4 [OLEAUT32.273]
4186 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
4188 fltIn = round( fltIn );
4189 if( fltIn < UI4_MIN || fltIn > UI4_MAX )
4191 return DISP_E_OVERFLOW;
4194 *pulOut = (ULONG) fltIn;
4199 /******************************************************************************
4200 * VarUI4FromR8 [OLEAUT32.274]
4202 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
4204 TRACE("( %f, %p ), stub\n", dblIn, pulOut );
4206 dblIn = round( dblIn );
4207 if( dblIn < UI4_MIN || dblIn > UI4_MAX )
4209 return DISP_E_OVERFLOW;
4212 *pulOut = (ULONG) dblIn;
4217 /******************************************************************************
4218 * VarUI4FromDate [OLEAUT32.275]
4220 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
4222 TRACE("( %f, %p ), stub\n", dateIn, pulOut );
4224 dateIn = round( dateIn );
4225 if( dateIn < UI4_MIN || dateIn > UI4_MAX )
4227 return DISP_E_OVERFLOW;
4230 *pulOut = (ULONG) dateIn;
4235 /******************************************************************************
4236 * VarUI4FromBool [OLEAUT32.279]
4238 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
4240 TRACE("( %d, %p ), stub\n", boolIn, pulOut );
4242 *pulOut = (ULONG) boolIn;
4247 /******************************************************************************
4248 * VarUI4FromI1 [OLEAUT32.280]
4250 HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
4252 TRACE("( %c, %p ), stub\n", cIn, pulOut );
4254 *pulOut = (ULONG) cIn;
4259 /******************************************************************************
4260 * VarUI4FromUI2 [OLEAUT32.281]
4262 HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4264 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4266 *pulOut = (ULONG) uiIn;
4271 /**********************************************************************
4272 * VarUI4FromCy [OLEAUT32.276]
4273 * Convert currency to unsigned long
4275 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
4276 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4278 if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4285 /**********************************************************************
4286 * VarCyFromUI1 [OLEAUT32.98]
4287 * Convert unsigned char to currency
4289 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
4291 pcyOut->s.Lo = ((ULONG)bIn) * 10000;
4296 /**********************************************************************
4297 * VarCyFromI2 [OLEAUT32.99]
4298 * Convert signed short to currency
4300 HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
4301 if (sIn < 0) pcyOut->s.Hi = -1;
4302 else pcyOut->s.Hi = 0;
4303 pcyOut->s.Lo = ((ULONG)sIn) * 10000;
4308 /**********************************************************************
4309 * VarCyFromI4 [OLEAUT32.100]
4310 * Convert signed long to currency
4312 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4313 double t = (double)lIn * (double)10000;
4314 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4315 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4316 if (lIn < 0) pcyOut->s.Hi--;
4321 /**********************************************************************
4322 * VarCyFromR4 [OLEAUT32.101]
4323 * Convert float to currency
4325 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
4326 double t = round((double)fltIn * (double)10000);
4327 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4328 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4329 if (fltIn < 0) pcyOut->s.Hi--;
4334 /**********************************************************************
4335 * VarCyFromR8 [OLEAUT32.102]
4336 * Convert double to currency
4338 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
4339 double t = round(dblIn * (double)10000);
4340 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4341 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4342 if (dblIn < 0) pcyOut->s.Hi--;
4347 /**********************************************************************
4348 * VarCyFromDate [OLEAUT32.103]
4349 * Convert date to currency
4351 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
4352 double t = round((double)dateIn * (double)10000);
4353 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4354 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4355 if (dateIn < 0) pcyOut->s.Hi--;
4360 /**********************************************************************
4361 * VarCyFromStr [OLEAUT32.104]
4362 * FIXME: Never tested with decimal seperator other than '.'
4364 HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
4366 LPSTR pNewString = NULL;
4367 char *decSep = NULL;
4368 char *strPtr,*curPtr = NULL;
4370 double currencyVal = 0.0;
4373 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4374 TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString, lcid, dwFlags, pcyOut );
4376 /* Get locale information - Decimal Seperator (size includes 0x00) */
4377 size = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, NULL, 0);
4378 decSep = (char *) malloc(size);
4379 rc = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, decSep, size);
4380 TRACE("Decimal Seperator is '%s'\n", decSep);
4382 /* Now copy to temporary buffer, skipping any character except 0-9 and
4383 the decimal seperator */
4384 curPtr = pBuffer; /* Current position in string being built */
4385 strPtr = pNewString; /* Current position in supplied currenct string */
4388 /* If decimal seperator, skip it and put '.' in string */
4389 if (strncmp(strPtr, decSep, (size-1)) == 0) {
4390 strPtr = strPtr + (size-1);
4393 } else if ((*strPtr == '+' || *strPtr == '-') ||
4394 (*strPtr >= '0' && *strPtr <= '9')) {
4402 /* Try to get currency into a double */
4403 currencyVal = atof(pBuffer);
4404 TRACE("Converted string '%s' to %f\n", pBuffer, currencyVal);
4406 /* Free allocated storage */
4407 HeapFree( GetProcessHeap(), 0, pNewString );
4410 /* Convert double -> currency using internal routine */
4411 return VarCyFromR8(currencyVal, pcyOut);
4415 /**********************************************************************
4416 * VarCyFromBool [OLEAUT32.106]
4417 * Convert boolean to currency
4419 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
4420 if (boolIn < 0) pcyOut->s.Hi = -1;
4421 else pcyOut->s.Hi = 0;
4422 pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
4427 /**********************************************************************
4428 * VarCyFromI1 [OLEAUT32.225]
4429 * Convert signed char to currency
4431 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
4432 if (cIn < 0) pcyOut->s.Hi = -1;
4433 else pcyOut->s.Hi = 0;
4434 pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
4439 /**********************************************************************
4440 * VarCyFromUI2 [OLEAUT32.226]
4441 * Convert unsigned short to currency
4443 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
4445 pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
4450 /**********************************************************************
4451 * VarCyFromUI4 [OLEAUT32.227]
4452 * Convert unsigned long to currency
4454 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4455 double t = (double)ulIn * (double)10000;
4456 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4457 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4463 /**********************************************************************
4464 * DosDateTimeToVariantTime [OLEAUT32.14]
4465 * Convert dos representation of time to the date and time representation
4466 * stored in a variant.
4468 INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4473 TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
4475 t.tm_sec = (wDosTime & 0x001f) * 2;
4476 t.tm_min = (wDosTime & 0x07e0) >> 5;
4477 t.tm_hour = (wDosTime & 0xf800) >> 11;
4479 t.tm_mday = (wDosDate & 0x001f);
4480 t.tm_mon = (wDosDate & 0x01e0) >> 5;
4481 t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
4483 return TmToDATE( &t, pvtime );
4487 /**********************************************************************
4488 * VarParseNumFromStr [OLEAUT32.46]
4490 HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
4491 NUMPARSE * pnumprs, BYTE * rgbDig)
4495 BOOL foundNum=FALSE;
4497 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
4498 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
4500 /* The other struct components are to be set by us */
4501 memset(rgbDig,0,pnumprs->cDig);
4503 /* FIXME: Just patching some values in */
4504 pnumprs->nPwr10 = 0;
4505 pnumprs->nBaseShift = 0;
4506 pnumprs->cchUsed = lastent;
4507 pnumprs->dwOutFlags = NUMPRS_DECIMAL;
4510 for (i=0; strIn[i] ;i++) {
4511 if ((strIn[i]>='0') && (strIn[i]<='9')) {
4513 if (pnumprs->cDig > cDig) {
4514 *(rgbDig++)=strIn[i]-'0';
4518 } else if ((strIn[i]=='-') && (foundNum==FALSE)) {
4519 pnumprs->dwOutFlags |= NUMPRS_NEG;
4522 pnumprs->cDig = cDig;
4523 TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags);
4528 /**********************************************************************
4529 * VarNumFromParseNum [OLEAUT32.47]
4531 HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
4532 ULONG dwVtBits, VARIANT * pvar)
4536 FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
4539 for (i=0;i<pnumprs->cDig;i++)
4540 xint = xint*10 + rgbDig[i];
4542 if (pnumprs->dwOutFlags & NUMPRS_NEG) {
4547 if (dwVtBits & VTBIT_I4) {
4549 V_UNION(pvar,intVal) = xint;
4552 if (dwVtBits & VTBIT_R8) {
4554 V_UNION(pvar,dblVal) = xint;
4557 if (dwVtBits & VTBIT_R4) {
4559 V_UNION(pvar,fltVal) = xint;
4562 if (dwVtBits & VTBIT_I2) {
4564 V_UNION(pvar,iVal) = xint;
4567 /* FIXME: Currency should be from a double */
4568 if (dwVtBits & VTBIT_CY) {
4570 TRACE("Calculated currency is xint=%ld\n", xint);
4571 VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4572 TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar,cyVal).s.Hi, V_UNION(pvar,cyVal).s.Lo);
4573 return VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4576 FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint);
4581 /**********************************************************************
4582 * VarFormatDateTime [OLEAUT32.97]
4584 HRESULT WINAPI VarFormatDateTime(LPVARIANT var, INT format, ULONG dwFlags, BSTR *out)
4586 FIXME("%p %d %lx %p\n", var, format, dwFlags, out);
4590 /**********************************************************************
4591 * VarFormatCurrency [OLEAUT32.127]
4593 HRESULT WINAPI VarFormatCurrency(LPVARIANT var, INT digits, INT lead, INT paren, INT group, ULONG dwFlags, BSTR *out)
4595 FIXME("%p %d %d %d %d %lx %p\n", var, digits, lead, paren, group, dwFlags, out);
4599 /**********************************************************************
4600 * VariantTimeToDosDateTime [OLEAUT32.13]
4601 * Convert variant representation of time to the date and time representation
4604 INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
4610 TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate, *wDosTime, &pvtime );
4612 if (DateToTm(pvtime, 0, &t) < 0) return 0;
4614 *wDosTime = *wDosTime | (t.tm_sec / 2);
4615 *wDosTime = *wDosTime | (t.tm_min << 5);
4616 *wDosTime = *wDosTime | (t.tm_hour << 11);
4618 *wDosDate = *wDosDate | t.tm_mday ;
4619 *wDosDate = *wDosDate | t.tm_mon << 5;
4620 *wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
4626 /***********************************************************************
4627 * SystemTimeToVariantTime [OLEAUT32.184]
4629 HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime, double *pvtime )
4633 TRACE(" %d/%d/%d %d:%d:%d\n",
4634 lpSystemTime->wMonth, lpSystemTime->wDay,
4635 lpSystemTime->wYear, lpSystemTime->wHour,
4636 lpSystemTime->wMinute, lpSystemTime->wSecond);
4638 if (lpSystemTime->wYear >= 1900)
4640 t.tm_sec = lpSystemTime->wSecond;
4641 t.tm_min = lpSystemTime->wMinute;
4642 t.tm_hour = lpSystemTime->wHour;
4644 t.tm_mday = lpSystemTime->wDay;
4645 t.tm_mon = lpSystemTime->wMonth - 1; /* tm_mon is 0..11, wMonth is 1..12 */
4646 t.tm_year = lpSystemTime->wYear;
4648 return TmToDATE( &t, pvtime );
4653 long firstDayOfNextYear;
4658 double decimalPart = 0.0;
4660 t.tm_sec = lpSystemTime->wSecond;
4661 t.tm_min = lpSystemTime->wMinute;
4662 t.tm_hour = lpSystemTime->wHour;
4664 /* Step year forward the same number of years before 1900 */
4665 t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
4666 t.tm_mon = lpSystemTime->wMonth - 1;
4667 t.tm_mday = lpSystemTime->wDay;
4669 /* Calculate date */
4670 TmToDATE( &t, pvtime );
4672 thisDay = (double) floor( *pvtime );
4673 decimalPart = fmod( *pvtime, thisDay );
4675 /* Now, calculate the same time for the first of Jan that year */
4681 t.tm_year = t.tm_year+1;
4682 TmToDATE( &t, &tmpDate );
4683 firstDayOfNextYear = (long) floor(tmpDate);
4685 /* Finally since we know the size of the year, subtract the two to get
4686 remaining time in the year */
4687 leftInYear = firstDayOfNextYear - thisDay;
4689 /* Now we want full years up to the year in question, and remainder of year
4690 of the year in question */
4691 if (isleap(lpSystemTime->wYear) ) {
4692 TRACE("Extra day due to leap year\n");
4693 result = 2.0 - ((firstDayOfNextYear - 366) + leftInYear - 2.0);
4695 result = 2.0 - ((firstDayOfNextYear - 365) + leftInYear - 2.0);
4697 *pvtime = (double) result + decimalPart;
4698 TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime, firstDayOfNextYear, thisDay, leftInYear);
4706 /***********************************************************************
4707 * VariantTimeToSystemTime [OLEAUT32.185]
4709 HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME lpSystemTime )
4711 double t = 0, timeofday = 0;
4713 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4714 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4716 /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4717 static const BYTE Month_Code[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4718 static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4720 /* The Century_Code is used to find the Day of the Week */
4721 static const BYTE Century_Code[] = {0, 6, 4, 2};
4725 TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime);
4730 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4732 lpSystemTime->wSecond = r.tm_sec;
4733 lpSystemTime->wMinute = r.tm_min;
4734 lpSystemTime->wHour = r.tm_hour;
4735 lpSystemTime->wDay = r.tm_mday;
4736 lpSystemTime->wMonth = r.tm_mon;
4738 if (lpSystemTime->wMonth == 12)
4739 lpSystemTime->wMonth = 1;
4741 lpSystemTime->wMonth++;
4743 lpSystemTime->wYear = r.tm_year;
4749 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4751 lpSystemTime->wSecond = r.tm_sec;
4752 lpSystemTime->wMinute = r.tm_min;
4753 lpSystemTime->wHour = r.tm_hour;
4755 lpSystemTime->wMonth = 13 - r.tm_mon;
4757 if (lpSystemTime->wMonth == 1)
4758 lpSystemTime->wMonth = 12;
4760 lpSystemTime->wMonth--;
4762 lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
4764 if (!isleap(lpSystemTime->wYear) )
4765 lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
4767 lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
4772 if (!isleap(lpSystemTime->wYear))
4775 (Century_Code+Month_Code+Year_Code+Day) % 7
4777 The century code repeats every 400 years , so the array
4778 works out like this,
4780 Century_Code[0] is for 16th/20th Centry
4781 Century_Code[1] is for 17th/21th Centry
4782 Century_Code[2] is for 18th/22th Centry
4783 Century_Code[3] is for 19th/23th Centry
4785 The year code is found with the formula (year + (year / 4))
4786 the "year" must be between 0 and 99 .
4788 The Month Code (Month_Code[1]) starts with January and
4792 lpSystemTime->wDayOfWeek = (
4793 Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
4794 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4795 Month_Code[lpSystemTime->wMonth]+
4796 lpSystemTime->wDay) % 7;
4798 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4799 else lpSystemTime->wDayOfWeek -= 1;
4803 lpSystemTime->wDayOfWeek = (
4804 Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
4805 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4806 Month_Code_LY[lpSystemTime->wMonth]+
4807 lpSystemTime->wDay) % 7;
4809 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4810 else lpSystemTime->wDayOfWeek -= 1;
4814 timeofday = vtime - t;
4816 lpSystemTime->wMilliseconds = (timeofday
4817 - lpSystemTime->wHour*(1/24)
4818 - lpSystemTime->wMinute*(1/1440)
4819 - lpSystemTime->wSecond*(1/86400) )*(1/5184000);
4824 /***********************************************************************
4825 * VarUdateFromDate [OLEAUT32.331]
4827 HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
4830 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4831 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4833 TRACE("DATE = %f\n", (double)datein);
4834 i = VariantTimeToSystemTime(datein, &(pudateout->st) );
4838 pudateout->wDayOfYear = 0;
4840 if (isleap(pudateout->st.wYear))
4842 for (i =1; i<pudateout->st.wMonth; i++)
4843 pudateout->wDayOfYear += Days_Per_Month[i];
4847 for (i =1; i<pudateout->st.wMonth; i++)
4848 pudateout->wDayOfYear += Days_Per_Month_LY[i];
4851 pudateout->wDayOfYear += pudateout->st.wDay;
4852 dwFlags = 0; /*VAR_VALIDDATE*/
4859 /***********************************************************************
4860 * VarDateFromUdate [OLEAUT32.330]
4862 HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
4863 ULONG dwFlags, DATE *datein)
4867 TRACE(" %d/%d/%d %d:%d:%d\n",
4868 pudateout->st.wMonth, pudateout->st.wDay,
4869 pudateout->st.wYear, pudateout->st.wHour,
4870 pudateout->st.wMinute, pudateout->st.wSecond);
4873 i = SystemTimeToVariantTime(&(pudateout->st), &t);
4877 else return E_INVALIDARG;
4881 /**********************************************************************
4882 * VarBstrCmp [OLEAUT32.314]
4885 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4886 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4889 HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
4893 TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
4895 /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
4896 if((!left) || (!right)) {
4898 if (!left && (!right || *right==0)) return VARCMP_EQ;
4899 else if (!right && (!left || *left==0)) return VARCMP_EQ;
4900 else return VARCMP_NULL;
4903 if(flags&NORM_IGNORECASE)
4904 r = lstrcmpiW(left,right);
4906 r = lstrcmpW(left,right);
4916 /**********************************************************************
4917 * VarBstrCat [OLEAUT32.313]
4919 HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
4924 TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
4926 /* On Windows, NULL parms are still handled (as empty strings) */
4927 if (left) size=size + lstrlenW(left);
4928 if (right) size=size + lstrlenW(right);
4931 result = SysAllocStringLen(NULL, size);
4933 if (left) lstrcatW(result,left);
4934 if (right) lstrcatW(result,right);
4935 TRACE("result = %s, [%p]\n", debugstr_w(result), result);
4940 /**********************************************************************
4941 * VarCat [OLEAUT32.318]
4943 HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
4945 /* Should we VariantClear out? */
4946 /* Can we handle array, vector, by ref etc. */
4947 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL &&
4948 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
4950 V_VT(out) = VT_NULL;
4953 else if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR)
4955 V_VT(out) = VT_BSTR;
4956 VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out));
4960 FIXME ("types not supported\n");
4964 /**********************************************************************
4965 * VarCmp [OLEAUT32.176]
4968 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4969 * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4972 HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
4981 TRACE("Left Var:\n");
4983 TRACE("Right Var:\n");
4984 dump_Variant(right);
4986 /* If either are null, then return VARCMP_NULL */
4987 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL ||
4988 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
4991 /* Strings - use VarBstrCmp */
4992 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
4993 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
4994 return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags);
4997 /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
4998 Use LONGLONG to maximize ranges */
5000 switch (V_VT(left)&VT_TYPEMASK) {
5001 case VT_I1 : lVal = V_UNION(left,cVal); break;
5002 case VT_I2 : lVal = V_UNION(left,iVal); break;
5003 case VT_I4 : lVal = V_UNION(left,lVal); break;
5004 case VT_INT : lVal = V_UNION(left,lVal); break;
5005 case VT_UI1 : lVal = V_UNION(left,bVal); break;
5006 case VT_UI2 : lVal = V_UNION(left,uiVal); break;
5007 case VT_UI4 : lVal = V_UNION(left,ulVal); break;
5008 case VT_UINT : lVal = V_UNION(left,ulVal); break;
5009 default: lOk = FALSE;
5013 switch (V_VT(right)&VT_TYPEMASK) {
5014 case VT_I1 : rVal = V_UNION(right,cVal); break;
5015 case VT_I2 : rVal = V_UNION(right,iVal); break;
5016 case VT_I4 : rVal = V_UNION(right,lVal); break;
5017 case VT_INT : rVal = V_UNION(right,lVal); break;
5018 case VT_UI1 : rVal = V_UNION(right,bVal); break;
5019 case VT_UI2 : rVal = V_UNION(right,uiVal); break;
5020 case VT_UI4 : rVal = V_UNION(right,ulVal); break;
5021 case VT_UINT : rVal = V_UNION(right,ulVal); break;
5022 default: rOk = FALSE;
5028 } else if (lVal > rVal) {
5035 /* Strings - use VarBstrCmp */
5036 if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
5037 (V_VT(right)&VT_TYPEMASK) == VT_DATE) {
5039 if (floor(V_UNION(left,date)) == floor(V_UNION(right,date))) {
5040 /* Due to floating point rounding errors, calculate varDate in whole numbers) */
5041 double wholePart = 0.0;
5045 /* Get the fraction * 24*60*60 to make it into whole seconds */
5046 wholePart = (double) floor( V_UNION(left,date) );
5047 if (wholePart == 0) wholePart = 1;
5048 leftR = floor(fmod( V_UNION(left,date), wholePart ) * (24*60*60));
5050 wholePart = (double) floor( V_UNION(right,date) );
5051 if (wholePart == 0) wholePart = 1;
5052 rightR = floor(fmod( V_UNION(right,date), wholePart ) * (24*60*60));
5054 if (leftR < rightR) {
5056 } else if (leftR > rightR) {
5062 } else if (V_UNION(left,date) < V_UNION(right,date)) {
5064 } else if (V_UNION(left,date) > V_UNION(right,date)) {
5070 FIXME("VarCmp partial implementation, doesnt support these pair of variant types");
5074 /**********************************************************************
5075 * VarAnd [OLEAUT32.142]
5078 HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5080 HRESULT rc = E_FAIL;
5082 TRACE("Left Var:\n");
5084 TRACE("Right Var:\n");
5085 dump_Variant(right);
5087 if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5088 (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5090 V_VT(result) = VT_BOOL;
5091 if (V_BOOL(left) && V_BOOL(right)) {
5092 V_BOOL(result) = VARIANT_TRUE;
5094 V_BOOL(result) = VARIANT_FALSE;
5105 int resT = 0; /* Testing has shown I2 & I2 == I2, all else
5106 becomes I4, even unsigned ints (incl. UI2) */
5109 switch (V_VT(left)&VT_TYPEMASK) {
5110 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
5111 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
5112 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5113 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5114 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
5115 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5116 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5117 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5118 default: lOk = FALSE;
5122 switch (V_VT(right)&VT_TYPEMASK) {
5123 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
5124 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
5125 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5126 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5127 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
5128 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5129 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5130 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5131 default: rOk = FALSE;
5135 res = (lVal & rVal);
5136 V_VT(result) = resT;
5138 case VT_I2 : V_UNION(result,iVal) = res; break;
5139 case VT_I4 : V_UNION(result,lVal) = res; break;
5141 FIXME("Unexpected result variant type %x\n", resT);
5142 V_UNION(result,lVal) = res;
5147 FIXME("VarAnd stub\n");
5151 TRACE("rc=%d, Result:\n", (int) rc);
5152 dump_Variant(result);
5156 /**********************************************************************
5157 * VarAdd [OLEAUT32.141]
5158 * FIXME: From MSDN: If ... Then
5159 * Both expressions are of the string type Concatenated.
5160 * One expression is a string type and the other a character Addition.
5161 * One expression is numeric and the other is a string Addition.
5162 * Both expressions are numeric Addition.
5163 * Either expression is NULL NULL is returned.
5164 * Both expressions are empty Integer subtype is returned.
5167 HRESULT WINAPI VarAdd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5169 HRESULT rc = E_FAIL;
5171 TRACE("Left Var:\n");
5173 TRACE("Right Var:\n");
5174 dump_Variant(right);
5176 /* Handle strings as concat */
5177 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
5178 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
5179 V_VT(result) = VT_BSTR;
5180 VarBstrCat(V_BSTR(left), V_BSTR(right), &V_BSTR(result));
5189 int resT = 0; /* Testing has shown I2 + I2 == I2, all else
5193 switch (V_VT(left)&VT_TYPEMASK) {
5194 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
5195 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
5196 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5197 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5198 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
5199 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5200 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5201 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5202 default: lOk = FALSE;
5206 switch (V_VT(right)&VT_TYPEMASK) {
5207 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
5208 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
5209 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5210 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5211 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
5212 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5213 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5214 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5215 default: rOk = FALSE;
5219 res = (lVal + rVal);
5220 V_VT(result) = resT;
5222 case VT_I2 : V_UNION(result,iVal) = res; break;
5223 case VT_I4 : V_UNION(result,lVal) = res; break;
5225 FIXME("Unexpected result variant type %x\n", resT);
5226 V_UNION(result,lVal) = res;
5231 FIXME("unimplemented part\n");
5235 TRACE("rc=%d, Result:\n", (int) rc);
5236 dump_Variant(result);
5240 /**********************************************************************
5241 * VarOr [OLEAUT32.157]
5244 HRESULT WINAPI VarOr(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5246 HRESULT rc = E_FAIL;
5248 TRACE("Left Var:\n");
5250 TRACE("Right Var:\n");
5251 dump_Variant(right);
5253 if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5254 (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5256 V_VT(result) = VT_BOOL;
5257 if (V_BOOL(left) || V_BOOL(right)) {
5258 V_BOOL(result) = VARIANT_TRUE;
5260 V_BOOL(result) = VARIANT_FALSE;
5271 int resT = 0; /* Testing has shown I2 & I2 == I2, all else
5272 becomes I4, even unsigned ints (incl. UI2) */
5275 switch (V_VT(left)&VT_TYPEMASK) {
5276 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
5277 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
5278 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5279 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5280 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
5281 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5282 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5283 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5284 default: lOk = FALSE;
5288 switch (V_VT(right)&VT_TYPEMASK) {
5289 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
5290 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
5291 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5292 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5293 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
5294 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5295 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5296 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5297 default: rOk = FALSE;
5301 res = (lVal | rVal);
5302 V_VT(result) = resT;
5304 case VT_I2 : V_UNION(result,iVal) = res; break;
5305 case VT_I4 : V_UNION(result,lVal) = res; break;
5307 FIXME("Unexpected result variant type %x\n", resT);
5308 V_UNION(result,lVal) = res;
5313 FIXME("unimplemented part\n");
5317 TRACE("rc=%d, Result:\n", (int) rc);
5318 dump_Variant(result);
5322 /**********************************************************************
5323 * VarNot [OLEAUT32.174]
5326 HRESULT WINAPI VarNot(LPVARIANT in, LPVARIANT result)
5328 HRESULT rc = E_FAIL;
5333 if ((V_VT(in)&VT_TYPEMASK) == VT_BOOL) {
5335 V_VT(result) = VT_BOOL;
5337 V_BOOL(result) = VARIANT_FALSE;
5339 V_BOOL(result) = VARIANT_TRUE;
5344 FIXME("VarNot stub\n");
5347 TRACE("rc=%d, Result:\n", (int) rc);
5348 dump_Variant(result);
5352 /**********************************************************************
5353 * VarTokenizeFormatString [OLEAUT32.140]
5355 * From investigation on W2K, a list is built up which is:
5357 * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
5358 * <token> - Insert appropriate token
5361 HRESULT WINAPI VarTokenizeFormatString(LPOLESTR format, LPBYTE rgbTok,
5362 int cbTok, int iFirstDay, int iFirstWeek,
5363 LCID lcid, int *pcbActual) {
5366 int realLen, formatLeft;
5368 LPSTR pFormatA, pStart;
5370 BOOL insertCopy = FALSE;
5371 LPSTR copyFrom = NULL;
5373 TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format), rgbTok, cbTok,
5374 iFirstDay, iFirstWeek);
5376 /* Big enough for header? */
5377 if (cbTok < sizeof(FORMATHDR)) {
5378 return TYPE_E_BUFFERTOOSMALL;
5382 hdr = (FORMATHDR *) rgbTok;
5383 memset(hdr, 0x00, sizeof(FORMATHDR));
5384 hdr->hex3 = 0x03; /* No idea what these are */
5387 /* Start parsing string */
5388 realLen = sizeof(FORMATHDR);
5389 pData = rgbTok + realLen;
5390 pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5392 formatLeft = strlen(pFormatA);
5394 /* Work through the format */
5395 while (*pFormatA != 0x00) {
5398 while (checkStr>=0 && (formatTokens[checkStr].tokenSize != 0x00)) {
5399 if (formatLeft >= formatTokens[checkStr].tokenSize &&
5400 strncmp(formatTokens[checkStr].str, pFormatA,
5401 formatTokens[checkStr].tokenSize) == 0) {
5402 TRACE("match on '%s'\n", formatTokens[checkStr].str);
5406 /* If we have skipped chars, insert the copy */
5407 if (insertCopy == TRUE) {
5409 if ((realLen + 3) > cbTok) {
5410 HeapFree( GetProcessHeap(), 0, pFormatA );
5411 return TYPE_E_BUFFERTOOSMALL;
5416 *pData = (BYTE)(copyFrom - pStart);
5418 *pData = (BYTE)(pFormatA - copyFrom);
5420 realLen = realLen + 3;
5424 /* Now insert the token itself */
5425 if ((realLen + 1) > cbTok) {
5426 HeapFree( GetProcessHeap(), 0, pFormatA );
5427 return TYPE_E_BUFFERTOOSMALL;
5429 *pData = formatTokens[checkStr].tokenId;
5431 realLen = realLen + 1;
5433 pFormatA = pFormatA + formatTokens[checkStr].tokenSize;
5434 formatLeft = formatLeft - formatTokens[checkStr].tokenSize;
5435 checkStr = -1; /* Flag as found and break out of while loop */
5441 /* Did we ever match a token? */
5442 if (checkStr != -1 && insertCopy == FALSE) {
5443 TRACE("No match - need to insert copy from %p [%p]\n", pFormatA, pStart);
5445 copyFrom = pFormatA;
5446 } else if (checkStr != -1) {
5447 pFormatA = pFormatA + 1;
5452 /* Finally, if we have skipped chars, insert the copy */
5453 if (insertCopy == TRUE) {
5455 TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom, pStart, pFormatA);
5456 if ((realLen + 3) > cbTok) {
5457 HeapFree( GetProcessHeap(), 0, pFormatA );
5458 return TYPE_E_BUFFERTOOSMALL;
5463 *pData = (BYTE)(copyFrom - pStart);
5465 *pData = (BYTE)(pFormatA - copyFrom);
5467 realLen = realLen + 3;
5470 /* Finally insert the terminator */
5471 if ((realLen + 1) > cbTok) {
5472 HeapFree( GetProcessHeap(), 0, pFormatA );
5473 return TYPE_E_BUFFERTOOSMALL;
5476 realLen = realLen + 1;
5478 /* Finally fill in the length */
5480 *pcbActual = realLen;
5484 for (i=0; i<realLen; i=i+0x10) {
5485 printf(" %4.4x : ", i);
5486 for (j=0; j<0x10 && (i+j < realLen); j++) {
5487 printf("%2.2x ", rgbTok[i+j]);
5493 HeapFree( GetProcessHeap(), 0, pFormatA );
5498 /**********************************************************************
5499 * VarFormatFromTokens [OLEAUT32.139]
5500 * FIXME: No account of flags or iFirstDay etc
5502 HRESULT WINAPI VarFormatFromTokens(LPVARIANT varIn, LPOLESTR format,
5503 LPBYTE pbTokCur, ULONG dwFlags, BSTR *pbstrOut,
5506 FORMATHDR *hdr = (FORMATHDR *)pbTokCur;
5507 BYTE *pData = pbTokCur + sizeof (FORMATHDR);
5508 LPSTR pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5509 char output[BUFFER_MAX];
5511 int size, whichToken;
5517 TRACE("'%s', %p %lx %p only date support\n", pFormatA, pbTokCur, dwFlags, pbstrOut);
5519 dump_Variant(varIn);
5521 memset(output, 0x00, BUFFER_MAX);
5524 while (*pData != TOK_END && ((pData - pbTokCur) <= (hdr->len))) {
5526 TRACE("Output looks like : '%s'\n", output);
5528 /* Convert varient to appropriate data type */
5530 while ((formatTokens[whichToken].tokenSize != 0x00) &&
5531 (formatTokens[whichToken].tokenId != *pData)) {
5535 /* Use Variant local from here downwards as always correct type */
5536 if (formatTokens[whichToken].tokenSize > 0 &&
5537 formatTokens[whichToken].varTypeRequired != 0) {
5538 VariantInit( &Variant );
5539 if (Coerce( &Variant, lcid, dwFlags, varIn,
5540 formatTokens[whichToken].varTypeRequired ) != S_OK) {
5541 HeapFree( GetProcessHeap(), 0, pFormatA );
5542 return DISP_E_TYPEMISMATCH;
5543 } else if (formatTokens[whichToken].varTypeRequired == VT_DATE) {
5544 if( DateToTm( V_UNION(&Variant,date), dwFlags, &TM ) == FALSE ) {
5545 HeapFree( GetProcessHeap(), 0, pFormatA );
5546 return E_INVALIDARG;
5551 TRACE("Looking for match on token '%x'\n", *pData);
5554 TRACE("Copy from %d for %d bytes\n", *(pData+1), *(pData+2));
5555 memcpy(pNextPos, &pFormatA[*(pData+1)], *(pData+2));
5556 pNextPos = pNextPos + *(pData+2);
5561 /* Get locale information - Time Seperator */
5562 size = GetLocaleInfoA(lcid, LOCALE_STIME, NULL, 0);
5563 GetLocaleInfoA(lcid, LOCALE_STIME, pNextPos, size);
5564 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5565 pNextPos = pNextPos + size;
5570 /* Get locale information - Date Seperator */
5571 size = GetLocaleInfoA(lcid, LOCALE_SDATE, NULL, 0);
5572 GetLocaleInfoA(lcid, LOCALE_SDATE, pNextPos, size);
5573 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5574 pNextPos = pNextPos + size;
5579 sprintf(pNextPos, "%d", TM.tm_mday);
5580 pNextPos = pNextPos + strlen(pNextPos);
5585 sprintf(pNextPos, "%2.2d", TM.tm_mday);
5586 pNextPos = pNextPos + strlen(pNextPos);
5591 sprintf(pNextPos, "%d", TM.tm_wday+1);
5592 pNextPos = pNextPos + strlen(pNextPos);
5597 sprintf(pNextPos, "%d", TM.tm_mon+1);
5598 pNextPos = pNextPos + strlen(pNextPos);
5603 sprintf(pNextPos, "%2.2d", TM.tm_mon+1);
5604 pNextPos = pNextPos + strlen(pNextPos);
5609 sprintf(pNextPos, "%d", ((TM.tm_mon+1)/4)+1);
5610 pNextPos = pNextPos + strlen(pNextPos);
5615 sprintf(pNextPos, "%2.2d", TM.tm_yday+1);
5616 pNextPos = pNextPos + strlen(pNextPos);
5621 sprintf(pNextPos, "%2.2d", TM.tm_year);
5622 pNextPos = pNextPos + strlen(pNextPos);
5627 sprintf(pNextPos, "%4.4d", TM.tm_year);
5628 pNextPos = pNextPos + strlen(pNextPos);
5633 sprintf(pNextPos, "%d", TM.tm_hour);
5634 pNextPos = pNextPos + strlen(pNextPos);
5639 sprintf(pNextPos, "%2.2d", TM.tm_hour);
5640 pNextPos = pNextPos + strlen(pNextPos);
5645 sprintf(pNextPos, "%d", TM.tm_min);
5646 pNextPos = pNextPos + strlen(pNextPos);
5651 sprintf(pNextPos, "%2.2d", TM.tm_min);
5652 pNextPos = pNextPos + strlen(pNextPos);
5657 sprintf(pNextPos, "%d", TM.tm_sec);
5658 pNextPos = pNextPos + strlen(pNextPos);
5663 sprintf(pNextPos, "%2.2d", TM.tm_sec);
5664 pNextPos = pNextPos + strlen(pNextPos);
5684 FIXME("Unhandled token for VarFormat %d\n", *pData);
5685 HeapFree( GetProcessHeap(), 0, pFormatA );
5686 return E_INVALIDARG;
5691 *pbstrOut = StringDupAtoBstr( output );
5692 HeapFree( GetProcessHeap(), 0, pFormatA );
5696 /**********************************************************************
5697 * VarFormat [OLEAUT32.87]
5700 HRESULT WINAPI VarFormat(LPVARIANT varIn, LPOLESTR format,
5701 int firstDay, int firstWeek, ULONG dwFlags,
5704 LPSTR pNewString = NULL;
5707 TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
5708 debugstr_w(format), firstDay, firstWeek, dwFlags);
5710 dump_Variant(varIn);
5712 /* Note: Must Handle references type Variants (contain ptrs
5713 to values rather than values */
5715 /* Get format string */
5716 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5718 /* FIXME: Handle some simple pre-definted format strings : */
5719 if (((V_VT(varIn)&VT_TYPEMASK) == VT_CY) && (lstrcmpiA(pNewString, "Currency") == 0)) {
5721 /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
5725 /* Handle references type Variants (contain ptrs to values rather than values */
5726 if (V_VT(varIn)&VT_BYREF) {
5727 rc = VarR8FromCy(*(CY *)V_UNION(varIn,byref), &curVal);
5729 rc = VarR8FromCy(V_UNION(varIn,cyVal), &curVal);
5733 char tmpStr[BUFFER_MAX];
5734 sprintf(tmpStr, "%f", curVal);
5735 if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags, tmpStr, NULL, pBuffer, BUFFER_MAX) == 0) {
5738 *pbstrOut = StringDupAtoBstr( pBuffer );
5742 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_DATE) {
5744 /* Attempt to do proper formatting! */
5745 int firstToken = -1;
5747 rc = VarTokenizeFormatString(format, pBuffer, sizeof(pBuffer), firstDay,
5748 firstWeek, GetUserDefaultLCID(), &firstToken);
5750 rc = VarFormatFromTokens(varIn, format, pBuffer, dwFlags, pbstrOut, GetUserDefaultLCID());
5753 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_R8) {
5754 if (V_VT(varIn)&VT_BYREF) {
5755 sprintf(pBuffer, "%f", *(double *)V_UNION(varIn,byref));
5757 sprintf(pBuffer, "%f", V_UNION(varIn,dblVal));
5760 *pbstrOut = StringDupAtoBstr( pBuffer );
5763 FIXME("VarFormat: Unsupported format %d!\n", V_VT(varIn)&VT_TYPEMASK);
5764 *pbstrOut = StringDupAtoBstr( "??" );
5767 /* Free allocated storage */
5768 HeapFree( GetProcessHeap(), 0, pNewString );
5769 TRACE("result: '%s'\n", debugstr_w(*pbstrOut));
5773 /**********************************************************************
5774 * VarCyMulI4 [OLEAUT32.304]
5775 * Multiply currency value by integer
5777 HRESULT WINAPI VarCyMulI4(CY cyIn, LONG mulBy, CY *pcyOut) {
5782 rc = VarR8FromCy(cyIn, &cyVal);
5784 rc = VarCyFromR8((cyVal * (double) mulBy), pcyOut);
5785 TRACE("Multiply %f by %ld = %f [%ld,%lu]\n", cyVal, mulBy, (cyVal * (double) mulBy),
5786 pcyOut->s.Hi, pcyOut->s.Lo);