4 * Copyright 1998 Jean-Claude Cote
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * This implements the low-level and hi-level APIs for manipulating VARIANTs.
22 * The low-level APIs are used to do data coercion between different data types.
23 * The hi-level APIs are built on top of these low-level APIs and handle
24 * initialization, copying, destroying and changing the type of VARIANTs.
27 * - The Variant APIs do not support international languages, currency
28 * types, number formating and calendar. They only support U.S. English format.
29 * - The Variant APIs do not the following types: IUknown, IDispatch, DECIMAL and SafeArray.
30 * The prototypes for these are commented out in the oleauto.h file. They need
31 * to be implemented and cases need to be added to the switches of the existing APIs.
32 * - The parsing of date for the VarDateFromStr is not complete.
33 * - The date manipulations do not support dates prior to 1900.
34 * - The parsing does not accept as many formats as the Windows implementation.
49 #define NONAMELESSUNION
50 #define NONAMELESSSTRUCT
54 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(ole);
61 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
65 # define FLT_MAX MAXFLOAT
67 # error "Can't find #define for MAXFLOAT/FLT_MAX"
73 static const char CHAR_MAX = 127;
74 static const char CHAR_MIN = -128;
75 static const BYTE UI1_MAX = 255;
76 static const BYTE UI1_MIN = 0;
77 static const unsigned short UI2_MAX = 65535;
78 static const unsigned short UI2_MIN = 0;
79 static const short I2_MAX = 32767;
80 static const short I2_MIN = -32768;
81 static const unsigned long UI4_MAX = 4294967295U;
82 static const unsigned long UI4_MIN = 0;
83 static const long I4_MAX = 2147483647;
84 static const long I4_MIN = -(2147483648U);
85 static const DATE DATE_MIN = -657434;
86 static const DATE DATE_MAX = 2958465;
88 /* the largest valid type
90 #define VT_MAXVALIDTYPE VT_CLSID
92 /* This mask is used to set a flag in wReserved1 of
93 * the VARIANTARG structure. The flag indicates if
94 * the API function is using an inner variant or not.
96 #define PROCESSING_INNER_VARIANT 0x0001
98 /* General use buffer.
100 #define BUFFER_MAX 1024
101 static char pBuffer[BUFFER_MAX];
104 * Note a leap year is one that is a multiple of 4
105 * but not of a 100. Except if it is a multiple of
106 * 400 then it is a leap year.
110 * Use 365 days/year and a manual calculation for leap year days
111 * to keep arithmetic simple
113 static const double DAYS_IN_ONE_YEAR = 365.0;
116 * Token definitions for Varient Formatting
117 * Worked out by experimentation on a w2k machine. Doesnt appear to be
118 * documented anywhere obviously so keeping definitions internally
121 /* Pre defined tokens */
122 #define TOK_COPY 0x00
124 #define LARGEST_TOKENID 6
126 /* Mapping of token name to id put into the tokenized form
127 Note testing on W2K shows aaaa and oooo are not parsed??!! */
128 #define TOK_COLON 0x03
129 #define TOK_SLASH 0x04
134 #define TOK_dddd 0x0b
135 #define TOK_ddddd 0x0c
136 #define TOK_dddddd 0x0d
142 #define TOK_mmmm 0x14
146 #define TOK_yyyy 0x18
153 #define TOK_ttttt 0x07
154 #define TOK_AMsPM 0x2f
155 #define TOK_amspm 0x32
158 #define TOK_AMPM 0x2e
160 typedef struct tagFORMATTOKEN {
167 typedef struct tagFORMATHDR {
174 FORMATTOKEN formatTokens[] = { /* FIXME: Only date formats so far */
175 {":" , 1, TOK_COLON , 0},
176 {"/" , 1, TOK_SLASH , 0},
177 {"c" , 1, TOK_c , VT_DATE},
178 {"dddddd", 6, TOK_dddddd , VT_DATE},
179 {"ddddd" , 5, TOK_ddddd , VT_DATE},
180 {"dddd" , 4, TOK_dddd , VT_DATE},
181 {"ddd" , 3, TOK_ddd , VT_DATE},
182 {"dd" , 2, TOK_dd , VT_DATE},
183 {"d" , 1, TOK_d , VT_DATE},
184 {"ww" , 2, TOK_ww , VT_DATE},
185 {"w" , 1, TOK_w , VT_DATE},
186 {"mmmm" , 4, TOK_mmmm , VT_DATE},
187 {"mmm" , 3, TOK_mmm , VT_DATE},
188 {"mm" , 2, TOK_mm , VT_DATE},
189 {"m" , 1, TOK_m , VT_DATE},
190 {"q" , 1, TOK_q , VT_DATE},
191 {"yyyy" , 4, TOK_yyyy , VT_DATE},
192 {"yy" , 2, TOK_yy , VT_DATE},
193 {"y" , 1, TOK_y , VT_DATE},
194 {"h" , 1, TOK_h , VT_DATE},
195 {"Hh" , 2, TOK_Hh , VT_DATE},
196 {"Nn" , 2, TOK_Nn , VT_DATE},
197 {"N" , 1, TOK_N , VT_DATE},
198 {"S" , 1, TOK_S , VT_DATE},
199 {"Ss" , 2, TOK_Ss , VT_DATE},
200 {"ttttt" , 5, TOK_ttttt , VT_DATE},
201 {"AM/PM" , 5, TOK_AMsPM , VT_DATE},
202 {"am/pm" , 5, TOK_amspm , VT_DATE},
203 {"A/P" , 3, TOK_AsP , VT_DATE},
204 {"a/p" , 3, TOK_asp , VT_DATE},
205 {"AMPM" , 4, TOK_AMPM , VT_DATE},
206 {0x00 , 0, 0 , VT_NULL}
209 /******************************************************************************
210 * DateTimeStringToTm [INTERNAL]
212 * Converts a string representation of a date and/or time to a tm structure.
214 * Note this function uses the postgresql date parsing functions found
215 * in the parsedt.c file.
217 * Returns TRUE if successful.
219 * Note: This function does not parse the day of the week,
220 * daylight savings time. It will only fill the followin fields in
221 * the tm struct, tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
223 ******************************************************************************/
224 static BOOL DateTimeStringToTm( OLECHAR* strIn, DWORD dwFlags, struct tm* pTm )
231 char *field[MAXDATEFIELDS];
232 int ftype[MAXDATEFIELDS];
233 char lowstr[MAXDATELEN + 1];
234 char* strDateTime = NULL;
236 /* Convert the string to ASCII since this is the only format
237 * postgesql can handle.
239 strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
241 if( strDateTime != NULL )
243 /* Make sure we don't go over the maximum length
244 * accepted by postgesql.
246 if( strlen( strDateTime ) <= MAXDATELEN )
248 if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
250 if( dwFlags & VAR_DATEVALUEONLY )
252 /* Get the date information.
253 * It returns 0 if date information was
254 * present and 1 if only time information was present.
255 * -1 if an error occures.
257 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
259 /* Eliminate the time information since we
260 * were asked to get date information only.
268 if( dwFlags & VAR_TIMEVALUEONLY )
270 /* Get time information only.
272 if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
279 /* Get both date and time information.
280 * It returns 0 if date information was
281 * present and 1 if only time information was present.
282 * -1 if an error occures.
284 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
291 HeapFree( GetProcessHeap(), 0, strDateTime );
302 /******************************************************************************
303 * TmToDATE [INTERNAL]
305 * The date is implemented using an 8 byte floating-point number.
306 * Days are represented by whole numbers increments starting with 0.00 has
307 * being December 30 1899, midnight.
308 * The hours are expressed as the fractional part of the number.
309 * December 30 1899 at midnight = 0.00
310 * January 1 1900 at midnight = 2.00
311 * January 4 1900 at 6 AM = 5.25
312 * January 4 1900 at noon = 5.50
313 * December 29 1899 at midnight = -1.00
314 * December 18 1899 at midnight = -12.00
315 * December 18 1899 at 6AM = -12.25
316 * December 18 1899 at 6PM = -12.75
317 * December 19 1899 at midnight = -11.00
318 * The tm structure is as follows:
320 * int tm_sec; seconds after the minute - [0,59]
321 * int tm_min; minutes after the hour - [0,59]
322 * int tm_hour; hours since midnight - [0,23]
323 * int tm_mday; day of the month - [1,31]
324 * int tm_mon; months since January - [0,11]
326 * int tm_wday; days since Sunday - [0,6]
327 * int tm_yday; days since January 1 - [0,365]
328 * int tm_isdst; daylight savings time flag
331 * Note: This function does not use the tm_wday, tm_yday, tm_wday,
332 * and tm_isdst fields of the tm structure. And only converts years
335 * Returns TRUE if successful.
337 static BOOL TmToDATE( struct tm* pTm, DATE *pDateOut )
341 /* Hmmm... An uninitialized Date in VB is December 30 1899 so
342 Start at 0. This is the way DATE is defined. */
344 /* Start at 1. This is the way DATE is defined.
345 * January 1, 1900 at Midnight is 1.00.
346 * January 1, 1900 at 6AM is 1.25.
351 if( (pTm->tm_year - 1900) >= 0 ) {
353 /* Add the number of days corresponding to
356 *pDateOut += (pTm->tm_year - 1900) * 365;
358 /* Add the leap days in the previous years between now and 1900.
359 * Note a leap year is one that is a multiple of 4
360 * but not of a 100. Except if it is a multiple of
361 * 400 then it is a leap year.
362 * Copied + reversed functionality into TmToDate
364 *pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
365 *pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
366 *pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
368 /* Set the leap year flag if the
369 * current year specified by tm_year is a
370 * leap year. This will be used to add a day
373 if( isleap( pTm->tm_year ) )
376 /* Add the number of days corresponding to
377 * the month. (remember tm_mon is 0..11)
379 switch( pTm->tm_mon )
385 *pDateOut += ( 59 + leapYear );
388 *pDateOut += ( 90 + leapYear );
391 *pDateOut += ( 120 + leapYear );
394 *pDateOut += ( 151 + leapYear );
397 *pDateOut += ( 181 + leapYear );
400 *pDateOut += ( 212 + leapYear );
403 *pDateOut += ( 243 + leapYear );
406 *pDateOut += ( 273 + leapYear );
409 *pDateOut += ( 304 + leapYear );
412 *pDateOut += ( 334 + leapYear );
415 /* Add the number of days in this month.
417 *pDateOut += pTm->tm_mday;
419 /* Add the number of seconds, minutes, and hours
420 * to the DATE. Note these are the fracionnal part
421 * of the DATE so seconds / number of seconds in a day.
427 *pDateOut += pTm->tm_hour / 24.0;
428 *pDateOut += pTm->tm_min / 1440.0;
429 *pDateOut += pTm->tm_sec / 86400.0;
433 /******************************************************************************
434 * DateToTm [INTERNAL]
436 * This function converts a windows DATE to a tm structure.
438 * It does not fill all the fields of the tm structure.
439 * Here is a list of the fields that are filled:
440 * tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
442 * Note this function does not support dates before the January 1, 1900
443 * or ( dateIn < 2.0 ).
445 * Returns TRUE if successful.
447 BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )
449 double decimalPart = 0.0;
450 double wholePart = 0.0;
452 memset(pTm,0,sizeof(*pTm));
454 /* Because of the nature of DATE format which
455 * associates 2.0 to January 1, 1900. We will
456 * remove 1.0 from the whole part of the DATE
457 * so that in the following code 1.0
458 * will correspond to January 1, 1900.
459 * This simplifies the processing of the DATE value.
461 decimalPart = fmod( dateIn, 1.0 ); /* Do this before the -1, otherwise 0.xx goes negative */
463 wholePart = (double) floor( dateIn );
465 if( !(dwFlags & VAR_TIMEVALUEONLY) )
467 unsigned int nDay = 0;
469 double yearsSince1900 = 0;
471 /* Hard code dates smaller than January 1, 1900. */
474 pTm->tm_mon = 11; /* December as tm_mon is 0..11 */
477 dateIn = dateIn * -1.0; /* Ensure +ve for time calculation */
478 decimalPart = decimalPart * -1.0; /* Ensure +ve for time calculation */
485 /* Start at 1900, this is where the DATE time 0.0 starts.
488 /* find in what year the day in the "wholePart" falls into.
489 * add the value to the year field.
491 yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 );
492 pTm->tm_year += yearsSince1900;
493 /* determine if this is a leap year.
495 if( isleap( pTm->tm_year ) )
501 /* find what day of that year the "wholePart" corresponds to.
502 * Note: nDay is in [1-366] format
504 nDay = (((unsigned int) wholePart) - ((pTm->tm_year-1900) * DAYS_IN_ONE_YEAR ));
506 /* Remove the leap days in the previous years between now and 1900.
507 * Note a leap year is one that is a multiple of 4
508 * but not of a 100. Except if it is a multiple of
509 * 400 then it is a leap year.
510 * Copied + reversed functionality from TmToDate
512 nDay -= ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
513 nDay += ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
514 nDay -= ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
516 /* Set the tm_yday value.
517 * Note: The day must be converted from [1-366] to [0-365]
519 /*pTm->tm_yday = nDay - 1;*/
520 /* find which month this day corresponds to.
527 else if( nDay <= ( 59 + leapYear ) )
529 pTm->tm_mday = nDay - 31;
532 else if( nDay <= ( 90 + leapYear ) )
534 pTm->tm_mday = nDay - ( 59 + leapYear );
537 else if( nDay <= ( 120 + leapYear ) )
539 pTm->tm_mday = nDay - ( 90 + leapYear );
542 else if( nDay <= ( 151 + leapYear ) )
544 pTm->tm_mday = nDay - ( 120 + leapYear );
547 else if( nDay <= ( 181 + leapYear ) )
549 pTm->tm_mday = nDay - ( 151 + leapYear );
552 else if( nDay <= ( 212 + leapYear ) )
554 pTm->tm_mday = nDay - ( 181 + leapYear );
557 else if( nDay <= ( 243 + leapYear ) )
559 pTm->tm_mday = nDay - ( 212 + leapYear );
562 else if( nDay <= ( 273 + leapYear ) )
564 pTm->tm_mday = nDay - ( 243 + leapYear );
567 else if( nDay <= ( 304 + leapYear ) )
569 pTm->tm_mday = nDay - ( 273 + leapYear );
572 else if( nDay <= ( 334 + leapYear ) )
574 pTm->tm_mday = nDay - ( 304 + leapYear );
577 else if( nDay <= ( 365 + leapYear ) )
579 pTm->tm_mday = nDay - ( 334 + leapYear );
584 if( !(dwFlags & VAR_DATEVALUEONLY) )
586 /* find the number of seconds in this day.
587 * fractional part times, hours, minutes, seconds.
588 * Note: 0.1 is hack to ensure figures come out in whole numbers
589 * due to floating point inaccuracies
591 pTm->tm_hour = (int) ( decimalPart * 24 );
592 pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
593 /* Note: 0.1 is hack to ensure seconds come out in whole numbers
594 due to floating point inaccuracies */
595 pTm->tm_sec = (int) (( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 ) + 0.1);
602 /******************************************************************************
603 * SizeOfVariantData [INTERNAL]
605 * This function finds the size of the data referenced by a Variant based
606 * the type "vt" of the Variant.
608 static int SizeOfVariantData( VARIANT* parg )
611 switch( V_VT(parg) & VT_TYPEMASK )
614 size = sizeof(short);
626 size = sizeof(unsigned short);
629 size = sizeof(unsigned int);
632 size = sizeof(unsigned long);
635 size = sizeof(float);
638 size = sizeof(double);
644 size = sizeof(VARIANT_BOOL);
649 size = sizeof(void*);
654 case( VT_DECIMAL ): /* hmm, tricky, DECIMAL is only VT_BYREF */
656 FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK );
662 /******************************************************************************
663 * StringDupAtoBstr [INTERNAL]
666 static BSTR StringDupAtoBstr( char* strIn )
669 OLECHAR* pNewString = NULL;
670 pNewString = HEAP_strdupAtoW( GetProcessHeap(), 0, strIn );
671 bstr = SysAllocString( pNewString );
672 HeapFree( GetProcessHeap(), 0, pNewString );
676 /******************************************************************************
679 * Round the double value to the nearest integer value.
681 static double round( double d )
683 double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
684 BOOL bEvenNumber = FALSE;
687 /* Save the sign of the number
689 nSign = (d >= 0.0) ? 1 : -1;
692 /* Remove the decimals.
694 integerValue = floor( d );
696 /* Set the Even flag. This is used to round the number when
697 * the decimals are exactly 1/2. If the integer part is
698 * odd the number is rounded up. If the integer part
699 * is even the number is rounded down. Using this method
700 * numbers are rounded up|down half the time.
702 bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
704 /* Remove the integral part of the number.
706 decimals = d - integerValue;
708 /* Note: Ceil returns the smallest integer that is greater that x.
709 * and floor returns the largest integer that is less than or equal to x.
713 /* If the decimal part is greater than 1/2
715 roundedValue = ceil( d );
717 else if( decimals < 0.5 )
719 /* If the decimal part is smaller than 1/2
721 roundedValue = floor( d );
725 /* the decimals are exactly 1/2 so round according to
726 * the bEvenNumber flag.
730 roundedValue = floor( d );
734 roundedValue = ceil( d );
738 return roundedValue * nSign;
741 /******************************************************************************
742 * RemoveCharacterFromString [INTERNAL]
744 * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
746 static void RemoveCharacterFromString( LPSTR str, LPSTR strOfCharToRemove )
748 LPSTR pNewString = NULL;
749 LPSTR strToken = NULL;
751 /* Check if we have a valid argument
755 pNewString = strdup( str );
757 strToken = strtok( pNewString, strOfCharToRemove );
758 while( strToken != NULL ) {
759 strcat( str, strToken );
760 strToken = strtok( NULL, strOfCharToRemove );
767 /******************************************************************************
768 * GetValidRealString [INTERNAL]
770 * Checks if the string is of proper format to be converted to a real value.
772 static BOOL IsValidRealString( LPSTR strRealString )
774 /* Real values that have a decimal point are required to either have
775 * digits before or after the decimal point. We will assume that
776 * we do not have any digits at either position. If we do encounter
777 * some we will disable this flag.
779 BOOL bDigitsRequired = TRUE;
780 /* Processed fields in the string representation of the real number.
782 BOOL bWhiteSpaceProcessed = FALSE;
783 BOOL bFirstSignProcessed = FALSE;
784 BOOL bFirstDigitsProcessed = FALSE;
785 BOOL bDecimalPointProcessed = FALSE;
786 BOOL bSecondDigitsProcessed = FALSE;
787 BOOL bExponentProcessed = FALSE;
788 BOOL bSecondSignProcessed = FALSE;
789 BOOL bThirdDigitsProcessed = FALSE;
790 /* Assume string parameter "strRealString" is valid and try to disprove it.
792 BOOL bValidRealString = TRUE;
794 /* Used to count the number of tokens in the "strRealString".
796 LPSTR strToken = NULL;
800 /* Check if we have a valid argument
802 if( strRealString == NULL )
804 bValidRealString = FALSE;
807 if( bValidRealString == TRUE )
809 /* Make sure we only have ONE token in the string.
811 strToken = strtok( strRealString, " " );
812 while( strToken != NULL ) {
814 strToken = strtok( NULL, " " );
819 bValidRealString = FALSE;
824 /* Make sure this token contains only valid characters.
825 * The string argument to atof has the following form:
826 * [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
827 * Whitespace consists of space and|or <TAB> characters, which are ignored.
828 * Sign is either plus '+' or minus '-'.
829 * Digits are one or more decimal digits.
830 * Note: If no digits appear before the decimal point, at least one must
831 * appear after the decimal point.
832 * The decimal digits may be followed by an exponent.
833 * An Exponent consists of an introductory letter ( D, d, E, or e) and
834 * an optionally signed decimal integer.
836 pChar = strRealString;
837 while( bValidRealString == TRUE && *pChar != '\0' )
845 if( bWhiteSpaceProcessed ||
846 bFirstSignProcessed ||
847 bFirstDigitsProcessed ||
848 bDecimalPointProcessed ||
849 bSecondDigitsProcessed ||
850 bExponentProcessed ||
851 bSecondSignProcessed ||
852 bThirdDigitsProcessed )
854 bValidRealString = FALSE;
861 if( bFirstSignProcessed == FALSE )
863 if( bFirstDigitsProcessed ||
864 bDecimalPointProcessed ||
865 bSecondDigitsProcessed ||
866 bExponentProcessed ||
867 bSecondSignProcessed ||
868 bThirdDigitsProcessed )
870 bValidRealString = FALSE;
872 bWhiteSpaceProcessed = TRUE;
873 bFirstSignProcessed = TRUE;
875 else if( bSecondSignProcessed == FALSE )
877 /* Note: The exponent must be present in
878 * order to accept the second sign...
880 if( bExponentProcessed == FALSE ||
881 bThirdDigitsProcessed ||
884 bValidRealString = FALSE;
886 bFirstSignProcessed = TRUE;
887 bWhiteSpaceProcessed = TRUE;
888 bFirstDigitsProcessed = TRUE;
889 bDecimalPointProcessed = TRUE;
890 bSecondDigitsProcessed = TRUE;
891 bSecondSignProcessed = TRUE;
907 if( bFirstDigitsProcessed == FALSE )
909 if( bDecimalPointProcessed ||
910 bSecondDigitsProcessed ||
911 bExponentProcessed ||
912 bSecondSignProcessed ||
913 bThirdDigitsProcessed )
915 bValidRealString = FALSE;
917 bFirstSignProcessed = TRUE;
918 bWhiteSpaceProcessed = TRUE;
919 /* We have found some digits before the decimal point
920 * so disable the "Digits required" flag.
922 bDigitsRequired = FALSE;
924 else if( bSecondDigitsProcessed == FALSE )
926 if( bExponentProcessed ||
927 bSecondSignProcessed ||
928 bThirdDigitsProcessed )
930 bValidRealString = FALSE;
932 bFirstSignProcessed = TRUE;
933 bWhiteSpaceProcessed = TRUE;
934 bFirstDigitsProcessed = TRUE;
935 bDecimalPointProcessed = TRUE;
936 /* We have found some digits after the decimal point
937 * so disable the "Digits required" flag.
939 bDigitsRequired = FALSE;
941 else if( bThirdDigitsProcessed == FALSE )
943 /* Getting here means everything else should be processed.
944 * If we get anything else than a decimal following this
945 * digit it will be flagged by the other cases, so
946 * we do not really need to do anything in here.
950 /* If DecimalPoint...
953 if( bDecimalPointProcessed ||
954 bSecondDigitsProcessed ||
955 bExponentProcessed ||
956 bSecondSignProcessed ||
957 bThirdDigitsProcessed )
959 bValidRealString = FALSE;
961 bFirstSignProcessed = TRUE;
962 bWhiteSpaceProcessed = TRUE;
963 bFirstDigitsProcessed = TRUE;
964 bDecimalPointProcessed = TRUE;
972 if( bExponentProcessed ||
973 bSecondSignProcessed ||
974 bThirdDigitsProcessed ||
977 bValidRealString = FALSE;
979 bFirstSignProcessed = TRUE;
980 bWhiteSpaceProcessed = TRUE;
981 bFirstDigitsProcessed = TRUE;
982 bDecimalPointProcessed = TRUE;
983 bSecondDigitsProcessed = TRUE;
984 bExponentProcessed = TRUE;
987 bValidRealString = FALSE;
990 /* Process next character.
995 /* If the required digits were not present we have an invalid
996 * string representation of a real number.
998 if( bDigitsRequired == TRUE )
1000 bValidRealString = FALSE;
1003 return bValidRealString;
1007 /******************************************************************************
1010 * This function dispatches execution to the proper conversion API
1011 * to do the necessary coercion.
1013 * FIXME: Passing down dwFlags to the conversion functions is wrong, this
1014 * is a different flagmask. Check MSDN.
1016 static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
1019 unsigned short vtFrom = 0;
1020 vtFrom = V_VT(ps) & VT_TYPEMASK;
1023 /* Note: Since "long" and "int" values both have 4 bytes and are
1024 * both signed integers "int" will be treated as "long" in the
1026 * The same goes for their unsigned versions.
1029 /* Trivial Case: If the coercion is from two types that are
1030 * identical then we can blindly copy from one argument to another.*/
1032 return VariantCopy(pd,ps);
1034 /* Cases requiring thought*/
1039 res = VariantClear( pd );
1042 res = VariantClear( pd );
1052 res = VarI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,cVal) );
1056 res = VarI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,cVal) );
1059 res = VarI1FromUI1( V_UNION(ps,bVal), &V_UNION(pd,cVal) );
1062 res = VarI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cVal) );
1066 res = VarI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cVal) );
1069 res = VarI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,cVal) );
1072 res = VarI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,cVal) );
1075 res = VarI1FromDate( V_UNION(ps,date), &V_UNION(pd,cVal) );
1078 res = VarI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,cVal) );
1081 res = VarI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cVal) );
1084 res = VarI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,cVal) );
1086 case( VT_DISPATCH ):
1087 /*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
1089 /*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
1092 res = DISP_E_TYPEMISMATCH;
1093 FIXME("Coercion from %d to VT_I1\n", vtFrom );
1102 res = VarI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,iVal) );
1106 res = VarI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,iVal) );
1109 res = VarI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,iVal) );
1112 res = VarI2FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,iVal) );
1116 res = VarI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,iVal) );
1119 res = VarI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,iVal) );
1122 res = VarI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,iVal) );
1125 res = VarI2FromDate( V_UNION(ps,date), &V_UNION(pd,iVal) );
1128 res = VarI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,iVal) );
1131 res = VarI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,iVal) );
1134 res = VarI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,iVal) );
1136 case( VT_DISPATCH ):
1137 /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
1139 /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
1142 res = DISP_E_TYPEMISMATCH;
1143 FIXME("Coercion from %d to VT_I2\n", vtFrom);
1153 V_UNION(pd,lVal) = 0;
1157 res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
1160 res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
1164 V_UNION(pd,lVal) = V_UNION(pd,scode);
1169 res = VariantCopy( pd, ps );
1172 res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
1175 res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
1179 res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
1182 res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
1185 res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
1188 res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
1191 res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
1194 res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
1197 res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
1199 case( VT_DISPATCH ):
1200 /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1202 /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1205 res = DISP_E_TYPEMISMATCH;
1206 FIXME("Coercion from %d to VT_INT/VT_I4\n", vtFrom);
1215 res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
1218 res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
1222 res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
1225 res = VariantCopy( pd, ps );
1228 res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
1232 res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
1235 res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
1238 res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
1241 res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
1244 res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
1247 res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
1250 res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
1252 case( VT_DISPATCH ):
1253 /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1255 /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1258 res = DISP_E_TYPEMISMATCH;
1259 FIXME("Coercion from %d to VT_UI1\n", vtFrom);
1268 res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
1271 res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
1275 res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
1278 res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
1281 res = VariantCopy( pd, ps );
1285 res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
1288 res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
1291 res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
1294 res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
1297 res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
1300 res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
1303 res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
1305 case( VT_DISPATCH ):
1306 /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1308 /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1311 res = DISP_E_TYPEMISMATCH;
1312 FIXME("Coercion from %d to VT_UI2\n", vtFrom);
1322 res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
1325 res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
1329 res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
1332 res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
1335 res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
1338 res = VariantCopy( pd, ps );
1341 res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
1344 res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
1347 res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
1350 res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
1353 res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
1356 res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
1358 case( VT_DISPATCH ):
1359 /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1361 /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1364 res = DISP_E_TYPEMISMATCH;
1365 FIXME("Coercion from %d to VT_UINT/VT_UI4\n", vtFrom);
1374 res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
1377 res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
1381 res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
1384 res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
1387 res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
1391 res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
1394 res = VariantCopy( pd, ps );
1397 res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
1400 res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
1403 res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
1406 res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
1409 res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
1412 V_UNION(pd,fltVal) = V_UNION(ps,scode);
1415 case( VT_DISPATCH ):
1416 /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1418 /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1421 res = DISP_E_TYPEMISMATCH;
1422 FIXME("Coercion from %d to VT_R4\n", vtFrom);
1431 res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
1434 res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
1438 res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
1441 res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
1444 res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
1448 res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
1451 res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
1454 res = VariantCopy( pd, ps );
1457 res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
1460 res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
1463 res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
1466 res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
1468 case( VT_DISPATCH ):
1469 /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1471 /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1474 res = DISP_E_TYPEMISMATCH;
1475 FIXME("Coercion from %d to VT_R8\n", vtFrom);
1484 res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
1487 res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
1490 res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
1493 res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
1496 res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
1499 res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
1502 res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
1505 res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
1508 res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
1511 res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
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 VT_DATE\n", vtFrom);
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 = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
1578 res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
1580 case( VT_DISPATCH ):
1581 /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1583 /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1586 res = DISP_E_TYPEMISMATCH;
1587 FIXME("Coercion from %d to VT_BOOL\n", vtFrom);
1596 if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
1599 res = E_OUTOFMEMORY;
1602 res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
1605 res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
1608 res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
1611 res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
1614 res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
1617 res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
1620 res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
1623 res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
1626 res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
1629 res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
1632 res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
1635 res = VarBstrFromBool( V_UNION(ps,boolVal), lcid, 0, &V_UNION(pd,bstrVal) );
1638 res = VariantCopy( pd, ps );
1641 res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
1643 case( VT_DISPATCH ):
1644 /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1646 /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1649 res = DISP_E_TYPEMISMATCH;
1650 FIXME("Coercion from %d to VT_BSTR\n", vtFrom);
1659 res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
1662 res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
1665 res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
1668 res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
1671 res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
1674 res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
1677 res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
1680 res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
1683 res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
1686 res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
1689 res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1692 res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1695 res = VariantCopy( pd, ps );
1698 res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
1700 case( VT_DISPATCH ):
1701 /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1703 /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1707 res = DISP_E_TYPEMISMATCH;
1708 FIXME("Coercion from %d to VT_CY\n", vtFrom);
1716 if (V_DISPATCH(ps) == NULL) {
1717 V_UNKNOWN(pd) = NULL;
1719 res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1722 case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4:
1723 case VT_R4: case VT_R8: case VT_CY: case VT_DATE:
1724 case VT_BSTR: case VT_ERROR: case VT_BOOL:
1725 case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1:
1726 case VT_UI2: case VT_UI4: case VT_I8: case VT_UI8: case VT_INT:
1727 case VT_UINT: case VT_VOID: case VT_HRESULT: case VT_PTR:
1728 case VT_SAFEARRAY: case VT_CARRAY: case VT_USERDEFINED:
1729 case VT_LPSTR: case VT_LPWSTR: case VT_RECORD: case VT_FILETIME:
1730 case VT_BLOB: case VT_STREAM: case VT_STORAGE:
1731 case VT_STREAMED_OBJECT: case VT_STORED_OBJECT: case VT_BLOB_OBJECT:
1732 case VT_CF: case VT_CLSID:
1733 res = DISP_E_TYPEMISMATCH;
1736 FIXME("Coercion from %d to VT_UNKNOWN unhandled.\n", vtFrom);
1737 res = DISP_E_BADVARTYPE;
1742 case( VT_DISPATCH ):
1745 if (V_UNION(ps,punkVal) == NULL) {
1746 V_UNION(pd,pdispVal) = NULL;
1748 res = IUnknown_QueryInterface(V_UNION(ps,punkVal), &IID_IDispatch, (LPVOID*)&V_UNION(pd,pdispVal));
1751 case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4:
1752 case VT_R4: case VT_R8: case VT_CY: case VT_DATE:
1753 case VT_BSTR: case VT_ERROR: case VT_BOOL:
1754 case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1:
1755 case VT_UI2: case VT_UI4: case VT_I8: case VT_UI8: case VT_INT:
1756 case VT_UINT: case VT_VOID: case VT_HRESULT: case VT_PTR:
1757 case VT_SAFEARRAY: case VT_CARRAY: case VT_USERDEFINED:
1758 case VT_LPSTR: case VT_LPWSTR: case VT_RECORD: case VT_FILETIME:
1759 case VT_BLOB: case VT_STREAM: case VT_STORAGE:
1760 case VT_STREAMED_OBJECT: case VT_STORED_OBJECT: case VT_BLOB_OBJECT:
1761 case VT_CF: case VT_CLSID:
1762 res = DISP_E_TYPEMISMATCH;
1765 FIXME("Coercion from %d to VT_DISPATCH unhandled.\n", vtFrom);
1766 res = DISP_E_BADVARTYPE;
1772 res = DISP_E_TYPEMISMATCH;
1773 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1780 /******************************************************************************
1781 * ValidateVtRange [INTERNAL]
1783 * Used internally by the hi-level Variant API to determine
1784 * if the vartypes are valid.
1786 static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
1788 /* if by value we must make sure it is in the
1789 * range of the valid types.
1791 if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1793 return DISP_E_BADVARTYPE;
1799 /******************************************************************************
1800 * ValidateVartype [INTERNAL]
1802 * Used internally by the hi-level Variant API to determine
1803 * if the vartypes are valid.
1805 static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
1809 /* check if we have a valid argument.
1813 /* if by reference check that the type is in
1814 * the valid range and that it is not of empty or null type
1816 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1817 ( vt & VT_TYPEMASK ) == VT_NULL ||
1818 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1820 res = DISP_E_BADVARTYPE;
1826 res = ValidateVtRange( vt );
1832 /******************************************************************************
1833 * ValidateVt [INTERNAL]
1835 * Used internally by the hi-level Variant API to determine
1836 * if the vartypes are valid.
1838 static HRESULT WINAPI ValidateVt( VARTYPE vt )
1842 /* check if we have a valid argument.
1846 /* if by reference check that the type is in
1847 * the valid range and that it is not of empty or null type
1849 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1850 ( vt & VT_TYPEMASK ) == VT_NULL ||
1851 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1853 res = DISP_E_BADVARTYPE;
1859 res = ValidateVtRange( vt );
1869 /******************************************************************************
1870 * VariantInit [OLEAUT32.8]
1872 * Initializes the Variant. Unlike VariantClear it does not interpret
1873 * the current contents of the Variant.
1875 void WINAPI VariantInit(VARIANTARG* pvarg)
1877 TRACE("(%p)\n",pvarg);
1879 memset(pvarg, 0, sizeof (VARIANTARG));
1880 V_VT(pvarg) = VT_EMPTY;
1885 /******************************************************************************
1886 * VariantClear [OLEAUT32.9]
1888 * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1889 * sets the wReservedX field to 0. The current contents of the VARIANT are
1890 * freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1891 * released. If VT_ARRAY the array is freed.
1893 HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
1896 TRACE("(%p)\n",pvarg);
1898 res = ValidateVariantType( V_VT(pvarg) );
1901 if( !( V_VT(pvarg) & VT_BYREF ) )
1904 * The VT_ARRAY flag is a special case of a safe array.
1906 if ( (V_VT(pvarg) & VT_ARRAY) != 0)
1908 SafeArrayDestroy(V_UNION(pvarg,parray));
1912 switch( V_VT(pvarg) & VT_TYPEMASK )
1915 SysFreeString( V_UNION(pvarg,bstrVal) );
1917 case( VT_DISPATCH ):
1918 if(V_UNION(pvarg,pdispVal)!=NULL)
1919 IDispatch_Release(V_UNION(pvarg,pdispVal));
1922 VariantClear(V_UNION(pvarg,pvarVal));
1925 if(V_UNION(pvarg,punkVal)!=NULL)
1926 IUnknown_Release(V_UNION(pvarg,punkVal));
1928 case( VT_SAFEARRAY ):
1929 SafeArrayDestroy(V_UNION(pvarg,parray));
1938 * Empty all the fields and mark the type as empty.
1940 memset(pvarg, 0, sizeof (VARIANTARG));
1941 V_VT(pvarg) = VT_EMPTY;
1947 /******************************************************************************
1948 * VariantCopy [OLEAUT32.10]
1950 * Frees up the designation variant and makes a copy of the source.
1952 HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
1956 TRACE("(%p, %p), vt=%d\n", pvargDest, pvargSrc, V_VT(pvargSrc));
1958 res = ValidateVariantType( V_VT(pvargSrc) );
1960 /* If the pointer are to the same variant we don't need
1963 if( pvargDest != pvargSrc && res == S_OK )
1965 VariantClear( pvargDest ); /* result is not checked */
1967 if( V_VT(pvargSrc) & VT_BYREF )
1969 /* In the case of byreference we only need
1970 * to copy the pointer.
1972 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1973 V_VT(pvargDest) = V_VT(pvargSrc);
1978 * The VT_ARRAY flag is another way to designate a safe array.
1980 if (V_VT(pvargSrc) & VT_ARRAY)
1982 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1986 /* In the case of by value we need to
1987 * copy the actual value. In the case of
1988 * VT_BSTR a copy of the string is made,
1989 * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1990 * called to increment the object's reference count.
1992 switch( V_VT(pvargSrc) & VT_TYPEMASK )
1995 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
1997 case( VT_DISPATCH ):
1998 V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
1999 if (V_UNION(pvargDest,pdispVal)!=NULL)
2000 IDispatch_AddRef(V_UNION(pvargDest,pdispVal));
2003 VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
2006 V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
2007 if (V_UNION(pvargDest,pdispVal)!=NULL)
2008 IUnknown_AddRef(V_UNION(pvargDest,punkVal));
2010 case( VT_SAFEARRAY ):
2011 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
2014 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
2018 V_VT(pvargDest) = V_VT(pvargSrc);
2019 dump_Variant(pvargDest);
2027 /******************************************************************************
2028 * VariantCopyInd [OLEAUT32.11]
2030 * Frees up the destination variant and makes a copy of the source. If
2031 * the source is of type VT_BYREF it performs the necessary indirections.
2033 HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
2037 TRACE("(%p, %p)\n", pvargDest, pvargSrc);
2039 res = ValidateVariantType( V_VT(pvargSrc) );
2044 if( V_VT(pvargSrc) & VT_BYREF )
2047 VariantInit( &varg );
2049 /* handle the in place copy.
2051 if( pvargDest == pvargSrc )
2053 /* we will use a copy of the source instead.
2055 res = VariantCopy( &varg, pvargSrc );
2061 res = VariantClear( pvargDest );
2066 * The VT_ARRAY flag is another way to designate a safearray variant.
2068 if ( V_VT(pvargSrc) & VT_ARRAY)
2070 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2074 /* In the case of by reference we need
2075 * to copy the date pointed to by the variant.
2078 /* Get the variant type.
2080 switch( V_VT(pvargSrc) & VT_TYPEMASK )
2083 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
2085 case( VT_DISPATCH ):
2086 V_UNION(pvargDest,pdispVal) = *V_UNION(pvargSrc,ppdispVal);
2087 if (V_UNION(pvargDest,pdispVal)!=NULL)
2088 IDispatch_AddRef(V_UNION(pvargDest,pdispVal));
2092 /* Prevent from cycling. According to tests on
2093 * VariantCopyInd in Windows and the documentation
2094 * this API dereferences the inner Variants to only one depth.
2095 * If the inner Variant itself contains an
2096 * other inner variant the E_INVALIDARG error is
2099 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
2101 /* If we get here we are attempting to deference
2102 * an inner variant that that is itself contained
2103 * in an inner variant so report E_INVALIDARG error.
2109 /* Set the processing inner variant flag.
2110 * We will set this flag in the inner variant
2111 * that will be passed to the VariantCopyInd function.
2113 (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
2115 /* Dereference the inner variant.
2117 res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
2118 /* We must also copy its type, I think.
2120 V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
2125 V_UNION(pvargDest,punkVal) = *V_UNION(pvargSrc,ppunkVal);
2126 if (V_UNION(pvargDest,pdispVal)!=NULL)
2127 IUnknown_AddRef(V_UNION(pvargDest,punkVal));
2129 case( VT_SAFEARRAY ):
2130 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2133 /* This is a by reference Variant which means that the union
2134 * part of the Variant contains a pointer to some data of
2135 * type "V_VT(pvargSrc) & VT_TYPEMASK".
2136 * We will deference this data in a generic fashion using
2137 * the void pointer "Variant.u.byref".
2138 * We will copy this data into the union of the destination
2141 memcpy( &pvargDest->n1.n2.n3, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
2146 if (res == S_OK) V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
2150 /* this should not fail.
2152 VariantClear( &varg );
2156 res = VariantCopy( pvargDest, pvargSrc );
2162 /******************************************************************************
2163 * Coerces a full safearray. Not optimal code.
2167 VARIANTARG* src, VARIANTARG *dst, LCID lcid, USHORT wFlags, VARTYPE vt
2169 SAFEARRAY *sarr = V_ARRAY(src);
2174 SafeArrayGetVartype(sarr,&vartype);
2177 if (sarr->cDims != 1) {
2178 FIXME("Can not coerce array with dim %d into BSTR\n", sarr->cDims);
2181 switch (V_VT(src) & VT_TYPEMASK) {
2183 hres = SafeArrayAccessData(sarr, &data);
2184 if (FAILED(hres)) return hres;
2186 /* Yes, just memcpied apparently. */
2187 V_BSTR(dst) = SysAllocStringByteLen(data, sarr->rgsabound[0].cElements);
2188 hres = SafeArrayUnaccessData(sarr);
2189 if (FAILED(hres)) return hres;
2192 FIXME("Cannot coerce array of %d into BSTR yet. Please report!\n", V_VT(src) & VT_TYPEMASK);
2197 V_VT(dst) = VT_SAFEARRAY;
2198 return SafeArrayCopy(sarr, &V_ARRAY(dst));
2200 FIXME("Cannot coerce array of vt 0x%x/0x%x into vt 0x%x yet. Please report/implement!\n", vartype, V_VT(src), vt);
2206 /******************************************************************************
2207 * VariantChangeType [OLEAUT32.12]
2209 HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2210 USHORT wFlags, VARTYPE vt)
2212 return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
2215 /******************************************************************************
2216 * VariantChangeTypeEx [OLEAUT32.147]
2218 HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2219 LCID lcid, USHORT wFlags, VARTYPE vt)
2223 VariantInit( &varg );
2225 TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
2226 TRACE("Src Var:\n");
2227 dump_Variant(pvargSrc);
2229 /* validate our source argument.
2231 res = ValidateVariantType( V_VT(pvargSrc) );
2233 /* validate the vartype.
2237 res = ValidateVt( vt );
2240 /* if we are doing an in-place conversion make a copy of the source.
2242 if( res == S_OK && pvargDest == pvargSrc )
2244 res = VariantCopy( &varg, pvargSrc );
2250 /* free up the destination variant.
2252 res = VariantClear( pvargDest );
2257 if( V_VT(pvargSrc) & VT_BYREF )
2259 /* Convert the source variant to a "byvalue" variant.
2263 if ((V_VT(pvargSrc) & 0xf000) != VT_BYREF) {
2264 FIXME("VT_TYPEMASK %x is unhandled.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2268 VariantInit( &Variant );
2269 res = VariantCopyInd( &Variant, pvargSrc );
2272 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2273 /* this should not fail.
2275 VariantClear( &Variant );
2278 if (V_VT(pvargSrc) & VT_ARRAY) {
2279 if ((V_VT(pvargSrc) & 0xf000) != VT_ARRAY) {
2280 FIXME("VT_TYPEMASK %x is unhandled in VT_ARRAY.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2283 V_VT(pvargDest) = VT_ARRAY | vt;
2284 res = coerce_array(pvargSrc, pvargDest, lcid, wFlags, vt);
2286 if ((V_VT(pvargSrc) & 0xf000)) {
2287 FIXME("VT_TYPEMASK %x is unhandled in normal case.\n",V_VT(pvargSrc) & VT_TYPEMASK);
2290 /* Use the current "byvalue" source variant.
2292 res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2296 /* this should not fail.
2298 VariantClear( &varg );
2300 /* set the type of the destination
2303 V_VT(pvargDest) = vt;
2305 TRACE("Dest Var:\n");
2306 dump_Variant(pvargDest);
2314 /******************************************************************************
2315 * VarUI1FromI2 [OLEAUT32.130]
2317 HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2319 TRACE("( %d, %p ), stub\n", sIn, pbOut );
2321 /* Check range of value.
2323 if( sIn < UI1_MIN || sIn > UI1_MAX )
2325 return DISP_E_OVERFLOW;
2328 *pbOut = (BYTE) sIn;
2333 /******************************************************************************
2334 * VarUI1FromI4 [OLEAUT32.131]
2336 HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2338 TRACE("( %ld, %p ), stub\n", lIn, pbOut );
2340 /* Check range of value.
2342 if( lIn < UI1_MIN || lIn > UI1_MAX )
2344 return DISP_E_OVERFLOW;
2347 *pbOut = (BYTE) lIn;
2353 /******************************************************************************
2354 * VarUI1FromR4 [OLEAUT32.132]
2356 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2358 TRACE("( %f, %p ), stub\n", fltIn, pbOut );
2360 /* Check range of value.
2362 fltIn = round( fltIn );
2363 if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2365 return DISP_E_OVERFLOW;
2368 *pbOut = (BYTE) fltIn;
2373 /******************************************************************************
2374 * VarUI1FromR8 [OLEAUT32.133]
2376 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2378 TRACE("( %f, %p ), stub\n", dblIn, pbOut );
2380 /* Check range of value.
2382 dblIn = round( dblIn );
2383 if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2385 return DISP_E_OVERFLOW;
2388 *pbOut = (BYTE) dblIn;
2393 /******************************************************************************
2394 * VarUI1FromDate [OLEAUT32.135]
2396 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2398 TRACE("( %f, %p ), stub\n", dateIn, pbOut );
2400 /* Check range of value.
2402 dateIn = round( dateIn );
2403 if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2405 return DISP_E_OVERFLOW;
2408 *pbOut = (BYTE) dateIn;
2413 /******************************************************************************
2414 * VarUI1FromBool [OLEAUT32.138]
2416 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2418 TRACE("( %d, %p ), stub\n", boolIn, pbOut );
2420 *pbOut = (BYTE) boolIn;
2425 /******************************************************************************
2426 * VarUI1FromI1 [OLEAUT32.237]
2428 HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
2430 TRACE("( %c, %p ), stub\n", cIn, pbOut );
2437 /******************************************************************************
2438 * VarUI1FromUI2 [OLEAUT32.238]
2440 HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2442 TRACE("( %d, %p ), stub\n", uiIn, pbOut );
2444 /* Check range of value.
2446 if( uiIn > UI1_MAX )
2448 return DISP_E_OVERFLOW;
2451 *pbOut = (BYTE) uiIn;
2456 /******************************************************************************
2457 * VarUI1FromUI4 [OLEAUT32.239]
2459 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2461 TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
2463 /* Check range of value.
2465 if( ulIn > UI1_MAX )
2467 return DISP_E_OVERFLOW;
2470 *pbOut = (BYTE) ulIn;
2476 /******************************************************************************
2477 * VarUI1FromStr [OLEAUT32.136]
2479 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2481 double dValue = 0.0;
2482 LPSTR pNewString = NULL;
2484 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
2486 /* Check if we have a valid argument
2488 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2489 RemoveCharacterFromString( pNewString, "," );
2490 if( IsValidRealString( pNewString ) == FALSE )
2492 return DISP_E_TYPEMISMATCH;
2495 /* Convert the valid string to a floating point number.
2497 dValue = atof( pNewString );
2499 /* We don't need the string anymore so free it.
2501 HeapFree( GetProcessHeap(), 0 , pNewString );
2503 /* Check range of value.
2505 dValue = round( dValue );
2506 if( dValue < UI1_MIN || dValue > UI1_MAX )
2508 return DISP_E_OVERFLOW;
2511 *pbOut = (BYTE) dValue;
2516 /**********************************************************************
2517 * VarUI1FromCy [OLEAUT32.134]
2518 * Convert currency to unsigned char
2520 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
2521 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2523 if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
2529 /******************************************************************************
2530 * VarI2FromUI1 [OLEAUT32.48]
2532 HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2534 TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
2536 *psOut = (short) bIn;
2541 /******************************************************************************
2542 * VarI2FromI4 [OLEAUT32.49]
2544 HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2546 TRACE("( %lx, %p ), stub\n", lIn, psOut );
2548 /* Check range of value.
2550 if( lIn < I2_MIN || lIn > I2_MAX )
2552 return DISP_E_OVERFLOW;
2555 *psOut = (short) lIn;
2560 /******************************************************************************
2561 * VarI2FromR4 [OLEAUT32.50]
2563 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2565 TRACE("( %f, %p ), stub\n", fltIn, psOut );
2567 /* Check range of value.
2569 fltIn = round( fltIn );
2570 if( fltIn < I2_MIN || fltIn > I2_MAX )
2572 return DISP_E_OVERFLOW;
2575 *psOut = (short) fltIn;
2580 /******************************************************************************
2581 * VarI2FromR8 [OLEAUT32.51]
2583 HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2585 TRACE("( %f, %p ), stub\n", dblIn, psOut );
2587 /* Check range of value.
2589 dblIn = round( dblIn );
2590 if( dblIn < I2_MIN || dblIn > I2_MAX )
2592 return DISP_E_OVERFLOW;
2595 *psOut = (short) dblIn;
2600 /******************************************************************************
2601 * VarI2FromDate [OLEAUT32.53]
2603 HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2605 TRACE("( %f, %p ), stub\n", dateIn, psOut );
2607 /* Check range of value.
2609 dateIn = round( dateIn );
2610 if( dateIn < I2_MIN || dateIn > I2_MAX )
2612 return DISP_E_OVERFLOW;
2615 *psOut = (short) dateIn;
2620 /******************************************************************************
2621 * VarI2FromBool [OLEAUT32.56]
2623 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2625 TRACE("( %d, %p ), stub\n", boolIn, psOut );
2627 *psOut = (short) boolIn;
2632 /******************************************************************************
2633 * VarI2FromI1 [OLEAUT32.205]
2635 HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
2637 TRACE("( %c, %p ), stub\n", cIn, psOut );
2639 *psOut = (short) cIn;
2644 /******************************************************************************
2645 * VarI2FromUI2 [OLEAUT32.206]
2647 HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2649 TRACE("( %d, %p ), stub\n", uiIn, psOut );
2651 /* Check range of value.
2655 return DISP_E_OVERFLOW;
2658 *psOut = (short) uiIn;
2663 /******************************************************************************
2664 * VarI2FromUI4 [OLEAUT32.207]
2666 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2668 TRACE("( %lx, %p ), stub\n", ulIn, psOut );
2670 /* Check range of value.
2672 if( ulIn < I2_MIN || ulIn > I2_MAX )
2674 return DISP_E_OVERFLOW;
2677 *psOut = (short) ulIn;
2682 /******************************************************************************
2683 * VarI2FromStr [OLEAUT32.54]
2685 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2687 double dValue = 0.0;
2688 LPSTR pNewString = NULL;
2690 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, psOut );
2692 /* Check if we have a valid argument
2694 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2695 RemoveCharacterFromString( pNewString, "," );
2696 if( IsValidRealString( pNewString ) == FALSE )
2698 return DISP_E_TYPEMISMATCH;
2701 /* Convert the valid string to a floating point number.
2703 dValue = atof( pNewString );
2705 /* We don't need the string anymore so free it.
2707 HeapFree( GetProcessHeap(), 0, pNewString );
2709 /* Check range of value.
2711 dValue = round( dValue );
2712 if( dValue < I2_MIN || dValue > I2_MAX )
2714 return DISP_E_OVERFLOW;
2717 *psOut = (short) dValue;
2722 /**********************************************************************
2723 * VarI2FromCy [OLEAUT32.52]
2724 * Convert currency to signed short
2726 HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
2727 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2729 if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
2735 /******************************************************************************
2736 * VarI4FromUI1 [OLEAUT32.58]
2738 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2740 TRACE("( %X, %p ), stub\n", bIn, plOut );
2742 *plOut = (LONG) bIn;
2748 /******************************************************************************
2749 * VarI4FromR4 [OLEAUT32.60]
2751 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2753 TRACE("( %f, %p ), stub\n", fltIn, plOut );
2755 /* Check range of value.
2757 fltIn = round( fltIn );
2758 if( fltIn < I4_MIN || fltIn > I4_MAX )
2760 return DISP_E_OVERFLOW;
2763 *plOut = (LONG) fltIn;
2768 /******************************************************************************
2769 * VarI4FromR8 [OLEAUT32.61]
2771 HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2773 TRACE("( %f, %p ), stub\n", dblIn, plOut );
2775 /* Check range of value.
2777 dblIn = round( dblIn );
2778 if( dblIn < I4_MIN || dblIn > I4_MAX )
2780 return DISP_E_OVERFLOW;
2783 *plOut = (LONG) dblIn;
2788 /******************************************************************************
2789 * VarI4FromDate [OLEAUT32.63]
2791 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2793 TRACE("( %f, %p ), stub\n", dateIn, plOut );
2795 /* Check range of value.
2797 dateIn = round( dateIn );
2798 if( dateIn < I4_MIN || dateIn > I4_MAX )
2800 return DISP_E_OVERFLOW;
2803 *plOut = (LONG) dateIn;
2808 /******************************************************************************
2809 * VarI4FromBool [OLEAUT32.66]
2811 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2813 TRACE("( %d, %p ), stub\n", boolIn, plOut );
2815 *plOut = (LONG) boolIn;
2820 /******************************************************************************
2821 * VarI4FromI1 [OLEAUT32.209]
2823 HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
2825 TRACE("( %c, %p ), stub\n", cIn, plOut );
2827 *plOut = (LONG) cIn;
2832 /******************************************************************************
2833 * VarI4FromUI2 [OLEAUT32.210]
2835 HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2837 TRACE("( %d, %p ), stub\n", uiIn, plOut );
2839 *plOut = (LONG) uiIn;
2844 /******************************************************************************
2845 * VarI4FromUI4 [OLEAUT32.211]
2847 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2849 TRACE("( %lx, %p ), stub\n", ulIn, plOut );
2851 /* Check range of value.
2853 if( ulIn < I4_MIN || ulIn > I4_MAX )
2855 return DISP_E_OVERFLOW;
2858 *plOut = (LONG) ulIn;
2863 /******************************************************************************
2864 * VarI4FromI2 [OLEAUT32.59]
2866 HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2868 TRACE("( %d, %p ), stub\n", sIn, plOut );
2870 *plOut = (LONG) sIn;
2875 /******************************************************************************
2876 * VarI4FromStr [OLEAUT32.64]
2878 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2880 double dValue = 0.0;
2881 LPSTR pNewString = NULL;
2883 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
2885 /* Check if we have a valid argument
2887 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2888 RemoveCharacterFromString( pNewString, "," );
2889 if( IsValidRealString( pNewString ) == FALSE )
2891 return DISP_E_TYPEMISMATCH;
2894 /* Convert the valid string to a floating point number.
2896 dValue = atof( pNewString );
2898 /* We don't need the string anymore so free it.
2900 HeapFree( GetProcessHeap(), 0, pNewString );
2902 /* Check range of value.
2904 dValue = round( dValue );
2905 if( dValue < I4_MIN || dValue > I4_MAX )
2907 return DISP_E_OVERFLOW;
2910 *plOut = (LONG) dValue;
2915 /**********************************************************************
2916 * VarI4FromCy [OLEAUT32.62]
2917 * Convert currency to signed long
2919 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
2920 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2922 if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
2928 /******************************************************************************
2929 * VarR4FromUI1 [OLEAUT32.68]
2931 HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
2933 TRACE("( %X, %p ), stub\n", bIn, pfltOut );
2935 *pfltOut = (FLOAT) bIn;
2940 /******************************************************************************
2941 * VarR4FromI2 [OLEAUT32.69]
2943 HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
2945 TRACE("( %d, %p ), stub\n", sIn, pfltOut );
2947 *pfltOut = (FLOAT) sIn;
2952 /******************************************************************************
2953 * VarR4FromI4 [OLEAUT32.70]
2955 HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
2957 TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
2959 *pfltOut = (FLOAT) lIn;
2964 /******************************************************************************
2965 * VarR4FromR8 [OLEAUT32.71]
2967 HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
2969 TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
2971 /* Check range of value.
2973 if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
2975 return DISP_E_OVERFLOW;
2978 *pfltOut = (FLOAT) dblIn;
2983 /******************************************************************************
2984 * VarR4FromDate [OLEAUT32.73]
2986 HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
2988 TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
2990 /* Check range of value.
2992 if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
2994 return DISP_E_OVERFLOW;
2997 *pfltOut = (FLOAT) dateIn;
3002 /******************************************************************************
3003 * VarR4FromBool [OLEAUT32.76]
3005 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
3007 TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
3009 *pfltOut = (FLOAT) boolIn;
3014 /******************************************************************************
3015 * VarR4FromI1 [OLEAUT32.213]
3017 HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
3019 TRACE("( %c, %p ), stub\n", cIn, pfltOut );
3021 *pfltOut = (FLOAT) cIn;
3026 /******************************************************************************
3027 * VarR4FromUI2 [OLEAUT32.214]
3029 HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
3031 TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
3033 *pfltOut = (FLOAT) uiIn;
3038 /******************************************************************************
3039 * VarR4FromUI4 [OLEAUT32.215]
3041 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
3043 TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
3045 *pfltOut = (FLOAT) ulIn;
3050 /******************************************************************************
3051 * VarR4FromStr [OLEAUT32.74]
3053 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
3055 double dValue = 0.0;
3056 LPSTR pNewString = NULL;
3058 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
3060 /* Check if we have a valid argument
3062 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3063 RemoveCharacterFromString( pNewString, "," );
3064 if( IsValidRealString( pNewString ) == FALSE )
3066 return DISP_E_TYPEMISMATCH;
3069 /* Convert the valid string to a floating point number.
3071 dValue = atof( pNewString );
3073 /* We don't need the string anymore so free it.
3075 HeapFree( GetProcessHeap(), 0, pNewString );
3077 /* Check range of value.
3079 if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
3081 return DISP_E_OVERFLOW;
3084 *pfltOut = (FLOAT) dValue;
3089 /**********************************************************************
3090 * VarR4FromCy [OLEAUT32.72]
3091 * Convert currency to float
3093 HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
3094 *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3099 /******************************************************************************
3100 * VarR8FromUI1 [OLEAUT32.78]
3102 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
3104 TRACE("( %d, %p ), stub\n", bIn, pdblOut );
3106 *pdblOut = (double) bIn;
3111 /******************************************************************************
3112 * VarR8FromI2 [OLEAUT32.79]
3114 HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
3116 TRACE("( %d, %p ), stub\n", sIn, pdblOut );
3118 *pdblOut = (double) sIn;
3123 /******************************************************************************
3124 * VarR8FromI4 [OLEAUT32.80]
3126 HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
3128 TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
3130 *pdblOut = (double) lIn;
3135 /******************************************************************************
3136 * VarR8FromR4 [OLEAUT32.81]
3138 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
3140 TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
3142 *pdblOut = (double) fltIn;
3147 /******************************************************************************
3148 * VarR8FromDate [OLEAUT32.83]
3150 HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
3152 TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
3154 *pdblOut = (double) dateIn;
3159 /******************************************************************************
3160 * VarR8FromBool [OLEAUT32.86]
3162 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
3164 TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
3166 *pdblOut = (double) boolIn;
3171 /******************************************************************************
3172 * VarR8FromI1 [OLEAUT32.217]
3174 HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
3176 TRACE("( %c, %p ), stub\n", cIn, pdblOut );
3178 *pdblOut = (double) cIn;
3183 /******************************************************************************
3184 * VarR8FromUI2 [OLEAUT32.218]
3186 HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
3188 TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
3190 *pdblOut = (double) uiIn;
3195 /******************************************************************************
3196 * VarR8FromUI4 [OLEAUT32.219]
3198 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
3200 TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
3202 *pdblOut = (double) ulIn;
3207 /******************************************************************************
3208 * VarR8FromStr [OLEAUT32.84]
3210 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
3212 double dValue = 0.0;
3213 LPSTR pNewString = NULL;
3215 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3216 TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString, lcid, dwFlags, pdblOut );
3218 /* Check if we have a valid argument
3220 RemoveCharacterFromString( pNewString, "," );
3221 if( IsValidRealString( pNewString ) == FALSE )
3223 return DISP_E_TYPEMISMATCH;
3226 /* Convert the valid string to a floating point number.
3228 dValue = atof( pNewString );
3230 /* We don't need the string anymore so free it.
3232 HeapFree( GetProcessHeap(), 0, pNewString );
3239 /**********************************************************************
3240 * VarR8FromCy [OLEAUT32.82]
3241 * Convert currency to double
3243 HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
3244 *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3245 TRACE("%lu %ld -> %f\n", cyIn.s.Hi, cyIn.s.Lo, *pdblOut);
3249 /******************************************************************************
3250 * VarDateFromUI1 [OLEAUT32.88]
3252 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
3254 TRACE("( %d, %p ), stub\n", bIn, pdateOut );
3256 *pdateOut = (DATE) bIn;
3261 /******************************************************************************
3262 * VarDateFromI2 [OLEAUT32.89]
3264 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
3266 TRACE("( %d, %p ), stub\n", sIn, pdateOut );
3268 *pdateOut = (DATE) sIn;
3273 /******************************************************************************
3274 * VarDateFromI4 [OLEAUT32.90]
3276 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3278 TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
3280 if( lIn < DATE_MIN || lIn > DATE_MAX )
3282 return DISP_E_OVERFLOW;
3285 *pdateOut = (DATE) lIn;
3290 /******************************************************************************
3291 * VarDateFromR4 [OLEAUT32.91]
3293 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3295 TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3297 if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
3299 return DISP_E_OVERFLOW;
3302 *pdateOut = (DATE) fltIn;
3307 /******************************************************************************
3308 * VarDateFromR8 [OLEAUT32.92]
3310 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3312 TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3314 if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3316 return DISP_E_OVERFLOW;
3319 *pdateOut = (DATE) dblIn;
3324 /******************************************************************************
3325 * VarDateFromStr [OLEAUT32.94]
3326 * The string representing the date is composed of two parts, a date and time.
3328 * The format of the time is has follows:
3329 * hh[:mm][:ss][AM|PM]
3330 * Whitespace can be inserted anywhere between these tokens. A whitespace consists
3331 * of space and/or tab characters, which are ignored.
3333 * The formats for the date part are has follows:
3337 * January dd[,] [yy]yy
3340 * Whitespace can be inserted anywhere between these tokens.
3342 * The formats for the date and time string are has follows.
3343 * date[whitespace][time]
3344 * [time][whitespace]date
3346 * These are the only characters allowed in a string representing a date and time:
3347 * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3349 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3354 memset( &TM, 0, sizeof(TM) );
3356 TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3358 if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
3360 if( TmToDATE( &TM, pdateOut ) == FALSE )
3367 ret = DISP_E_TYPEMISMATCH;
3369 TRACE("Return value %f\n", *pdateOut);
3373 /******************************************************************************
3374 * VarDateFromI1 [OLEAUT32.221]
3376 HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
3378 TRACE("( %c, %p ), stub\n", cIn, pdateOut );
3380 *pdateOut = (DATE) cIn;
3385 /******************************************************************************
3386 * VarDateFromUI2 [OLEAUT32.222]
3388 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3390 TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
3392 if( uiIn > DATE_MAX )
3394 return DISP_E_OVERFLOW;
3397 *pdateOut = (DATE) uiIn;
3402 /******************************************************************************
3403 * VarDateFromUI4 [OLEAUT32.223]
3405 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3407 TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
3409 if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3411 return DISP_E_OVERFLOW;
3414 *pdateOut = (DATE) ulIn;
3419 /******************************************************************************
3420 * VarDateFromBool [OLEAUT32.96]
3422 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3424 TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
3426 *pdateOut = (DATE) boolIn;
3431 /**********************************************************************
3432 * VarDateFromCy [OLEAUT32.93]
3433 * Convert currency to date
3435 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
3436 *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3438 if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3442 /******************************************************************************
3443 * VarBstrFromUI1 [OLEAUT32.108]
3445 HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3447 TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3448 sprintf( pBuffer, "%d", bVal );
3450 *pbstrOut = StringDupAtoBstr( pBuffer );
3455 /******************************************************************************
3456 * VarBstrFromI2 [OLEAUT32.109]
3458 HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3460 TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3461 sprintf( pBuffer, "%d", iVal );
3462 *pbstrOut = StringDupAtoBstr( pBuffer );
3467 /******************************************************************************
3468 * VarBstrFromI4 [OLEAUT32.110]
3470 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3472 TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
3474 sprintf( pBuffer, "%ld", lIn );
3475 *pbstrOut = StringDupAtoBstr( pBuffer );
3480 /******************************************************************************
3481 * VarBstrFromR4 [OLEAUT32.111]
3483 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3485 TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
3487 sprintf( pBuffer, "%.7G", fltIn );
3488 *pbstrOut = StringDupAtoBstr( pBuffer );
3493 /******************************************************************************
3494 * VarBstrFromR8 [OLEAUT32.112]
3496 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3498 TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
3500 sprintf( pBuffer, "%.15G", dblIn );
3501 *pbstrOut = StringDupAtoBstr( pBuffer );
3506 /******************************************************************************
3507 * VarBstrFromCy [OLEAUT32.113]
3509 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
3511 double curVal = 0.0;
3513 TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid, dwFlags, pbstrOut);
3515 /* Firstly get the currency in a double, then put it in a buffer */
3516 rc = VarR8FromCy(cyIn, &curVal);
3518 sprintf(pBuffer, "%G", curVal);
3519 *pbstrOut = StringDupAtoBstr( pBuffer );
3525 /******************************************************************************
3526 * VarBstrFromDate [OLEAUT32.114]
3528 * The date is implemented using an 8 byte floating-point number.
3529 * Days are represented by whole numbers increments starting with 0.00 as
3530 * being December 30 1899, midnight.
3531 * The hours are expressed as the fractional part of the number.
3532 * December 30 1899 at midnight = 0.00
3533 * January 1 1900 at midnight = 2.00
3534 * January 4 1900 at 6 AM = 5.25
3535 * January 4 1900 at noon = 5.50
3536 * December 29 1899 at midnight = -1.00
3537 * December 18 1899 at midnight = -12.00
3538 * December 18 1899 at 6AM = -12.25
3539 * December 18 1899 at 6PM = -12.75
3540 * December 19 1899 at midnight = -11.00
3541 * The tm structure is as follows:
3543 * int tm_sec; seconds after the minute - [0,59]
3544 * int tm_min; minutes after the hour - [0,59]
3545 * int tm_hour; hours since midnight - [0,23]
3546 * int tm_mday; day of the month - [1,31]
3547 * int tm_mon; months since January - [0,11]
3548 * int tm_year; years
3549 * int tm_wday; days since Sunday - [0,6]
3550 * int tm_yday; days since January 1 - [0,365]
3551 * int tm_isdst; daylight savings time flag
3554 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3557 memset( &TM, 0, sizeof(TM) );
3559 TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
3561 if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
3563 return E_INVALIDARG;
3566 if( dwFlags & VAR_DATEVALUEONLY )
3567 strftime( pBuffer, BUFFER_MAX, "%x", &TM );
3568 else if( dwFlags & VAR_TIMEVALUEONLY )
3569 strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3571 strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3573 TRACE("result: %s\n", pBuffer);
3574 *pbstrOut = StringDupAtoBstr( pBuffer );
3578 /******************************************************************************
3579 * VarBstrFromBool [OLEAUT32.116]
3581 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3583 TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
3585 sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
3587 *pbstrOut = StringDupAtoBstr( pBuffer );
3592 /******************************************************************************
3593 * VarBstrFromI1 [OLEAUT32.229]
3595 HRESULT WINAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3597 TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3598 sprintf( pBuffer, "%d", cIn );
3599 *pbstrOut = StringDupAtoBstr( pBuffer );
3604 /******************************************************************************
3605 * VarBstrFromUI2 [OLEAUT32.230]
3607 HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3609 TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3610 sprintf( pBuffer, "%d", uiIn );
3611 *pbstrOut = StringDupAtoBstr( pBuffer );
3616 /******************************************************************************
3617 * VarBstrFromUI4 [OLEAUT32.231]
3619 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3621 TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3622 sprintf( pBuffer, "%ld", ulIn );
3623 *pbstrOut = StringDupAtoBstr( pBuffer );
3628 /******************************************************************************
3629 * VarBoolFromUI1 [OLEAUT32.118]
3631 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3633 TRACE("( %d, %p ), stub\n", bIn, pboolOut );
3637 *pboolOut = VARIANT_FALSE;
3641 *pboolOut = VARIANT_TRUE;
3647 /******************************************************************************
3648 * VarBoolFromI2 [OLEAUT32.119]
3650 HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3652 TRACE("( %d, %p ), stub\n", sIn, pboolOut );
3654 *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
3659 /******************************************************************************
3660 * VarBoolFromI4 [OLEAUT32.120]
3662 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3664 TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
3666 *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
3671 /******************************************************************************
3672 * VarBoolFromR4 [OLEAUT32.121]
3674 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3676 TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
3678 *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3683 /******************************************************************************
3684 * VarBoolFromR8 [OLEAUT32.122]
3686 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3688 TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
3690 *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3695 /******************************************************************************
3696 * VarBoolFromDate [OLEAUT32.123]
3698 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3700 TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
3702 *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3707 /******************************************************************************
3708 * VarBoolFromStr [OLEAUT32.125]
3710 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3713 char* pNewString = NULL;
3715 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
3717 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3719 if( pNewString == NULL || strlen( pNewString ) == 0 )
3721 ret = DISP_E_TYPEMISMATCH;
3726 if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
3728 *pboolOut = VARIANT_TRUE;
3730 else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
3732 *pboolOut = VARIANT_FALSE;
3736 /* Try converting the string to a floating point number.
3738 double dValue = 0.0;
3739 HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3742 ret = DISP_E_TYPEMISMATCH;
3745 *pboolOut = (dValue == 0.0) ?
3746 VARIANT_FALSE : VARIANT_TRUE;
3750 HeapFree( GetProcessHeap(), 0, pNewString );
3755 /******************************************************************************
3756 * VarBoolFromI1 [OLEAUT32.233]
3758 HRESULT WINAPI VarBoolFromI1(CHAR cIn, VARIANT_BOOL* pboolOut)
3760 TRACE("( %c, %p ), stub\n", cIn, pboolOut );
3762 *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3767 /******************************************************************************
3768 * VarBoolFromUI2 [OLEAUT32.234]
3770 HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3772 TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
3774 *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3779 /******************************************************************************
3780 * VarBoolFromUI4 [OLEAUT32.235]
3782 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3784 TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
3786 *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3791 /**********************************************************************
3792 * VarBoolFromCy [OLEAUT32.124]
3793 * Convert currency to boolean
3795 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
3796 if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
3802 /******************************************************************************
3803 * VarI1FromUI1 [OLEAUT32.244]
3805 HRESULT WINAPI VarI1FromUI1(BYTE bIn, CHAR* pcOut)
3807 TRACE("( %d, %p ), stub\n", bIn, pcOut );
3809 /* Check range of value.
3811 if( bIn > CHAR_MAX )
3813 return DISP_E_OVERFLOW;
3816 *pcOut = (CHAR) bIn;
3821 /******************************************************************************
3822 * VarI1FromI2 [OLEAUT32.245]
3824 HRESULT WINAPI VarI1FromI2(short uiIn, CHAR* pcOut)
3826 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3828 if( uiIn > CHAR_MAX )
3830 return DISP_E_OVERFLOW;
3833 *pcOut = (CHAR) uiIn;
3838 /******************************************************************************
3839 * VarI1FromI4 [OLEAUT32.246]
3841 HRESULT WINAPI VarI1FromI4(LONG lIn, CHAR* pcOut)
3843 TRACE("( %ld, %p ), stub\n", lIn, pcOut );
3845 if( lIn < CHAR_MIN || lIn > CHAR_MAX )
3847 return DISP_E_OVERFLOW;
3850 *pcOut = (CHAR) lIn;
3855 /******************************************************************************
3856 * VarI1FromR4 [OLEAUT32.247]
3858 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, CHAR* pcOut)
3860 TRACE("( %f, %p ), stub\n", fltIn, pcOut );
3862 fltIn = round( fltIn );
3863 if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
3865 return DISP_E_OVERFLOW;
3868 *pcOut = (CHAR) fltIn;
3873 /******************************************************************************
3874 * VarI1FromR8 [OLEAUT32.248]
3876 HRESULT WINAPI VarI1FromR8(double dblIn, CHAR* pcOut)
3878 TRACE("( %f, %p ), stub\n", dblIn, pcOut );
3880 dblIn = round( dblIn );
3881 if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
3883 return DISP_E_OVERFLOW;
3886 *pcOut = (CHAR) dblIn;
3891 /******************************************************************************
3892 * VarI1FromDate [OLEAUT32.249]
3894 HRESULT WINAPI VarI1FromDate(DATE dateIn, CHAR* pcOut)
3896 TRACE("( %f, %p ), stub\n", dateIn, pcOut );
3898 dateIn = round( dateIn );
3899 if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
3901 return DISP_E_OVERFLOW;
3904 *pcOut = (CHAR) dateIn;
3909 /******************************************************************************
3910 * VarI1FromStr [OLEAUT32.251]
3912 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CHAR* pcOut)
3914 double dValue = 0.0;
3915 LPSTR pNewString = NULL;
3917 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
3919 /* Check if we have a valid argument
3921 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3922 RemoveCharacterFromString( pNewString, "," );
3923 if( IsValidRealString( pNewString ) == FALSE )
3925 return DISP_E_TYPEMISMATCH;
3928 /* Convert the valid string to a floating point number.
3930 dValue = atof( pNewString );
3932 /* We don't need the string anymore so free it.
3934 HeapFree( GetProcessHeap(), 0, pNewString );
3936 /* Check range of value.
3938 dValue = round( dValue );
3939 if( dValue < CHAR_MIN || dValue > CHAR_MAX )
3941 return DISP_E_OVERFLOW;
3944 *pcOut = (CHAR) dValue;
3949 /******************************************************************************
3950 * VarI1FromBool [OLEAUT32.253]
3952 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
3954 TRACE("( %d, %p ), stub\n", boolIn, pcOut );
3956 *pcOut = (CHAR) boolIn;
3961 /******************************************************************************
3962 * VarI1FromUI2 [OLEAUT32.254]
3964 HRESULT WINAPI VarI1FromUI2(USHORT uiIn, CHAR* pcOut)
3966 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3968 if( uiIn > CHAR_MAX )
3970 return DISP_E_OVERFLOW;
3973 *pcOut = (CHAR) uiIn;
3978 /******************************************************************************
3979 * VarI1FromUI4 [OLEAUT32.255]
3981 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, CHAR* pcOut)
3983 TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
3985 if( ulIn > CHAR_MAX )
3987 return DISP_E_OVERFLOW;
3990 *pcOut = (CHAR) ulIn;
3995 /**********************************************************************
3996 * VarI1FromCy [OLEAUT32.250]
3997 * Convert currency to signed char
3999 HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
4000 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4002 if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
4008 /******************************************************************************
4009 * VarUI2FromUI1 [OLEAUT32.257]
4011 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
4013 TRACE("( %d, %p ), stub\n", bIn, puiOut );
4015 *puiOut = (USHORT) bIn;
4020 /******************************************************************************
4021 * VarUI2FromI2 [OLEAUT32.258]
4023 HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
4025 TRACE("( %d, %p ), stub\n", uiIn, puiOut );
4027 if( uiIn < UI2_MIN )
4029 return DISP_E_OVERFLOW;
4032 *puiOut = (USHORT) uiIn;
4037 /******************************************************************************
4038 * VarUI2FromI4 [OLEAUT32.259]
4040 HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
4042 TRACE("( %ld, %p ), stub\n", lIn, puiOut );
4044 if( lIn < UI2_MIN || lIn > UI2_MAX )
4046 return DISP_E_OVERFLOW;
4049 *puiOut = (USHORT) lIn;
4054 /******************************************************************************
4055 * VarUI2FromR4 [OLEAUT32.260]
4057 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
4059 TRACE("( %f, %p ), stub\n", fltIn, puiOut );
4061 fltIn = round( fltIn );
4062 if( fltIn < UI2_MIN || fltIn > UI2_MAX )
4064 return DISP_E_OVERFLOW;
4067 *puiOut = (USHORT) fltIn;
4072 /******************************************************************************
4073 * VarUI2FromR8 [OLEAUT32.261]
4075 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
4077 TRACE("( %f, %p ), stub\n", dblIn, puiOut );
4079 dblIn = round( dblIn );
4080 if( dblIn < UI2_MIN || dblIn > UI2_MAX )
4082 return DISP_E_OVERFLOW;
4085 *puiOut = (USHORT) dblIn;
4090 /******************************************************************************
4091 * VarUI2FromDate [OLEAUT32.262]
4093 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
4095 TRACE("( %f, %p ), stub\n", dateIn, puiOut );
4097 dateIn = round( dateIn );
4098 if( dateIn < UI2_MIN || dateIn > UI2_MAX )
4100 return DISP_E_OVERFLOW;
4103 *puiOut = (USHORT) dateIn;
4108 /******************************************************************************
4109 * VarUI2FromStr [OLEAUT32.264]
4111 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
4113 double dValue = 0.0;
4114 LPSTR pNewString = NULL;
4116 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
4118 /* Check if we have a valid argument
4120 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4121 RemoveCharacterFromString( pNewString, "," );
4122 if( IsValidRealString( pNewString ) == FALSE )
4124 return DISP_E_TYPEMISMATCH;
4127 /* Convert the valid string to a floating point number.
4129 dValue = atof( pNewString );
4131 /* We don't need the string anymore so free it.
4133 HeapFree( GetProcessHeap(), 0, pNewString );
4135 /* Check range of value.
4137 dValue = round( dValue );
4138 if( dValue < UI2_MIN || dValue > UI2_MAX )
4140 return DISP_E_OVERFLOW;
4143 *puiOut = (USHORT) dValue;
4148 /******************************************************************************
4149 * VarUI2FromBool [OLEAUT32.266]
4151 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
4153 TRACE("( %d, %p ), stub\n", boolIn, puiOut );
4155 *puiOut = (USHORT) boolIn;
4160 /******************************************************************************
4161 * VarUI2FromI1 [OLEAUT32.267]
4163 HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
4165 TRACE("( %c, %p ), stub\n", cIn, puiOut );
4167 *puiOut = (USHORT) cIn;
4172 /******************************************************************************
4173 * VarUI2FromUI4 [OLEAUT32.268]
4175 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
4177 TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
4179 if( ulIn > UI2_MAX )
4181 return DISP_E_OVERFLOW;
4184 *puiOut = (USHORT) ulIn;
4189 /******************************************************************************
4190 * VarUI4FromStr [OLEAUT32.277]
4192 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
4194 double dValue = 0.0;
4195 LPSTR pNewString = NULL;
4197 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
4199 /* Check if we have a valid argument
4201 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4202 RemoveCharacterFromString( pNewString, "," );
4203 if( IsValidRealString( pNewString ) == FALSE )
4205 return DISP_E_TYPEMISMATCH;
4208 /* Convert the valid string to a floating point number.
4210 dValue = atof( pNewString );
4212 /* We don't need the string anymore so free it.
4214 HeapFree( GetProcessHeap(), 0, pNewString );
4216 /* Check range of value.
4218 dValue = round( dValue );
4219 if( dValue < UI4_MIN || dValue > UI4_MAX )
4221 return DISP_E_OVERFLOW;
4224 *pulOut = (ULONG) dValue;
4229 /**********************************************************************
4230 * VarUI2FromCy [OLEAUT32.263]
4231 * Convert currency to unsigned short
4233 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
4234 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4236 if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
4238 *pusOut = (USHORT)t;
4243 /******************************************************************************
4244 * VarUI4FromUI1 [OLEAUT32.270]
4246 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
4248 TRACE("( %d, %p ), stub\n", bIn, pulOut );
4250 *pulOut = (USHORT) bIn;
4255 /******************************************************************************
4256 * VarUI4FromI2 [OLEAUT32.271]
4258 HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
4260 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4262 if( uiIn < UI4_MIN )
4264 return DISP_E_OVERFLOW;
4267 *pulOut = (ULONG) uiIn;
4272 /******************************************************************************
4273 * VarUI4FromI4 [OLEAUT32.272]
4275 HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
4277 TRACE("( %ld, %p ), stub\n", lIn, pulOut );
4281 return DISP_E_OVERFLOW;
4284 *pulOut = (ULONG) lIn;
4289 /******************************************************************************
4290 * VarUI4FromR4 [OLEAUT32.273]
4292 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
4294 fltIn = round( fltIn );
4295 if( fltIn < UI4_MIN || fltIn > UI4_MAX )
4297 return DISP_E_OVERFLOW;
4300 *pulOut = (ULONG) fltIn;
4305 /******************************************************************************
4306 * VarUI4FromR8 [OLEAUT32.274]
4308 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
4310 TRACE("( %f, %p ), stub\n", dblIn, pulOut );
4312 dblIn = round( dblIn );
4313 if( dblIn < UI4_MIN || dblIn > UI4_MAX )
4315 return DISP_E_OVERFLOW;
4318 *pulOut = (ULONG) dblIn;
4323 /******************************************************************************
4324 * VarUI4FromDate [OLEAUT32.275]
4326 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
4328 TRACE("( %f, %p ), stub\n", dateIn, pulOut );
4330 dateIn = round( dateIn );
4331 if( dateIn < UI4_MIN || dateIn > UI4_MAX )
4333 return DISP_E_OVERFLOW;
4336 *pulOut = (ULONG) dateIn;
4341 /******************************************************************************
4342 * VarUI4FromBool [OLEAUT32.279]
4344 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
4346 TRACE("( %d, %p ), stub\n", boolIn, pulOut );
4348 *pulOut = (ULONG) boolIn;
4353 /******************************************************************************
4354 * VarUI4FromI1 [OLEAUT32.280]
4356 HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
4358 TRACE("( %c, %p ), stub\n", cIn, pulOut );
4360 *pulOut = (ULONG) cIn;
4365 /******************************************************************************
4366 * VarUI4FromUI2 [OLEAUT32.281]
4368 HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4370 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4372 *pulOut = (ULONG) uiIn;
4377 /**********************************************************************
4378 * VarUI4FromCy [OLEAUT32.276]
4379 * Convert currency to unsigned long
4381 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
4382 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4384 if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4391 /**********************************************************************
4392 * VarCyFromUI1 [OLEAUT32.98]
4393 * Convert unsigned char to currency
4395 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
4397 pcyOut->s.Lo = ((ULONG)bIn) * 10000;
4402 /**********************************************************************
4403 * VarCyFromI2 [OLEAUT32.99]
4404 * Convert signed short to currency
4406 HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
4407 if (sIn < 0) pcyOut->s.Hi = -1;
4408 else pcyOut->s.Hi = 0;
4409 pcyOut->s.Lo = ((ULONG)sIn) * 10000;
4414 /**********************************************************************
4415 * VarCyFromI4 [OLEAUT32.100]
4416 * Convert signed long to currency
4418 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4419 double t = (double)lIn * (double)10000;
4420 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4421 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4422 if (lIn < 0) pcyOut->s.Hi--;
4427 /**********************************************************************
4428 * VarCyFromR4 [OLEAUT32.101]
4429 * Convert float to currency
4431 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
4432 double t = round((double)fltIn * (double)10000);
4433 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4434 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4435 if (fltIn < 0) pcyOut->s.Hi--;
4440 /**********************************************************************
4441 * VarCyFromR8 [OLEAUT32.102]
4442 * Convert double to currency
4444 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
4445 double t = round(dblIn * (double)10000);
4446 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4447 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4448 if (dblIn < 0) pcyOut->s.Hi--;
4453 /**********************************************************************
4454 * VarCyFromDate [OLEAUT32.103]
4455 * Convert date to currency
4457 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
4458 double t = round((double)dateIn * (double)10000);
4459 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4460 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4461 if (dateIn < 0) pcyOut->s.Hi--;
4466 /**********************************************************************
4467 * VarCyFromStr [OLEAUT32.104]
4468 * FIXME: Never tested with decimal seperator other than '.'
4470 HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
4472 LPSTR pNewString = NULL;
4473 char *decSep = NULL;
4474 char *strPtr,*curPtr = NULL;
4476 double currencyVal = 0.0;
4479 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4480 TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString, lcid, dwFlags, pcyOut );
4482 /* Get locale information - Decimal Seperator (size includes 0x00) */
4483 size = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, NULL, 0);
4484 decSep = (char *) malloc(size);
4485 rc = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, decSep, size);
4486 TRACE("Decimal Seperator is '%s'\n", decSep);
4488 /* Now copy to temporary buffer, skipping any character except 0-9 and
4489 the decimal seperator */
4490 curPtr = pBuffer; /* Current position in string being built */
4491 strPtr = pNewString; /* Current position in supplied currenct string */
4494 /* If decimal seperator, skip it and put '.' in string */
4495 if (strncmp(strPtr, decSep, (size-1)) == 0) {
4496 strPtr = strPtr + (size-1);
4499 } else if ((*strPtr == '+' || *strPtr == '-') ||
4500 (*strPtr >= '0' && *strPtr <= '9')) {
4508 /* Try to get currency into a double */
4509 currencyVal = atof(pBuffer);
4510 TRACE("Converted string '%s' to %f\n", pBuffer, currencyVal);
4512 /* Free allocated storage */
4513 HeapFree( GetProcessHeap(), 0, pNewString );
4516 /* Convert double -> currency using internal routine */
4517 return VarCyFromR8(currencyVal, pcyOut);
4521 /**********************************************************************
4522 * VarCyFromBool [OLEAUT32.106]
4523 * Convert boolean to currency
4525 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
4526 if (boolIn < 0) pcyOut->s.Hi = -1;
4527 else pcyOut->s.Hi = 0;
4528 pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
4533 /**********************************************************************
4534 * VarCyFromI1 [OLEAUT32.225]
4535 * Convert signed char to currency
4537 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
4538 if (cIn < 0) pcyOut->s.Hi = -1;
4539 else pcyOut->s.Hi = 0;
4540 pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
4545 /**********************************************************************
4546 * VarCyFromUI2 [OLEAUT32.226]
4547 * Convert unsigned short to currency
4549 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
4551 pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
4556 /**********************************************************************
4557 * VarCyFromUI4 [OLEAUT32.227]
4558 * Convert unsigned long to currency
4560 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4561 double t = (double)ulIn * (double)10000;
4562 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4563 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4569 /**********************************************************************
4570 * DosDateTimeToVariantTime [OLEAUT32.14]
4571 * Convert dos representation of time to the date and time representation
4572 * stored in a variant.
4574 INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4579 TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
4581 t.tm_sec = (wDosTime & 0x001f) * 2;
4582 t.tm_min = (wDosTime & 0x07e0) >> 5;
4583 t.tm_hour = (wDosTime & 0xf800) >> 11;
4585 t.tm_mday = (wDosDate & 0x001f);
4586 t.tm_mon = (wDosDate & 0x01e0) >> 5;
4587 t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
4589 return TmToDATE( &t, pvtime );
4593 /**********************************************************************
4594 * VarParseNumFromStr [OLEAUT32.46]
4596 HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
4597 NUMPARSE * pnumprs, BYTE * rgbDig)
4601 BOOL foundNum=FALSE;
4603 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
4604 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
4606 /* The other struct components are to be set by us */
4607 memset(rgbDig,0,pnumprs->cDig);
4609 /* FIXME: Just patching some values in */
4610 pnumprs->nPwr10 = 0;
4611 pnumprs->nBaseShift = 0;
4612 pnumprs->cchUsed = lastent;
4613 pnumprs->dwOutFlags = NUMPRS_DECIMAL;
4616 for (i=0; strIn[i] ;i++) {
4617 if ((strIn[i]>='0') && (strIn[i]<='9')) {
4619 if (pnumprs->cDig > cDig) {
4620 *(rgbDig++)=strIn[i]-'0';
4624 } else if ((strIn[i]=='-') && (foundNum==FALSE)) {
4625 pnumprs->dwOutFlags |= NUMPRS_NEG;
4628 pnumprs->cDig = cDig;
4629 TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags);
4634 /**********************************************************************
4635 * VarNumFromParseNum [OLEAUT32.47]
4637 HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
4638 ULONG dwVtBits, VARIANT * pvar)
4642 FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
4645 for (i=0;i<pnumprs->cDig;i++)
4646 xint = xint*10 + rgbDig[i];
4648 if (pnumprs->dwOutFlags & NUMPRS_NEG) {
4653 if (dwVtBits & VTBIT_I4) {
4655 V_UNION(pvar,intVal) = xint;
4658 if (dwVtBits & VTBIT_R8) {
4660 V_UNION(pvar,dblVal) = xint;
4663 if (dwVtBits & VTBIT_R4) {
4665 V_UNION(pvar,fltVal) = xint;
4668 if (dwVtBits & VTBIT_I2) {
4670 V_UNION(pvar,iVal) = xint;
4673 /* FIXME: Currency should be from a double */
4674 if (dwVtBits & VTBIT_CY) {
4676 TRACE("Calculated currency is xint=%ld\n", xint);
4677 VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4678 TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar,cyVal).s.Hi, V_UNION(pvar,cyVal).s.Lo);
4679 return VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4682 FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint);
4687 /**********************************************************************
4688 * VarFormatDateTime [OLEAUT32.97]
4690 HRESULT WINAPI VarFormatDateTime(LPVARIANT var, INT format, ULONG dwFlags, BSTR *out)
4692 FIXME("%p %d %lx %p\n", var, format, dwFlags, out);
4696 /**********************************************************************
4697 * VarFormatCurrency [OLEAUT32.127]
4699 HRESULT WINAPI VarFormatCurrency(LPVARIANT var, INT digits, INT lead, INT paren, INT group, ULONG dwFlags, BSTR *out)
4701 FIXME("%p %d %d %d %d %lx %p\n", var, digits, lead, paren, group, dwFlags, out);
4705 /**********************************************************************
4706 * VariantTimeToDosDateTime [OLEAUT32.13]
4707 * Convert variant representation of time to the date and time representation
4710 INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
4716 TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate, *wDosTime, &pvtime );
4718 if (DateToTm(pvtime, 0, &t) < 0) return 0;
4720 *wDosTime = *wDosTime | (t.tm_sec / 2);
4721 *wDosTime = *wDosTime | (t.tm_min << 5);
4722 *wDosTime = *wDosTime | (t.tm_hour << 11);
4724 *wDosDate = *wDosDate | t.tm_mday ;
4725 *wDosDate = *wDosDate | t.tm_mon << 5;
4726 *wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
4732 /***********************************************************************
4733 * SystemTimeToVariantTime [OLEAUT32.184]
4735 HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime, double *pvtime )
4739 TRACE(" %d/%d/%d %d:%d:%d\n",
4740 lpSystemTime->wMonth, lpSystemTime->wDay,
4741 lpSystemTime->wYear, lpSystemTime->wHour,
4742 lpSystemTime->wMinute, lpSystemTime->wSecond);
4744 if (lpSystemTime->wYear >= 1900)
4746 t.tm_sec = lpSystemTime->wSecond;
4747 t.tm_min = lpSystemTime->wMinute;
4748 t.tm_hour = lpSystemTime->wHour;
4750 t.tm_mday = lpSystemTime->wDay;
4751 t.tm_mon = lpSystemTime->wMonth - 1; /* tm_mon is 0..11, wMonth is 1..12 */
4752 t.tm_year = lpSystemTime->wYear;
4754 return TmToDATE( &t, pvtime );
4759 long firstDayOfNextYear;
4764 double decimalPart = 0.0;
4766 t.tm_sec = lpSystemTime->wSecond;
4767 t.tm_min = lpSystemTime->wMinute;
4768 t.tm_hour = lpSystemTime->wHour;
4770 /* Step year forward the same number of years before 1900 */
4771 t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
4772 t.tm_mon = lpSystemTime->wMonth - 1;
4773 t.tm_mday = lpSystemTime->wDay;
4775 /* Calculate date */
4776 TmToDATE( &t, pvtime );
4778 thisDay = (double) floor( *pvtime );
4779 decimalPart = fmod( *pvtime, thisDay );
4781 /* Now, calculate the same time for the first of Jan that year */
4787 t.tm_year = t.tm_year+1;
4788 TmToDATE( &t, &tmpDate );
4789 firstDayOfNextYear = (long) floor(tmpDate);
4791 /* Finally since we know the size of the year, subtract the two to get
4792 remaining time in the year */
4793 leftInYear = firstDayOfNextYear - thisDay;
4795 /* Now we want full years up to the year in question, and remainder of year
4796 of the year in question */
4797 if (isleap(lpSystemTime->wYear) ) {
4798 TRACE("Extra day due to leap year\n");
4799 result = 2.0 - ((firstDayOfNextYear - 366) + leftInYear - 2.0);
4801 result = 2.0 - ((firstDayOfNextYear - 365) + leftInYear - 2.0);
4803 *pvtime = (double) result + decimalPart;
4804 TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime, firstDayOfNextYear, thisDay, leftInYear);
4812 /***********************************************************************
4813 * VariantTimeToSystemTime [OLEAUT32.185]
4815 HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME lpSystemTime )
4817 double t = 0, timeofday = 0;
4819 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4820 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4822 /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4823 static const BYTE Month_Code[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4824 static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4826 /* The Century_Code is used to find the Day of the Week */
4827 static const BYTE Century_Code[] = {0, 6, 4, 2};
4831 TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime);
4836 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4838 lpSystemTime->wSecond = r.tm_sec;
4839 lpSystemTime->wMinute = r.tm_min;
4840 lpSystemTime->wHour = r.tm_hour;
4841 lpSystemTime->wDay = r.tm_mday;
4842 lpSystemTime->wMonth = r.tm_mon;
4844 if (lpSystemTime->wMonth == 12)
4845 lpSystemTime->wMonth = 1;
4847 lpSystemTime->wMonth++;
4849 lpSystemTime->wYear = r.tm_year;
4855 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4857 lpSystemTime->wSecond = r.tm_sec;
4858 lpSystemTime->wMinute = r.tm_min;
4859 lpSystemTime->wHour = r.tm_hour;
4861 lpSystemTime->wMonth = 13 - r.tm_mon;
4863 if (lpSystemTime->wMonth == 1)
4864 lpSystemTime->wMonth = 12;
4866 lpSystemTime->wMonth--;
4868 lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
4870 if (!isleap(lpSystemTime->wYear) )
4871 lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
4873 lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
4878 if (!isleap(lpSystemTime->wYear))
4881 (Century_Code+Month_Code+Year_Code+Day) % 7
4883 The century code repeats every 400 years , so the array
4884 works out like this,
4886 Century_Code[0] is for 16th/20th Centry
4887 Century_Code[1] is for 17th/21th Centry
4888 Century_Code[2] is for 18th/22th Centry
4889 Century_Code[3] is for 19th/23th Centry
4891 The year code is found with the formula (year + (year / 4))
4892 the "year" must be between 0 and 99 .
4894 The Month Code (Month_Code[1]) starts with January and
4898 lpSystemTime->wDayOfWeek = (
4899 Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
4900 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4901 Month_Code[lpSystemTime->wMonth]+
4902 lpSystemTime->wDay) % 7;
4904 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4905 else lpSystemTime->wDayOfWeek -= 1;
4909 lpSystemTime->wDayOfWeek = (
4910 Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
4911 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4912 Month_Code_LY[lpSystemTime->wMonth]+
4913 lpSystemTime->wDay) % 7;
4915 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4916 else lpSystemTime->wDayOfWeek -= 1;
4920 timeofday = vtime - t;
4922 lpSystemTime->wMilliseconds = (timeofday
4923 - lpSystemTime->wHour*(1/24)
4924 - lpSystemTime->wMinute*(1/1440)
4925 - lpSystemTime->wSecond*(1/86400) )*(1/5184000);
4930 /***********************************************************************
4931 * VarUdateFromDate [OLEAUT32.331]
4933 HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
4936 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4937 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4939 TRACE("DATE = %f\n", (double)datein);
4940 i = VariantTimeToSystemTime(datein, &(pudateout->st) );
4944 pudateout->wDayOfYear = 0;
4946 if (isleap(pudateout->st.wYear))
4948 for (i =1; i<pudateout->st.wMonth; i++)
4949 pudateout->wDayOfYear += Days_Per_Month[i];
4953 for (i =1; i<pudateout->st.wMonth; i++)
4954 pudateout->wDayOfYear += Days_Per_Month_LY[i];
4957 pudateout->wDayOfYear += pudateout->st.wDay;
4958 dwFlags = 0; /*VAR_VALIDDATE*/
4965 /***********************************************************************
4966 * VarDateFromUdate [OLEAUT32.330]
4968 HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
4969 ULONG dwFlags, DATE *datein)
4973 TRACE(" %d/%d/%d %d:%d:%d\n",
4974 pudateout->st.wMonth, pudateout->st.wDay,
4975 pudateout->st.wYear, pudateout->st.wHour,
4976 pudateout->st.wMinute, pudateout->st.wSecond);
4979 i = SystemTimeToVariantTime(&(pudateout->st), &t);
4983 else return E_INVALIDARG;
4987 /**********************************************************************
4988 * VarBstrCmp [OLEAUT32.314]
4991 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4992 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4995 HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
4999 TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
5001 /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
5002 if((!left) || (!right)) {
5004 if (!left && (!right || *right==0)) return VARCMP_EQ;
5005 else if (!right && (!left || *left==0)) return VARCMP_EQ;
5006 else return VARCMP_NULL;
5009 if(flags&NORM_IGNORECASE)
5010 r = lstrcmpiW(left,right);
5012 r = lstrcmpW(left,right);
5022 /**********************************************************************
5023 * VarBstrCat [OLEAUT32.313]
5025 HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
5030 TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
5032 /* On Windows, NULL parms are still handled (as empty strings) */
5033 if (left) size=size + lstrlenW(left);
5034 if (right) size=size + lstrlenW(right);
5037 result = SysAllocStringLen(NULL, size);
5039 if (left) lstrcatW(result,left);
5040 if (right) lstrcatW(result,right);
5041 TRACE("result = %s, [%p]\n", debugstr_w(result), result);
5046 /**********************************************************************
5047 * VarCat [OLEAUT32.318]
5049 HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
5051 /* Should we VariantClear out? */
5052 /* Can we handle array, vector, by ref etc. */
5053 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL &&
5054 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
5056 V_VT(out) = VT_NULL;
5060 if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR)
5062 V_VT(out) = VT_BSTR;
5063 VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out));
5066 if (V_VT(left) == VT_BSTR) {
5070 V_VT(out) = VT_BSTR;
5071 hres = VariantChangeTypeEx(&bstrvar,right,0,0,VT_BSTR);
5073 FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right));
5076 VarBstrCat (V_BSTR(left), V_BSTR(&bstrvar), &V_BSTR(out));
5079 if (V_VT(right) == VT_BSTR) {
5083 V_VT(out) = VT_BSTR;
5084 hres = VariantChangeTypeEx(&bstrvar,left,0,0,VT_BSTR);
5086 FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right));
5089 VarBstrCat (V_BSTR(&bstrvar), V_BSTR(right), &V_BSTR(out));
5092 FIXME ("types %d / %d not supported\n",V_VT(left)&VT_TYPEMASK, V_VT(right)&VT_TYPEMASK);
5096 /**********************************************************************
5097 * VarCmp [OLEAUT32.176]
5100 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
5101 * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
5104 HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
5113 TRACE("Left Var:\n");
5115 TRACE("Right Var:\n");
5116 dump_Variant(right);
5118 /* If either are null, then return VARCMP_NULL */
5119 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL ||
5120 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
5123 /* Strings - use VarBstrCmp */
5124 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
5125 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
5126 return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags);
5129 /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
5130 Use LONGLONG to maximize ranges */
5132 switch (V_VT(left)&VT_TYPEMASK) {
5133 case VT_I1 : lVal = V_UNION(left,cVal); break;
5134 case VT_I2 : lVal = V_UNION(left,iVal); break;
5135 case VT_I4 : lVal = V_UNION(left,lVal); break;
5136 case VT_INT : lVal = V_UNION(left,lVal); break;
5137 case VT_UI1 : lVal = V_UNION(left,bVal); break;
5138 case VT_UI2 : lVal = V_UNION(left,uiVal); break;
5139 case VT_UI4 : lVal = V_UNION(left,ulVal); break;
5140 case VT_UINT : lVal = V_UNION(left,ulVal); break;
5141 case VT_BOOL : lVal = V_UNION(left,boolVal); break;
5142 default: lOk = FALSE;
5146 switch (V_VT(right)&VT_TYPEMASK) {
5147 case VT_I1 : rVal = V_UNION(right,cVal); break;
5148 case VT_I2 : rVal = V_UNION(right,iVal); break;
5149 case VT_I4 : rVal = V_UNION(right,lVal); break;
5150 case VT_INT : rVal = V_UNION(right,lVal); break;
5151 case VT_UI1 : rVal = V_UNION(right,bVal); break;
5152 case VT_UI2 : rVal = V_UNION(right,uiVal); break;
5153 case VT_UI4 : rVal = V_UNION(right,ulVal); break;
5154 case VT_UINT : rVal = V_UNION(right,ulVal); break;
5155 case VT_BOOL : rVal = V_UNION(right,boolVal); break;
5156 default: rOk = FALSE;
5162 } else if (lVal > rVal) {
5169 /* Strings - use VarBstrCmp */
5170 if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
5171 (V_VT(right)&VT_TYPEMASK) == VT_DATE) {
5173 if (floor(V_UNION(left,date)) == floor(V_UNION(right,date))) {
5174 /* Due to floating point rounding errors, calculate varDate in whole numbers) */
5175 double wholePart = 0.0;
5179 /* Get the fraction * 24*60*60 to make it into whole seconds */
5180 wholePart = (double) floor( V_UNION(left,date) );
5181 if (wholePart == 0) wholePart = 1;
5182 leftR = floor(fmod( V_UNION(left,date), wholePart ) * (24*60*60));
5184 wholePart = (double) floor( V_UNION(right,date) );
5185 if (wholePart == 0) wholePart = 1;
5186 rightR = floor(fmod( V_UNION(right,date), wholePart ) * (24*60*60));
5188 if (leftR < rightR) {
5190 } else if (leftR > rightR) {
5196 } else if (V_UNION(left,date) < V_UNION(right,date)) {
5198 } else if (V_UNION(left,date) > V_UNION(right,date)) {
5204 FIXME("VarCmp partial implementation, doesnt support vt 0x%x / 0x%x\n",V_VT(left), V_VT(right));
5208 /**********************************************************************
5209 * VarAnd [OLEAUT32.142]
5212 HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5214 HRESULT rc = E_FAIL;
5216 TRACE("Left Var:\n");
5218 TRACE("Right Var:\n");
5219 dump_Variant(right);
5221 if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5222 (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5224 V_VT(result) = VT_BOOL;
5225 if (V_BOOL(left) && V_BOOL(right)) {
5226 V_BOOL(result) = VARIANT_TRUE;
5228 V_BOOL(result) = VARIANT_FALSE;
5239 int resT = 0; /* Testing has shown I2 & I2 == I2, all else
5240 becomes I4, even unsigned ints (incl. UI2) */
5243 switch (V_VT(left)&VT_TYPEMASK) {
5244 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
5245 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
5246 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5247 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5248 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
5249 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5250 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5251 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5252 default: lOk = FALSE;
5256 switch (V_VT(right)&VT_TYPEMASK) {
5257 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
5258 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
5259 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5260 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5261 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
5262 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5263 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5264 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5265 default: rOk = FALSE;
5269 res = (lVal & rVal);
5270 V_VT(result) = resT;
5272 case VT_I2 : V_UNION(result,iVal) = res; break;
5273 case VT_I4 : V_UNION(result,lVal) = res; break;
5275 FIXME("Unexpected result variant type %x\n", resT);
5276 V_UNION(result,lVal) = res;
5281 FIXME("VarAnd stub\n");
5285 TRACE("rc=%d, Result:\n", (int) rc);
5286 dump_Variant(result);
5290 /**********************************************************************
5291 * VarAdd [OLEAUT32.141]
5292 * FIXME: From MSDN: If ... Then
5293 * Both expressions are of the string type Concatenated.
5294 * One expression is a string type and the other a character Addition.
5295 * One expression is numeric and the other is a string Addition.
5296 * Both expressions are numeric Addition.
5297 * Either expression is NULL NULL is returned.
5298 * Both expressions are empty Integer subtype is returned.
5301 HRESULT WINAPI VarAdd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5303 HRESULT rc = E_FAIL;
5305 TRACE("Left Var:\n");
5307 TRACE("Right Var:\n");
5308 dump_Variant(right);
5310 /* Handle strings as concat */
5311 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
5312 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
5313 V_VT(result) = VT_BSTR;
5314 VarBstrCat(V_BSTR(left), V_BSTR(right), &V_BSTR(result));
5323 int resT = 0; /* Testing has shown I2 + I2 == I2, all else
5327 switch (V_VT(left)&VT_TYPEMASK) {
5328 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
5329 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
5330 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5331 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5332 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
5333 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5334 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5335 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5336 default: lOk = FALSE;
5340 switch (V_VT(right)&VT_TYPEMASK) {
5341 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
5342 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
5343 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5344 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5345 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
5346 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5347 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5348 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5349 default: rOk = FALSE;
5353 res = (lVal + rVal);
5354 V_VT(result) = resT;
5356 case VT_I2 : V_UNION(result,iVal) = res; break;
5357 case VT_I4 : V_UNION(result,lVal) = res; break;
5359 FIXME("Unexpected result variant type %x\n", resT);
5360 V_UNION(result,lVal) = res;
5365 FIXME("unimplemented part\n");
5369 TRACE("rc=%d, Result:\n", (int) rc);
5370 dump_Variant(result);
5374 /**********************************************************************
5375 * VarOr [OLEAUT32.157]
5378 HRESULT WINAPI VarOr(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5380 HRESULT rc = E_FAIL;
5382 TRACE("Left Var:\n");
5384 TRACE("Right Var:\n");
5385 dump_Variant(right);
5387 if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5388 (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5390 V_VT(result) = VT_BOOL;
5391 if (V_BOOL(left) || V_BOOL(right)) {
5392 V_BOOL(result) = VARIANT_TRUE;
5394 V_BOOL(result) = VARIANT_FALSE;
5405 int resT = 0; /* Testing has shown I2 & I2 == I2, all else
5406 becomes I4, even unsigned ints (incl. UI2) */
5409 switch (V_VT(left)&VT_TYPEMASK) {
5410 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
5411 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
5412 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5413 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
5414 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
5415 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
5416 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5417 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
5418 default: lOk = FALSE;
5422 switch (V_VT(right)&VT_TYPEMASK) {
5423 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
5424 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
5425 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5426 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
5427 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
5428 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
5429 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5430 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
5431 default: rOk = FALSE;
5435 res = (lVal | rVal);
5436 V_VT(result) = resT;
5438 case VT_I2 : V_UNION(result,iVal) = res; break;
5439 case VT_I4 : V_UNION(result,lVal) = res; break;
5441 FIXME("Unexpected result variant type %x\n", resT);
5442 V_UNION(result,lVal) = res;
5447 FIXME("unimplemented part\n");
5451 TRACE("rc=%d, Result:\n", (int) rc);
5452 dump_Variant(result);
5456 /**********************************************************************
5457 * VarNot [OLEAUT32.174]
5460 HRESULT WINAPI VarNot(LPVARIANT in, LPVARIANT result)
5462 HRESULT rc = E_FAIL;
5467 if ((V_VT(in)&VT_TYPEMASK) == VT_BOOL) {
5469 V_VT(result) = VT_BOOL;
5471 V_BOOL(result) = VARIANT_FALSE;
5473 V_BOOL(result) = VARIANT_TRUE;
5478 FIXME("VarNot stub\n");
5481 TRACE("rc=%d, Result:\n", (int) rc);
5482 dump_Variant(result);
5486 /**********************************************************************
5487 * VarTokenizeFormatString [OLEAUT32.140]
5489 * From investigation on W2K, a list is built up which is:
5491 * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
5492 * <token> - Insert appropriate token
5495 HRESULT WINAPI VarTokenizeFormatString(LPOLESTR format, LPBYTE rgbTok,
5496 int cbTok, int iFirstDay, int iFirstWeek,
5497 LCID lcid, int *pcbActual) {
5500 int realLen, formatLeft;
5502 LPSTR pFormatA, pStart;
5504 BOOL insertCopy = FALSE;
5505 LPSTR copyFrom = NULL;
5507 TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format), rgbTok, cbTok,
5508 iFirstDay, iFirstWeek);
5510 /* Big enough for header? */
5511 if (cbTok < sizeof(FORMATHDR)) {
5512 return TYPE_E_BUFFERTOOSMALL;
5516 hdr = (FORMATHDR *) rgbTok;
5517 memset(hdr, 0x00, sizeof(FORMATHDR));
5518 hdr->hex3 = 0x03; /* No idea what these are */
5521 /* Start parsing string */
5522 realLen = sizeof(FORMATHDR);
5523 pData = rgbTok + realLen;
5524 pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5526 formatLeft = strlen(pFormatA);
5528 /* Work through the format */
5529 while (*pFormatA != 0x00) {
5532 while (checkStr>=0 && (formatTokens[checkStr].tokenSize != 0x00)) {
5533 if (formatLeft >= formatTokens[checkStr].tokenSize &&
5534 strncmp(formatTokens[checkStr].str, pFormatA,
5535 formatTokens[checkStr].tokenSize) == 0) {
5536 TRACE("match on '%s'\n", formatTokens[checkStr].str);
5540 /* If we have skipped chars, insert the copy */
5541 if (insertCopy == TRUE) {
5543 if ((realLen + 3) > cbTok) {
5544 HeapFree( GetProcessHeap(), 0, pFormatA );
5545 return TYPE_E_BUFFERTOOSMALL;
5550 *pData = (BYTE)(copyFrom - pStart);
5552 *pData = (BYTE)(pFormatA - copyFrom);
5554 realLen = realLen + 3;
5558 /* Now insert the token itself */
5559 if ((realLen + 1) > cbTok) {
5560 HeapFree( GetProcessHeap(), 0, pFormatA );
5561 return TYPE_E_BUFFERTOOSMALL;
5563 *pData = formatTokens[checkStr].tokenId;
5565 realLen = realLen + 1;
5567 pFormatA = pFormatA + formatTokens[checkStr].tokenSize;
5568 formatLeft = formatLeft - formatTokens[checkStr].tokenSize;
5569 checkStr = -1; /* Flag as found and break out of while loop */
5575 /* Did we ever match a token? */
5576 if (checkStr != -1 && insertCopy == FALSE) {
5577 TRACE("No match - need to insert copy from %p [%p]\n", pFormatA, pStart);
5579 copyFrom = pFormatA;
5580 } else if (checkStr != -1) {
5581 pFormatA = pFormatA + 1;
5586 /* Finally, if we have skipped chars, insert the copy */
5587 if (insertCopy == TRUE) {
5589 TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom, pStart, pFormatA);
5590 if ((realLen + 3) > cbTok) {
5591 HeapFree( GetProcessHeap(), 0, pFormatA );
5592 return TYPE_E_BUFFERTOOSMALL;
5597 *pData = (BYTE)(copyFrom - pStart);
5599 *pData = (BYTE)(pFormatA - copyFrom);
5601 realLen = realLen + 3;
5604 /* Finally insert the terminator */
5605 if ((realLen + 1) > cbTok) {
5606 HeapFree( GetProcessHeap(), 0, pFormatA );
5607 return TYPE_E_BUFFERTOOSMALL;
5610 realLen = realLen + 1;
5612 /* Finally fill in the length */
5614 *pcbActual = realLen;
5618 for (i=0; i<realLen; i=i+0x10) {
5619 printf(" %4.4x : ", i);
5620 for (j=0; j<0x10 && (i+j < realLen); j++) {
5621 printf("%2.2x ", rgbTok[i+j]);
5627 HeapFree( GetProcessHeap(), 0, pFormatA );
5632 /**********************************************************************
5633 * VarFormatFromTokens [OLEAUT32.139]
5634 * FIXME: No account of flags or iFirstDay etc
5636 HRESULT WINAPI VarFormatFromTokens(LPVARIANT varIn, LPOLESTR format,
5637 LPBYTE pbTokCur, ULONG dwFlags, BSTR *pbstrOut,
5640 FORMATHDR *hdr = (FORMATHDR *)pbTokCur;
5641 BYTE *pData = pbTokCur + sizeof (FORMATHDR);
5642 LPSTR pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5643 char output[BUFFER_MAX];
5645 int size, whichToken;
5651 TRACE("'%s', %p %lx %p only date support\n", pFormatA, pbTokCur, dwFlags, pbstrOut);
5653 dump_Variant(varIn);
5655 memset(output, 0x00, BUFFER_MAX);
5658 while (*pData != TOK_END && ((pData - pbTokCur) <= (hdr->len))) {
5660 TRACE("Output looks like : '%s'\n", output);
5662 /* Convert varient to appropriate data type */
5664 while ((formatTokens[whichToken].tokenSize != 0x00) &&
5665 (formatTokens[whichToken].tokenId != *pData)) {
5669 /* Use Variant local from here downwards as always correct type */
5670 if (formatTokens[whichToken].tokenSize > 0 &&
5671 formatTokens[whichToken].varTypeRequired != 0) {
5672 VariantInit( &Variant );
5673 if (Coerce( &Variant, lcid, dwFlags, varIn,
5674 formatTokens[whichToken].varTypeRequired ) != S_OK) {
5675 HeapFree( GetProcessHeap(), 0, pFormatA );
5676 return DISP_E_TYPEMISMATCH;
5677 } else if (formatTokens[whichToken].varTypeRequired == VT_DATE) {
5678 if( DateToTm( V_UNION(&Variant,date), dwFlags, &TM ) == FALSE ) {
5679 HeapFree( GetProcessHeap(), 0, pFormatA );
5680 return E_INVALIDARG;
5685 TRACE("Looking for match on token '%x'\n", *pData);
5688 TRACE("Copy from %d for %d bytes\n", *(pData+1), *(pData+2));
5689 memcpy(pNextPos, &pFormatA[*(pData+1)], *(pData+2));
5690 pNextPos = pNextPos + *(pData+2);
5695 /* Get locale information - Time Seperator */
5696 size = GetLocaleInfoA(lcid, LOCALE_STIME, NULL, 0);
5697 GetLocaleInfoA(lcid, LOCALE_STIME, pNextPos, size);
5698 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5699 pNextPos = pNextPos + size;
5704 /* Get locale information - Date Seperator */
5705 size = GetLocaleInfoA(lcid, LOCALE_SDATE, NULL, 0);
5706 GetLocaleInfoA(lcid, LOCALE_SDATE, pNextPos, size);
5707 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5708 pNextPos = pNextPos + size;
5713 sprintf(pNextPos, "%d", TM.tm_mday);
5714 pNextPos = pNextPos + strlen(pNextPos);
5719 sprintf(pNextPos, "%2.2d", TM.tm_mday);
5720 pNextPos = pNextPos + strlen(pNextPos);
5725 sprintf(pNextPos, "%d", TM.tm_wday+1);
5726 pNextPos = pNextPos + strlen(pNextPos);
5731 sprintf(pNextPos, "%d", TM.tm_mon+1);
5732 pNextPos = pNextPos + strlen(pNextPos);
5737 sprintf(pNextPos, "%2.2d", TM.tm_mon+1);
5738 pNextPos = pNextPos + strlen(pNextPos);
5743 sprintf(pNextPos, "%d", ((TM.tm_mon+1)/4)+1);
5744 pNextPos = pNextPos + strlen(pNextPos);
5749 sprintf(pNextPos, "%2.2d", TM.tm_yday+1);
5750 pNextPos = pNextPos + strlen(pNextPos);
5755 sprintf(pNextPos, "%2.2d", TM.tm_year);
5756 pNextPos = pNextPos + strlen(pNextPos);
5761 sprintf(pNextPos, "%4.4d", TM.tm_year);
5762 pNextPos = pNextPos + strlen(pNextPos);
5767 sprintf(pNextPos, "%d", TM.tm_hour);
5768 pNextPos = pNextPos + strlen(pNextPos);
5773 sprintf(pNextPos, "%2.2d", TM.tm_hour);
5774 pNextPos = pNextPos + strlen(pNextPos);
5779 sprintf(pNextPos, "%d", TM.tm_min);
5780 pNextPos = pNextPos + strlen(pNextPos);
5785 sprintf(pNextPos, "%2.2d", TM.tm_min);
5786 pNextPos = pNextPos + strlen(pNextPos);
5791 sprintf(pNextPos, "%d", TM.tm_sec);
5792 pNextPos = pNextPos + strlen(pNextPos);
5797 sprintf(pNextPos, "%2.2d", TM.tm_sec);
5798 pNextPos = pNextPos + strlen(pNextPos);
5818 FIXME("Unhandled token for VarFormat %d\n", *pData);
5819 HeapFree( GetProcessHeap(), 0, pFormatA );
5820 return E_INVALIDARG;
5825 *pbstrOut = StringDupAtoBstr( output );
5826 HeapFree( GetProcessHeap(), 0, pFormatA );
5830 /**********************************************************************
5831 * VarFormat [OLEAUT32.87]
5834 HRESULT WINAPI VarFormat(LPVARIANT varIn, LPOLESTR format,
5835 int firstDay, int firstWeek, ULONG dwFlags,
5838 LPSTR pNewString = NULL;
5841 TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
5842 debugstr_w(format), firstDay, firstWeek, dwFlags);
5844 dump_Variant(varIn);
5846 /* Note: Must Handle references type Variants (contain ptrs
5847 to values rather than values */
5849 /* Get format string */
5850 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5852 /* FIXME: Handle some simple pre-definted format strings : */
5853 if (((V_VT(varIn)&VT_TYPEMASK) == VT_CY) && (lstrcmpiA(pNewString, "Currency") == 0)) {
5855 /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
5859 /* Handle references type Variants (contain ptrs to values rather than values */
5860 if (V_VT(varIn)&VT_BYREF) {
5861 rc = VarR8FromCy(*(CY *)V_UNION(varIn,byref), &curVal);
5863 rc = VarR8FromCy(V_UNION(varIn,cyVal), &curVal);
5867 char tmpStr[BUFFER_MAX];
5868 sprintf(tmpStr, "%f", curVal);
5869 if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags, tmpStr, NULL, pBuffer, BUFFER_MAX) == 0) {
5872 *pbstrOut = StringDupAtoBstr( pBuffer );
5876 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_DATE) {
5878 /* Attempt to do proper formatting! */
5879 int firstToken = -1;
5881 rc = VarTokenizeFormatString(format, pBuffer, sizeof(pBuffer), firstDay,
5882 firstWeek, GetUserDefaultLCID(), &firstToken);
5884 rc = VarFormatFromTokens(varIn, format, pBuffer, dwFlags, pbstrOut, GetUserDefaultLCID());
5887 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_R8) {
5888 if (V_VT(varIn)&VT_BYREF) {
5889 sprintf(pBuffer, "%f", *V_UNION(varIn,pdblVal));
5891 sprintf(pBuffer, "%f", V_UNION(varIn,dblVal));
5894 *pbstrOut = StringDupAtoBstr( pBuffer );
5896 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_BSTR) {
5897 if (V_VT(varIn)&VT_BYREF)
5898 *pbstrOut = SysAllocString( *V_UNION(varIn,pbstrVal) );
5900 *pbstrOut = SysAllocString( V_UNION(varIn,bstrVal) );
5902 FIXME("VarFormat: Unsupported format %d!\n", V_VT(varIn)&VT_TYPEMASK);
5903 *pbstrOut = StringDupAtoBstr( "??" );
5906 /* Free allocated storage */
5907 HeapFree( GetProcessHeap(), 0, pNewString );
5908 TRACE("result: '%s'\n", debugstr_w(*pbstrOut));
5912 /**********************************************************************
5913 * VarCyMulI4 [OLEAUT32.304]
5914 * Multiply currency value by integer
5916 HRESULT WINAPI VarCyMulI4(CY cyIn, LONG mulBy, CY *pcyOut) {
5921 rc = VarR8FromCy(cyIn, &cyVal);
5923 rc = VarCyFromR8((cyVal * (double) mulBy), pcyOut);
5924 TRACE("Multiply %f by %ld = %f [%ld,%lu]\n", cyVal, mulBy, (cyVal * (double) mulBy),
5925 pcyOut->s.Hi, pcyOut->s.Lo);