4 * Copyright 1998 Jean-Claude Cote
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * This implements the low-level and hi-level APIs for manipulating VARIANTs.
22 * The low-level APIs are used to do data coercion between different data types.
23 * The hi-level APIs are built on top of these low-level APIs and handle
24 * initialization, copying, destroying and changing the type of VARIANTs.
27 * - The Variant APIs do not support international languages, currency
28 * types, number formating and calendar. They only support U.S. English format.
29 * - The Variant APIs do not the following types: IUknown, IDispatch, DECIMAL and SafeArray.
30 * The prototypes for these are commented out in the oleauto.h file. They need
31 * to be implemented and cases need to be added to the switches of the existing APIs.
32 * - The parsing of date for the VarDateFromStr is not complete.
33 * - The date manipulations do not support dates prior to 1900.
34 * - The parsing does not accept as many formats as the Windows implementation.
52 #include "wine/debug.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(ole);
59 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
63 # define FLT_MAX MAXFLOAT
65 # error "Can't find #define for MAXFLOAT/FLT_MAX"
71 static const char CHAR_MAX = 127;
72 static const char CHAR_MIN = -128;
73 static const BYTE UI1_MAX = 255;
74 static const BYTE UI1_MIN = 0;
75 static const unsigned short UI2_MAX = 65535;
76 static const unsigned short UI2_MIN = 0;
77 static const short I2_MAX = 32767;
78 static const short I2_MIN = -32768;
79 static const unsigned long UI4_MAX = 4294967295U;
80 static const unsigned long UI4_MIN = 0;
81 static const long I4_MAX = 2147483647;
82 static const long I4_MIN = -(2147483648U);
83 static const DATE DATE_MIN = -657434;
84 static const DATE DATE_MAX = 2958465;
87 /* This mask is used to set a flag in wReserved1 of
88 * the VARIANTARG structure. The flag indicates if
89 * the API function is using an inner variant or not.
91 #define PROCESSING_INNER_VARIANT 0x0001
93 /* General use buffer.
95 #define BUFFER_MAX 1024
96 static char pBuffer[BUFFER_MAX];
99 * Note a leap year is one that is a multiple of 4
100 * but not of a 100. Except if it is a multiple of
101 * 400 then it is a leap year.
105 * Use 365 days/year and a manual calculation for leap year days
106 * to keep arithmetic simple
108 static const double DAYS_IN_ONE_YEAR = 365.0;
111 * Token definitions for Varient Formatting
112 * Worked out by experimentation on a w2k machine. Doesnt appear to be
113 * documented anywhere obviously so keeping definitions internally
116 /* Pre defined tokens */
117 #define TOK_COPY 0x00
119 #define LARGEST_TOKENID 6
121 /* Mapping of token name to id put into the tokenized form
122 Note testing on W2K shows aaaa and oooo are not parsed??!! */
123 #define TOK_COLON 0x03
124 #define TOK_SLASH 0x04
129 #define TOK_dddd 0x0b
130 #define TOK_ddddd 0x0c
131 #define TOK_dddddd 0x0d
137 #define TOK_mmmm 0x14
141 #define TOK_yyyy 0x18
148 #define TOK_ttttt 0x07
149 #define TOK_AMsPM 0x2f
150 #define TOK_amspm 0x32
153 #define TOK_AMPM 0x2e
155 typedef struct tagFORMATTOKEN {
162 typedef struct tagFORMATHDR {
169 FORMATTOKEN formatTokens[] = { /* FIXME: Only date formats so far */
170 {":" , 1, TOK_COLON , 0},
171 {"/" , 1, TOK_SLASH , 0},
172 {"c" , 1, TOK_c , VT_DATE},
173 {"dddddd", 6, TOK_dddddd , VT_DATE},
174 {"ddddd" , 5, TOK_ddddd , VT_DATE},
175 {"dddd" , 4, TOK_dddd , VT_DATE},
176 {"ddd" , 3, TOK_ddd , VT_DATE},
177 {"dd" , 2, TOK_dd , VT_DATE},
178 {"d" , 1, TOK_d , VT_DATE},
179 {"ww" , 2, TOK_ww , VT_DATE},
180 {"w" , 1, TOK_w , VT_DATE},
181 {"mmmm" , 4, TOK_mmmm , VT_DATE},
182 {"mmm" , 3, TOK_mmm , VT_DATE},
183 {"mm" , 2, TOK_mm , VT_DATE},
184 {"m" , 1, TOK_m , VT_DATE},
185 {"q" , 1, TOK_q , VT_DATE},
186 {"yyyy" , 4, TOK_yyyy , VT_DATE},
187 {"yy" , 2, TOK_yy , VT_DATE},
188 {"y" , 1, TOK_y , VT_DATE},
189 {"h" , 1, TOK_h , VT_DATE},
190 {"Hh" , 2, TOK_Hh , VT_DATE},
191 {"Nn" , 2, TOK_Nn , VT_DATE},
192 {"N" , 1, TOK_N , VT_DATE},
193 {"S" , 1, TOK_S , VT_DATE},
194 {"Ss" , 2, TOK_Ss , VT_DATE},
195 {"ttttt" , 5, TOK_ttttt , VT_DATE},
196 {"AM/PM" , 5, TOK_AMsPM , VT_DATE},
197 {"am/pm" , 5, TOK_amspm , VT_DATE},
198 {"A/P" , 3, TOK_AsP , VT_DATE},
199 {"a/p" , 3, TOK_asp , VT_DATE},
200 {"AMPM" , 4, TOK_AMPM , VT_DATE},
201 {0x00 , 0, 0 , VT_NULL}
204 /******************************************************************************
205 * DateTimeStringToTm [INTERNAL]
207 * Converts a string representation of a date and/or time to a tm structure.
209 * Note this function uses the postgresql date parsing functions found
210 * in the parsedt.c file.
212 * Returns TRUE if successful.
214 * Note: This function does not parse the day of the week,
215 * daylight savings time. It will only fill the followin fields in
216 * the tm struct, tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
218 ******************************************************************************/
219 static BOOL DateTimeStringToTm( OLECHAR* strIn, DWORD dwFlags, struct tm* pTm )
226 char *field[MAXDATEFIELDS];
227 int ftype[MAXDATEFIELDS];
228 char lowstr[MAXDATELEN + 1];
229 char* strDateTime = NULL;
231 /* Convert the string to ASCII since this is the only format
232 * postgesql can handle.
234 strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
236 if( strDateTime != NULL )
238 /* Make sure we don't go over the maximum length
239 * accepted by postgesql.
241 if( strlen( strDateTime ) <= MAXDATELEN )
243 if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
245 if( dwFlags & VAR_DATEVALUEONLY )
247 /* Get the date information.
248 * It returns 0 if date information was
249 * present and 1 if only time information was present.
250 * -1 if an error occures.
252 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
254 /* Eliminate the time information since we
255 * were asked to get date information only.
263 if( dwFlags & VAR_TIMEVALUEONLY )
265 /* Get time information only.
267 if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
274 /* Get both date and time information.
275 * It returns 0 if date information was
276 * present and 1 if only time information was present.
277 * -1 if an error occures.
279 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
286 HeapFree( GetProcessHeap(), 0, strDateTime );
297 /******************************************************************************
298 * TmToDATE [INTERNAL]
300 * The date is implemented using an 8 byte floating-point number.
301 * Days are represented by whole numbers increments starting with 0.00 has
302 * being December 30 1899, midnight.
303 * The hours are expressed as the fractional part of the number.
304 * December 30 1899 at midnight = 0.00
305 * January 1 1900 at midnight = 2.00
306 * January 4 1900 at 6 AM = 5.25
307 * January 4 1900 at noon = 5.50
308 * December 29 1899 at midnight = -1.00
309 * December 18 1899 at midnight = -12.00
310 * December 18 1899 at 6AM = -12.25
311 * December 18 1899 at 6PM = -12.75
312 * December 19 1899 at midnight = -11.00
313 * The tm structure is as follows:
315 * int tm_sec; seconds after the minute - [0,59]
316 * int tm_min; minutes after the hour - [0,59]
317 * int tm_hour; hours since midnight - [0,23]
318 * int tm_mday; day of the month - [1,31]
319 * int tm_mon; months since January - [0,11]
321 * int tm_wday; days since Sunday - [0,6]
322 * int tm_yday; days since January 1 - [0,365]
323 * int tm_isdst; daylight savings time flag
326 * Note: This function does not use the tm_wday, tm_yday, tm_wday,
327 * and tm_isdst fields of the tm structure. And only converts years
330 * Returns TRUE if successful.
332 static BOOL TmToDATE( struct tm* pTm, DATE *pDateOut )
336 /* Hmmm... An uninitialized Date in VB is December 30 1899 so
337 Start at 0. This is the way DATE is defined. */
339 /* Start at 1. This is the way DATE is defined.
340 * January 1, 1900 at Midnight is 1.00.
341 * January 1, 1900 at 6AM is 1.25.
346 if( (pTm->tm_year - 1900) >= 0 ) {
348 /* Add the number of days corresponding to
351 *pDateOut += (pTm->tm_year - 1900) * 365;
353 /* Add the leap days in the previous years between now and 1900.
354 * Note a leap year is one that is a multiple of 4
355 * but not of a 100. Except if it is a multiple of
356 * 400 then it is a leap year.
357 * Copied + reversed functionality into TmToDate
359 *pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
360 *pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
361 *pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
363 /* Set the leap year flag if the
364 * current year specified by tm_year is a
365 * leap year. This will be used to add a day
368 if( isleap( pTm->tm_year ) )
371 /* Add the number of days corresponding to
372 * the month. (remember tm_mon is 0..11)
374 switch( pTm->tm_mon )
380 *pDateOut += ( 59 + leapYear );
383 *pDateOut += ( 90 + leapYear );
386 *pDateOut += ( 120 + leapYear );
389 *pDateOut += ( 151 + leapYear );
392 *pDateOut += ( 181 + leapYear );
395 *pDateOut += ( 212 + leapYear );
398 *pDateOut += ( 243 + leapYear );
401 *pDateOut += ( 273 + leapYear );
404 *pDateOut += ( 304 + leapYear );
407 *pDateOut += ( 334 + leapYear );
410 /* Add the number of days in this month.
412 *pDateOut += pTm->tm_mday;
414 /* Add the number of seconds, minutes, and hours
415 * to the DATE. Note these are the fracionnal part
416 * of the DATE so seconds / number of seconds in a day.
422 *pDateOut += pTm->tm_hour / 24.0;
423 *pDateOut += pTm->tm_min / 1440.0;
424 *pDateOut += pTm->tm_sec / 86400.0;
428 /******************************************************************************
429 * DateToTm [INTERNAL]
431 * This function converts a windows DATE to a tm structure.
433 * It does not fill all the fields of the tm structure.
434 * Here is a list of the fields that are filled:
435 * tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
437 * Note this function does not support dates before the January 1, 1900
438 * or ( dateIn < 2.0 ).
440 * Returns TRUE if successful.
442 BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )
444 double decimalPart = 0.0;
445 double wholePart = 0.0;
447 memset(pTm,0,sizeof(*pTm));
449 /* Because of the nature of DATE format which
450 * associates 2.0 to January 1, 1900. We will
451 * remove 1.0 from the whole part of the DATE
452 * so that in the following code 1.0
453 * will correspond to January 1, 1900.
454 * This simplifies the processing of the DATE value.
456 decimalPart = fmod( dateIn, 1.0 ); /* Do this before the -1, otherwise 0.xx goes negative */
458 wholePart = (double) floor( dateIn );
460 if( !(dwFlags & VAR_TIMEVALUEONLY) )
462 unsigned int nDay = 0;
464 double yearsSince1900 = 0;
466 /* Hard code dates smaller than January 1, 1900. */
469 pTm->tm_mon = 11; /* December as tm_mon is 0..11 */
472 dateIn = dateIn * -1.0; /* Ensure +ve for time calculation */
473 decimalPart = decimalPart * -1.0; /* Ensure +ve for time calculation */
480 /* Start at 1900, this is where the DATE time 0.0 starts.
483 /* find in what year the day in the "wholePart" falls into.
484 * add the value to the year field.
486 yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 );
487 pTm->tm_year += yearsSince1900;
488 /* determine if this is a leap year.
490 if( isleap( pTm->tm_year ) )
496 /* find what day of that year the "wholePart" corresponds to.
497 * Note: nDay is in [1-366] format
499 nDay = (((unsigned int) wholePart) - ((pTm->tm_year-1900) * DAYS_IN_ONE_YEAR ));
501 /* Remove the leap days in the previous years between now and 1900.
502 * Note a leap year is one that is a multiple of 4
503 * but not of a 100. Except if it is a multiple of
504 * 400 then it is a leap year.
505 * Copied + reversed functionality from TmToDate
507 nDay -= ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
508 nDay += ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
509 nDay -= ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
511 /* Set the tm_yday value.
512 * Note: The day must be converted from [1-366] to [0-365]
514 /*pTm->tm_yday = nDay - 1;*/
515 /* find which month this day corresponds to.
522 else if( nDay <= ( 59 + leapYear ) )
524 pTm->tm_mday = nDay - 31;
527 else if( nDay <= ( 90 + leapYear ) )
529 pTm->tm_mday = nDay - ( 59 + leapYear );
532 else if( nDay <= ( 120 + leapYear ) )
534 pTm->tm_mday = nDay - ( 90 + leapYear );
537 else if( nDay <= ( 151 + leapYear ) )
539 pTm->tm_mday = nDay - ( 120 + leapYear );
542 else if( nDay <= ( 181 + leapYear ) )
544 pTm->tm_mday = nDay - ( 151 + leapYear );
547 else if( nDay <= ( 212 + leapYear ) )
549 pTm->tm_mday = nDay - ( 181 + leapYear );
552 else if( nDay <= ( 243 + leapYear ) )
554 pTm->tm_mday = nDay - ( 212 + leapYear );
557 else if( nDay <= ( 273 + leapYear ) )
559 pTm->tm_mday = nDay - ( 243 + leapYear );
562 else if( nDay <= ( 304 + leapYear ) )
564 pTm->tm_mday = nDay - ( 273 + leapYear );
567 else if( nDay <= ( 334 + leapYear ) )
569 pTm->tm_mday = nDay - ( 304 + leapYear );
572 else if( nDay <= ( 365 + leapYear ) )
574 pTm->tm_mday = nDay - ( 334 + leapYear );
579 if( !(dwFlags & VAR_DATEVALUEONLY) )
581 /* find the number of seconds in this day.
582 * fractional part times, hours, minutes, seconds.
583 * Note: 0.1 is hack to ensure figures come out in whole numbers
584 * due to floating point inaccuracies
586 pTm->tm_hour = (int) ( decimalPart * 24 );
587 pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
588 /* Note: 0.1 is hack to ensure seconds come out in whole numbers
589 due to floating point inaccuracies */
590 pTm->tm_sec = (int) (( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 ) + 0.1);
597 /******************************************************************************
598 * SizeOfVariantData [INTERNAL]
600 * This function finds the size of the data referenced by a Variant based
601 * the type "vt" of the Variant.
603 static int SizeOfVariantData( VARIANT* parg )
606 switch( V_VT(parg) & VT_TYPEMASK )
609 size = sizeof(short);
621 size = sizeof(unsigned short);
624 size = sizeof(unsigned int);
627 size = sizeof(unsigned long);
630 size = sizeof(float);
633 size = sizeof(double);
639 size = sizeof(VARIANT_BOOL);
644 size = sizeof(void*);
649 case( VT_DECIMAL ): /* hmm, tricky, DECIMAL is only VT_BYREF */
651 FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK );
657 /******************************************************************************
658 * StringDupAtoBstr [INTERNAL]
661 static BSTR StringDupAtoBstr( char* strIn )
664 OLECHAR* pNewString = NULL;
665 pNewString = HEAP_strdupAtoW( GetProcessHeap(), 0, strIn );
666 bstr = SysAllocString( pNewString );
667 HeapFree( GetProcessHeap(), 0, pNewString );
671 /******************************************************************************
674 * Round the double value to the nearest integer value.
676 static double round( double d )
678 double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
679 BOOL bEvenNumber = FALSE;
682 /* Save the sign of the number
684 nSign = (d >= 0.0) ? 1 : -1;
687 /* Remove the decimals.
689 integerValue = floor( d );
691 /* Set the Even flag. This is used to round the number when
692 * the decimals are exactly 1/2. If the integer part is
693 * odd the number is rounded up. If the integer part
694 * is even the number is rounded down. Using this method
695 * numbers are rounded up|down half the time.
697 bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
699 /* Remove the integral part of the number.
701 decimals = d - integerValue;
703 /* Note: Ceil returns the smallest integer that is greater that x.
704 * and floor returns the largest integer that is less than or equal to x.
708 /* If the decimal part is greater than 1/2
710 roundedValue = ceil( d );
712 else if( decimals < 0.5 )
714 /* If the decimal part is smaller than 1/2
716 roundedValue = floor( d );
720 /* the decimals are exactly 1/2 so round according to
721 * the bEvenNumber flag.
725 roundedValue = floor( d );
729 roundedValue = ceil( d );
733 return roundedValue * nSign;
736 /******************************************************************************
737 * RemoveCharacterFromString [INTERNAL]
739 * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
741 static void RemoveCharacterFromString( LPSTR str, LPSTR strOfCharToRemove )
743 LPSTR pNewString = NULL;
744 LPSTR strToken = NULL;
746 /* Check if we have a valid argument
750 pNewString = strdup( str );
752 strToken = strtok( pNewString, strOfCharToRemove );
753 while( strToken != NULL ) {
754 strcat( str, strToken );
755 strToken = strtok( NULL, strOfCharToRemove );
762 /******************************************************************************
763 * GetValidRealString [INTERNAL]
765 * Checks if the string is of proper format to be converted to a real value.
767 static BOOL IsValidRealString( LPSTR strRealString )
769 /* Real values that have a decimal point are required to either have
770 * digits before or after the decimal point. We will assume that
771 * we do not have any digits at either position. If we do encounter
772 * some we will disable this flag.
774 BOOL bDigitsRequired = TRUE;
775 /* Processed fields in the string representation of the real number.
777 BOOL bWhiteSpaceProcessed = FALSE;
778 BOOL bFirstSignProcessed = FALSE;
779 BOOL bFirstDigitsProcessed = FALSE;
780 BOOL bDecimalPointProcessed = FALSE;
781 BOOL bSecondDigitsProcessed = FALSE;
782 BOOL bExponentProcessed = FALSE;
783 BOOL bSecondSignProcessed = FALSE;
784 BOOL bThirdDigitsProcessed = FALSE;
785 /* Assume string parameter "strRealString" is valid and try to disprove it.
787 BOOL bValidRealString = TRUE;
789 /* Used to count the number of tokens in the "strRealString".
791 LPSTR strToken = NULL;
795 /* Check if we have a valid argument
797 if( strRealString == NULL )
799 bValidRealString = FALSE;
802 if( bValidRealString == TRUE )
804 /* Make sure we only have ONE token in the string.
806 strToken = strtok( strRealString, " " );
807 while( strToken != NULL ) {
809 strToken = strtok( NULL, " " );
814 bValidRealString = FALSE;
819 /* Make sure this token contains only valid characters.
820 * The string argument to atof has the following form:
821 * [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
822 * Whitespace consists of space and|or <TAB> characters, which are ignored.
823 * Sign is either plus '+' or minus '-'.
824 * Digits are one or more decimal digits.
825 * Note: If no digits appear before the decimal point, at least one must
826 * appear after the decimal point.
827 * The decimal digits may be followed by an exponent.
828 * An Exponent consists of an introductory letter ( D, d, E, or e) and
829 * an optionally signed decimal integer.
831 pChar = strRealString;
832 while( bValidRealString == TRUE && *pChar != '\0' )
840 if( bWhiteSpaceProcessed ||
841 bFirstSignProcessed ||
842 bFirstDigitsProcessed ||
843 bDecimalPointProcessed ||
844 bSecondDigitsProcessed ||
845 bExponentProcessed ||
846 bSecondSignProcessed ||
847 bThirdDigitsProcessed )
849 bValidRealString = FALSE;
856 if( bFirstSignProcessed == FALSE )
858 if( bFirstDigitsProcessed ||
859 bDecimalPointProcessed ||
860 bSecondDigitsProcessed ||
861 bExponentProcessed ||
862 bSecondSignProcessed ||
863 bThirdDigitsProcessed )
865 bValidRealString = FALSE;
867 bWhiteSpaceProcessed = TRUE;
868 bFirstSignProcessed = TRUE;
870 else if( bSecondSignProcessed == FALSE )
872 /* Note: The exponent must be present in
873 * order to accept the second sign...
875 if( bExponentProcessed == FALSE ||
876 bThirdDigitsProcessed ||
879 bValidRealString = FALSE;
881 bFirstSignProcessed = TRUE;
882 bWhiteSpaceProcessed = TRUE;
883 bFirstDigitsProcessed = TRUE;
884 bDecimalPointProcessed = TRUE;
885 bSecondDigitsProcessed = TRUE;
886 bSecondSignProcessed = TRUE;
902 if( bFirstDigitsProcessed == FALSE )
904 if( bDecimalPointProcessed ||
905 bSecondDigitsProcessed ||
906 bExponentProcessed ||
907 bSecondSignProcessed ||
908 bThirdDigitsProcessed )
910 bValidRealString = FALSE;
912 bFirstSignProcessed = TRUE;
913 bWhiteSpaceProcessed = TRUE;
914 /* We have found some digits before the decimal point
915 * so disable the "Digits required" flag.
917 bDigitsRequired = FALSE;
919 else if( bSecondDigitsProcessed == FALSE )
921 if( bExponentProcessed ||
922 bSecondSignProcessed ||
923 bThirdDigitsProcessed )
925 bValidRealString = FALSE;
927 bFirstSignProcessed = TRUE;
928 bWhiteSpaceProcessed = TRUE;
929 bFirstDigitsProcessed = TRUE;
930 bDecimalPointProcessed = TRUE;
931 /* We have found some digits after the decimal point
932 * so disable the "Digits required" flag.
934 bDigitsRequired = FALSE;
936 else if( bThirdDigitsProcessed == FALSE )
938 /* Getting here means everything else should be processed.
939 * If we get anything else than a decimal following this
940 * digit it will be flagged by the other cases, so
941 * we do not really need to do anything in here.
945 /* If DecimalPoint...
948 if( bDecimalPointProcessed ||
949 bSecondDigitsProcessed ||
950 bExponentProcessed ||
951 bSecondSignProcessed ||
952 bThirdDigitsProcessed )
954 bValidRealString = FALSE;
956 bFirstSignProcessed = TRUE;
957 bWhiteSpaceProcessed = TRUE;
958 bFirstDigitsProcessed = TRUE;
959 bDecimalPointProcessed = TRUE;
967 if( bExponentProcessed ||
968 bSecondSignProcessed ||
969 bThirdDigitsProcessed ||
972 bValidRealString = FALSE;
974 bFirstSignProcessed = TRUE;
975 bWhiteSpaceProcessed = TRUE;
976 bFirstDigitsProcessed = TRUE;
977 bDecimalPointProcessed = TRUE;
978 bSecondDigitsProcessed = TRUE;
979 bExponentProcessed = TRUE;
982 bValidRealString = FALSE;
985 /* Process next character.
990 /* If the required digits were not present we have an invalid
991 * string representation of a real number.
993 if( bDigitsRequired == TRUE )
995 bValidRealString = FALSE;
998 return bValidRealString;
1002 /******************************************************************************
1005 * This function dispatches execution to the proper conversion API
1006 * to do the necessary coercion.
1008 * FIXME: Passing down dwFlags to the conversion functions is wrong, this
1009 * is a different flagmask. Check MSDN.
1011 static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
1014 unsigned short vtFrom = 0;
1015 vtFrom = V_VT(ps) & VT_TYPEMASK;
1018 /* Note: Since "long" and "int" values both have 4 bytes and are
1019 * both signed integers "int" will be treated as "long" in the
1021 * The same goes for their unsigned versions.
1024 /* Trivial Case: If the coercion is from two types that are
1025 * identical then we can blindly copy from one argument to another.*/
1028 return VariantCopy(pd,ps);
1031 /* Cases requiring thought*/
1036 res = VariantClear( pd );
1039 res = VariantClear( pd );
1049 res = VariantCopy( pd, ps );
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 %d\n", vtFrom, vt );
1102 res = VarI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,iVal) );
1105 res = VariantCopy( pd, ps );
1109 res = VarI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,iVal) );
1112 res = VarI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,iVal) );
1115 res = VarI2FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,iVal) );
1119 res = VarI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,iVal) );
1122 res = VarI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,iVal) );
1125 res = VarI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,iVal) );
1128 res = VarI2FromDate( V_UNION(ps,date), &V_UNION(pd,iVal) );
1131 res = VarI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,iVal) );
1134 res = VarI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,iVal) );
1137 res = VarI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,iVal) );
1139 case( VT_DISPATCH ):
1140 /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
1142 /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
1145 res = DISP_E_TYPEMISMATCH;
1146 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1156 V_UNION(pd,lVal) = 0;
1160 res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
1163 res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
1167 res = VariantCopy( pd, ps );
1170 res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
1173 res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
1177 res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
1180 res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
1183 res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
1186 res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
1189 res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
1192 res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
1195 res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
1197 case( VT_DISPATCH ):
1198 /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1200 /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1203 res = DISP_E_TYPEMISMATCH;
1204 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1213 res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
1216 res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
1220 res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
1223 res = VariantCopy( pd, ps );
1226 res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
1230 res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
1233 res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
1236 res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
1239 res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
1242 res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
1245 res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
1248 res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
1250 case( VT_DISPATCH ):
1251 /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1253 /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1256 res = DISP_E_TYPEMISMATCH;
1257 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1266 res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
1269 res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
1273 res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
1276 res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
1279 res = VariantCopy( pd, ps );
1283 res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
1286 res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
1289 res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
1292 res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
1295 res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
1298 res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
1301 res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
1303 case( VT_DISPATCH ):
1304 /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1306 /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1309 res = DISP_E_TYPEMISMATCH;
1310 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1320 res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
1323 res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
1327 res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
1330 res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
1333 res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
1336 res = VariantCopy( pd, ps );
1339 res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
1342 res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
1345 res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
1348 res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
1351 res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
1354 res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
1356 case( VT_DISPATCH ):
1357 /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1359 /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1362 res = DISP_E_TYPEMISMATCH;
1363 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1372 res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
1375 res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
1379 res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
1382 res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
1385 res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
1389 res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
1392 res = VariantCopy( pd, ps );
1395 res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
1398 res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
1401 res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
1404 res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
1407 res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
1409 case( VT_DISPATCH ):
1410 /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1412 /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1415 res = DISP_E_TYPEMISMATCH;
1416 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1425 res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
1428 res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
1432 res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
1435 res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
1438 res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
1442 res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
1445 res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
1448 res = VariantCopy( pd, ps );
1451 res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
1454 res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
1457 res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
1460 res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
1462 case( VT_DISPATCH ):
1463 /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1465 /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1468 res = DISP_E_TYPEMISMATCH;
1469 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1478 res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
1481 res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
1484 res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
1487 res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
1490 res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
1493 res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
1496 res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
1499 res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
1502 res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
1505 res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
1508 res = VariantCopy( pd, ps );
1511 res = VarDateFromBool( V_UNION(ps,boolVal), &V_UNION(pd,date) );
1514 res = VarDateFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,date) );
1517 res = VarDateFromCy( V_UNION(ps,cyVal), &V_UNION(pd,date) );
1519 case( VT_DISPATCH ):
1520 /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1522 /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1525 res = DISP_E_TYPEMISMATCH;
1526 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1536 V_UNION(pd,boolVal) = VARIANT_FALSE;
1539 res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
1542 res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
1545 res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
1548 res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
1551 res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
1554 res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
1557 res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
1560 res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
1563 res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
1566 res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
1569 res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
1572 res = VariantCopy( pd, ps );
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 %d\n", vtFrom, vt );
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 %d\n", vtFrom, vt );
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 %d\n", vtFrom, vt );
1714 if (vtFrom == VT_DISPATCH)
1716 res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1720 res = DISP_E_TYPEMISMATCH;
1721 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1726 res = DISP_E_TYPEMISMATCH;
1727 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1734 /******************************************************************************
1735 * ValidateVtRange [INTERNAL]
1737 * Used internally by the hi-level Variant API to determine
1738 * if the vartypes are valid.
1740 static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
1742 /* if by value we must make sure it is in the
1743 * range of the valid types.
1745 if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1747 return DISP_E_BADVARTYPE;
1753 /******************************************************************************
1754 * ValidateVartype [INTERNAL]
1756 * Used internally by the hi-level Variant API to determine
1757 * if the vartypes are valid.
1759 static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
1763 /* check if we have a valid argument.
1767 /* if by reference check that the type is in
1768 * the valid range and that it is not of empty or null type
1770 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1771 ( vt & VT_TYPEMASK ) == VT_NULL ||
1772 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1774 res = DISP_E_BADVARTYPE;
1780 res = ValidateVtRange( vt );
1786 /******************************************************************************
1787 * ValidateVt [INTERNAL]
1789 * Used internally by the hi-level Variant API to determine
1790 * if the vartypes are valid.
1792 static HRESULT WINAPI ValidateVt( VARTYPE vt )
1796 /* check if we have a valid argument.
1800 /* if by reference check that the type is in
1801 * the valid range and that it is not of empty or null type
1803 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1804 ( vt & VT_TYPEMASK ) == VT_NULL ||
1805 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1807 res = DISP_E_BADVARTYPE;
1813 res = ValidateVtRange( vt );
1823 /******************************************************************************
1824 * VariantInit [OLEAUT32.8]
1826 * Initializes the Variant. Unlike VariantClear it does not interpret
1827 * the current contents of the Variant.
1829 void WINAPI VariantInit(VARIANTARG* pvarg)
1831 TRACE("(%p)\n",pvarg);
1833 memset(pvarg, 0, sizeof (VARIANTARG));
1834 V_VT(pvarg) = VT_EMPTY;
1839 /******************************************************************************
1840 * VariantClear [OLEAUT32.9]
1842 * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1843 * sets the wReservedX field to 0. The current contents of the VARIANT are
1844 * freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1845 * released. If VT_ARRAY the array is freed.
1847 HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
1850 TRACE("(%p)\n",pvarg);
1852 res = ValidateVariantType( V_VT(pvarg) );
1855 if( !( V_VT(pvarg) & VT_BYREF ) )
1858 * The VT_ARRAY flag is a special case of a safe array.
1860 if ( (V_VT(pvarg) & VT_ARRAY) != 0)
1862 SafeArrayDestroy(V_UNION(pvarg,parray));
1866 switch( V_VT(pvarg) & VT_TYPEMASK )
1869 SysFreeString( V_UNION(pvarg,bstrVal) );
1871 case( VT_DISPATCH ):
1872 if(V_UNION(pvarg,pdispVal)!=NULL)
1873 ICOM_CALL(Release,V_UNION(pvarg,pdispVal));
1876 VariantClear(V_UNION(pvarg,pvarVal));
1879 if(V_UNION(pvarg,punkVal)!=NULL)
1880 ICOM_CALL(Release,V_UNION(pvarg,punkVal));
1882 case( VT_SAFEARRAY ):
1883 SafeArrayDestroy(V_UNION(pvarg,parray));
1892 * Empty all the fields and mark the type as empty.
1894 memset(pvarg, 0, sizeof (VARIANTARG));
1895 V_VT(pvarg) = VT_EMPTY;
1901 /******************************************************************************
1902 * VariantCopy [OLEAUT32.10]
1904 * Frees up the designation variant and makes a copy of the source.
1906 HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
1910 TRACE("(%p, %p), vt=%d\n", pvargDest, pvargSrc, V_VT(pvargSrc));
1912 res = ValidateVariantType( V_VT(pvargSrc) );
1914 /* If the pointer are to the same variant we don't need
1917 if( pvargDest != pvargSrc && res == S_OK )
1919 res = VariantClear( pvargDest );
1923 if( V_VT(pvargSrc) & VT_BYREF )
1925 /* In the case of byreference we only need
1926 * to copy the pointer.
1928 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1929 V_VT(pvargDest) = V_VT(pvargSrc);
1934 * The VT_ARRAY flag is another way to designate a safe array.
1936 if (V_VT(pvargSrc) & VT_ARRAY)
1938 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1942 /* In the case of by value we need to
1943 * copy the actual value. In the case of
1944 * VT_BSTR a copy of the string is made,
1945 * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1946 * called to increment the object's reference count.
1948 switch( V_VT(pvargSrc) & VT_TYPEMASK )
1951 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
1953 case( VT_DISPATCH ):
1954 V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
1955 if (V_UNION(pvargDest,pdispVal)!=NULL)
1956 ICOM_CALL(AddRef,V_UNION(pvargDest,pdispVal));
1959 VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
1962 V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
1963 if (V_UNION(pvargDest,pdispVal)!=NULL)
1964 ICOM_CALL(AddRef,V_UNION(pvargDest,punkVal));
1966 case( VT_SAFEARRAY ):
1967 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1970 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1975 V_VT(pvargDest) = V_VT(pvargSrc);
1984 /******************************************************************************
1985 * VariantCopyInd [OLEAUT32.11]
1987 * Frees up the destination variant and makes a copy of the source. If
1988 * the source is of type VT_BYREF it performs the necessary indirections.
1990 HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
1994 TRACE("(%p, %p)\n", pvargDest, pvargSrc);
1996 res = ValidateVariantType( V_VT(pvargSrc) );
2001 if( V_VT(pvargSrc) & VT_BYREF )
2004 VariantInit( &varg );
2006 /* handle the in place copy.
2008 if( pvargDest == pvargSrc )
2010 /* we will use a copy of the source instead.
2012 res = VariantCopy( &varg, pvargSrc );
2018 res = VariantClear( pvargDest );
2023 * The VT_ARRAY flag is another way to designate a safearray variant.
2025 if ( V_VT(pvargSrc) & VT_ARRAY)
2027 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2031 /* In the case of by reference we need
2032 * to copy the date pointed to by the variant.
2035 /* Get the variant type.
2037 switch( V_VT(pvargSrc) & VT_TYPEMASK )
2040 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
2042 case( VT_DISPATCH ):
2046 /* Prevent from cycling. According to tests on
2047 * VariantCopyInd in Windows and the documentation
2048 * this API dereferences the inner Variants to only one depth.
2049 * If the inner Variant itself contains an
2050 * other inner variant the E_INVALIDARG error is
2053 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
2055 /* If we get here we are attempting to deference
2056 * an inner variant that that is itself contained
2057 * in an inner variant so report E_INVALIDARG error.
2063 /* Set the processing inner variant flag.
2064 * We will set this flag in the inner variant
2065 * that will be passed to the VariantCopyInd function.
2067 (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
2069 /* Dereference the inner variant.
2071 res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
2072 /* We must also copy its type, I think.
2074 V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
2080 case( VT_SAFEARRAY ):
2081 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2084 /* This is a by reference Variant which means that the union
2085 * part of the Variant contains a pointer to some data of
2086 * type "V_VT(pvargSrc) & VT_TYPEMASK".
2087 * We will deference this data in a generic fashion using
2088 * the void pointer "Variant.u.byref".
2089 * We will copy this data into the union of the destination
2092 memcpy( &pvargDest->n1.n2.n3, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
2097 if (res == S_OK) V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
2101 /* this should not fail.
2103 VariantClear( &varg );
2107 res = VariantCopy( pvargDest, pvargSrc );
2113 /******************************************************************************
2114 * VariantChangeType [OLEAUT32.12]
2116 HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2117 USHORT wFlags, VARTYPE vt)
2119 return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
2122 /******************************************************************************
2123 * VariantChangeTypeEx [OLEAUT32.147]
2125 HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2126 LCID lcid, USHORT wFlags, VARTYPE vt)
2130 VariantInit( &varg );
2132 TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
2133 TRACE("Src Var:\n");
2134 dump_Variant(pvargSrc);
2136 /* validate our source argument.
2138 res = ValidateVariantType( V_VT(pvargSrc) );
2140 /* validate the vartype.
2144 res = ValidateVt( vt );
2147 /* if we are doing an in-place conversion make a copy of the source.
2149 if( res == S_OK && pvargDest == pvargSrc )
2151 res = VariantCopy( &varg, pvargSrc );
2157 /* free up the destination variant.
2159 res = VariantClear( pvargDest );
2164 if( V_VT(pvargSrc) & VT_BYREF )
2166 /* Convert the source variant to a "byvalue" variant.
2169 VariantInit( &Variant );
2170 res = VariantCopyInd( &Variant, pvargSrc );
2173 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2174 /* this should not fail.
2176 VariantClear( &Variant );
2182 /* Use the current "byvalue" source variant.
2184 res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2187 /* this should not fail.
2189 VariantClear( &varg );
2191 /* set the type of the destination
2194 V_VT(pvargDest) = vt;
2196 TRACE("Dest Var:\n");
2197 dump_Variant(pvargDest);
2205 /******************************************************************************
2206 * VarUI1FromI2 [OLEAUT32.130]
2208 HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2210 TRACE("( %d, %p ), stub\n", sIn, pbOut );
2212 /* Check range of value.
2214 if( sIn < UI1_MIN || sIn > UI1_MAX )
2216 return DISP_E_OVERFLOW;
2219 *pbOut = (BYTE) sIn;
2224 /******************************************************************************
2225 * VarUI1FromI4 [OLEAUT32.131]
2227 HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2229 TRACE("( %ld, %p ), stub\n", lIn, pbOut );
2231 /* Check range of value.
2233 if( lIn < UI1_MIN || lIn > UI1_MAX )
2235 return DISP_E_OVERFLOW;
2238 *pbOut = (BYTE) lIn;
2244 /******************************************************************************
2245 * VarUI1FromR4 [OLEAUT32.132]
2247 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2249 TRACE("( %f, %p ), stub\n", fltIn, pbOut );
2251 /* Check range of value.
2253 fltIn = round( fltIn );
2254 if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2256 return DISP_E_OVERFLOW;
2259 *pbOut = (BYTE) fltIn;
2264 /******************************************************************************
2265 * VarUI1FromR8 [OLEAUT32.133]
2267 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2269 TRACE("( %f, %p ), stub\n", dblIn, pbOut );
2271 /* Check range of value.
2273 dblIn = round( dblIn );
2274 if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2276 return DISP_E_OVERFLOW;
2279 *pbOut = (BYTE) dblIn;
2284 /******************************************************************************
2285 * VarUI1FromDate [OLEAUT32.135]
2287 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2289 TRACE("( %f, %p ), stub\n", dateIn, pbOut );
2291 /* Check range of value.
2293 dateIn = round( dateIn );
2294 if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2296 return DISP_E_OVERFLOW;
2299 *pbOut = (BYTE) dateIn;
2304 /******************************************************************************
2305 * VarUI1FromBool [OLEAUT32.138]
2307 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2309 TRACE("( %d, %p ), stub\n", boolIn, pbOut );
2311 *pbOut = (BYTE) boolIn;
2316 /******************************************************************************
2317 * VarUI1FromI1 [OLEAUT32.237]
2319 HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
2321 TRACE("( %c, %p ), stub\n", cIn, pbOut );
2328 /******************************************************************************
2329 * VarUI1FromUI2 [OLEAUT32.238]
2331 HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2333 TRACE("( %d, %p ), stub\n", uiIn, pbOut );
2335 /* Check range of value.
2337 if( uiIn > UI1_MAX )
2339 return DISP_E_OVERFLOW;
2342 *pbOut = (BYTE) uiIn;
2347 /******************************************************************************
2348 * VarUI1FromUI4 [OLEAUT32.239]
2350 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2352 TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
2354 /* Check range of value.
2356 if( ulIn > UI1_MAX )
2358 return DISP_E_OVERFLOW;
2361 *pbOut = (BYTE) ulIn;
2367 /******************************************************************************
2368 * VarUI1FromStr [OLEAUT32.136]
2370 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2372 double dValue = 0.0;
2373 LPSTR pNewString = NULL;
2375 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
2377 /* Check if we have a valid argument
2379 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2380 RemoveCharacterFromString( pNewString, "," );
2381 if( IsValidRealString( pNewString ) == FALSE )
2383 return DISP_E_TYPEMISMATCH;
2386 /* Convert the valid string to a floating point number.
2388 dValue = atof( pNewString );
2390 /* We don't need the string anymore so free it.
2392 HeapFree( GetProcessHeap(), 0 , pNewString );
2394 /* Check range of value.
2396 dValue = round( dValue );
2397 if( dValue < UI1_MIN || dValue > UI1_MAX )
2399 return DISP_E_OVERFLOW;
2402 *pbOut = (BYTE) dValue;
2407 /**********************************************************************
2408 * VarUI1FromCy [OLEAUT32.134]
2409 * Convert currency to unsigned char
2411 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
2412 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2414 if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
2420 /******************************************************************************
2421 * VarI2FromUI1 [OLEAUT32.48]
2423 HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2425 TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
2427 *psOut = (short) bIn;
2432 /******************************************************************************
2433 * VarI2FromI4 [OLEAUT32.49]
2435 HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2437 TRACE("( %lx, %p ), stub\n", lIn, psOut );
2439 /* Check range of value.
2441 if( lIn < I2_MIN || lIn > I2_MAX )
2443 return DISP_E_OVERFLOW;
2446 *psOut = (short) lIn;
2451 /******************************************************************************
2452 * VarI2FromR4 [OLEAUT32.50]
2454 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2456 TRACE("( %f, %p ), stub\n", fltIn, psOut );
2458 /* Check range of value.
2460 fltIn = round( fltIn );
2461 if( fltIn < I2_MIN || fltIn > I2_MAX )
2463 return DISP_E_OVERFLOW;
2466 *psOut = (short) fltIn;
2471 /******************************************************************************
2472 * VarI2FromR8 [OLEAUT32.51]
2474 HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2476 TRACE("( %f, %p ), stub\n", dblIn, psOut );
2478 /* Check range of value.
2480 dblIn = round( dblIn );
2481 if( dblIn < I2_MIN || dblIn > I2_MAX )
2483 return DISP_E_OVERFLOW;
2486 *psOut = (short) dblIn;
2491 /******************************************************************************
2492 * VarI2FromDate [OLEAUT32.53]
2494 HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2496 TRACE("( %f, %p ), stub\n", dateIn, psOut );
2498 /* Check range of value.
2500 dateIn = round( dateIn );
2501 if( dateIn < I2_MIN || dateIn > I2_MAX )
2503 return DISP_E_OVERFLOW;
2506 *psOut = (short) dateIn;
2511 /******************************************************************************
2512 * VarI2FromBool [OLEAUT32.56]
2514 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2516 TRACE("( %d, %p ), stub\n", boolIn, psOut );
2518 *psOut = (short) boolIn;
2523 /******************************************************************************
2524 * VarI2FromI1 [OLEAUT32.205]
2526 HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
2528 TRACE("( %c, %p ), stub\n", cIn, psOut );
2530 *psOut = (short) cIn;
2535 /******************************************************************************
2536 * VarI2FromUI2 [OLEAUT32.206]
2538 HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2540 TRACE("( %d, %p ), stub\n", uiIn, psOut );
2542 /* Check range of value.
2546 return DISP_E_OVERFLOW;
2549 *psOut = (short) uiIn;
2554 /******************************************************************************
2555 * VarI2FromUI4 [OLEAUT32.207]
2557 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2559 TRACE("( %lx, %p ), stub\n", ulIn, psOut );
2561 /* Check range of value.
2563 if( ulIn < I2_MIN || ulIn > I2_MAX )
2565 return DISP_E_OVERFLOW;
2568 *psOut = (short) ulIn;
2573 /******************************************************************************
2574 * VarI2FromStr [OLEAUT32.54]
2576 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2578 double dValue = 0.0;
2579 LPSTR pNewString = NULL;
2581 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, psOut );
2583 /* Check if we have a valid argument
2585 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2586 RemoveCharacterFromString( pNewString, "," );
2587 if( IsValidRealString( pNewString ) == FALSE )
2589 return DISP_E_TYPEMISMATCH;
2592 /* Convert the valid string to a floating point number.
2594 dValue = atof( pNewString );
2596 /* We don't need the string anymore so free it.
2598 HeapFree( GetProcessHeap(), 0, pNewString );
2600 /* Check range of value.
2602 dValue = round( dValue );
2603 if( dValue < I2_MIN || dValue > I2_MAX )
2605 return DISP_E_OVERFLOW;
2608 *psOut = (short) dValue;
2613 /**********************************************************************
2614 * VarI2FromCy [OLEAUT32.52]
2615 * Convert currency to signed short
2617 HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
2618 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2620 if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
2626 /******************************************************************************
2627 * VarI4FromUI1 [OLEAUT32.58]
2629 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2631 TRACE("( %X, %p ), stub\n", bIn, plOut );
2633 *plOut = (LONG) bIn;
2639 /******************************************************************************
2640 * VarI4FromR4 [OLEAUT32.60]
2642 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2644 TRACE("( %f, %p ), stub\n", fltIn, plOut );
2646 /* Check range of value.
2648 fltIn = round( fltIn );
2649 if( fltIn < I4_MIN || fltIn > I4_MAX )
2651 return DISP_E_OVERFLOW;
2654 *plOut = (LONG) fltIn;
2659 /******************************************************************************
2660 * VarI4FromR8 [OLEAUT32.61]
2662 HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2664 TRACE("( %f, %p ), stub\n", dblIn, plOut );
2666 /* Check range of value.
2668 dblIn = round( dblIn );
2669 if( dblIn < I4_MIN || dblIn > I4_MAX )
2671 return DISP_E_OVERFLOW;
2674 *plOut = (LONG) dblIn;
2679 /******************************************************************************
2680 * VarI4FromDate [OLEAUT32.63]
2682 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2684 TRACE("( %f, %p ), stub\n", dateIn, plOut );
2686 /* Check range of value.
2688 dateIn = round( dateIn );
2689 if( dateIn < I4_MIN || dateIn > I4_MAX )
2691 return DISP_E_OVERFLOW;
2694 *plOut = (LONG) dateIn;
2699 /******************************************************************************
2700 * VarI4FromBool [OLEAUT32.66]
2702 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2704 TRACE("( %d, %p ), stub\n", boolIn, plOut );
2706 *plOut = (LONG) boolIn;
2711 /******************************************************************************
2712 * VarI4FromI1 [OLEAUT32.209]
2714 HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
2716 TRACE("( %c, %p ), stub\n", cIn, plOut );
2718 *plOut = (LONG) cIn;
2723 /******************************************************************************
2724 * VarI4FromUI2 [OLEAUT32.210]
2726 HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2728 TRACE("( %d, %p ), stub\n", uiIn, plOut );
2730 *plOut = (LONG) uiIn;
2735 /******************************************************************************
2736 * VarI4FromUI4 [OLEAUT32.211]
2738 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2740 TRACE("( %lx, %p ), stub\n", ulIn, plOut );
2742 /* Check range of value.
2744 if( ulIn < I4_MIN || ulIn > I4_MAX )
2746 return DISP_E_OVERFLOW;
2749 *plOut = (LONG) ulIn;
2754 /******************************************************************************
2755 * VarI4FromI2 [OLEAUT32.59]
2757 HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2759 TRACE("( %d, %p ), stub\n", sIn, plOut );
2761 *plOut = (LONG) sIn;
2766 /******************************************************************************
2767 * VarI4FromStr [OLEAUT32.64]
2769 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2771 double dValue = 0.0;
2772 LPSTR pNewString = NULL;
2774 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
2776 /* Check if we have a valid argument
2778 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2779 RemoveCharacterFromString( pNewString, "," );
2780 if( IsValidRealString( pNewString ) == FALSE )
2782 return DISP_E_TYPEMISMATCH;
2785 /* Convert the valid string to a floating point number.
2787 dValue = atof( pNewString );
2789 /* We don't need the string anymore so free it.
2791 HeapFree( GetProcessHeap(), 0, pNewString );
2793 /* Check range of value.
2795 dValue = round( dValue );
2796 if( dValue < I4_MIN || dValue > I4_MAX )
2798 return DISP_E_OVERFLOW;
2801 *plOut = (LONG) dValue;
2806 /**********************************************************************
2807 * VarI4FromCy [OLEAUT32.62]
2808 * Convert currency to signed long
2810 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
2811 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2813 if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
2819 /******************************************************************************
2820 * VarR4FromUI1 [OLEAUT32.68]
2822 HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
2824 TRACE("( %X, %p ), stub\n", bIn, pfltOut );
2826 *pfltOut = (FLOAT) bIn;
2831 /******************************************************************************
2832 * VarR4FromI2 [OLEAUT32.69]
2834 HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
2836 TRACE("( %d, %p ), stub\n", sIn, pfltOut );
2838 *pfltOut = (FLOAT) sIn;
2843 /******************************************************************************
2844 * VarR4FromI4 [OLEAUT32.70]
2846 HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
2848 TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
2850 *pfltOut = (FLOAT) lIn;
2855 /******************************************************************************
2856 * VarR4FromR8 [OLEAUT32.71]
2858 HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
2860 TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
2862 /* Check range of value.
2864 if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
2866 return DISP_E_OVERFLOW;
2869 *pfltOut = (FLOAT) dblIn;
2874 /******************************************************************************
2875 * VarR4FromDate [OLEAUT32.73]
2877 HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
2879 TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
2881 /* Check range of value.
2883 if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
2885 return DISP_E_OVERFLOW;
2888 *pfltOut = (FLOAT) dateIn;
2893 /******************************************************************************
2894 * VarR4FromBool [OLEAUT32.76]
2896 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
2898 TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
2900 *pfltOut = (FLOAT) boolIn;
2905 /******************************************************************************
2906 * VarR4FromI1 [OLEAUT32.213]
2908 HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
2910 TRACE("( %c, %p ), stub\n", cIn, pfltOut );
2912 *pfltOut = (FLOAT) cIn;
2917 /******************************************************************************
2918 * VarR4FromUI2 [OLEAUT32.214]
2920 HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
2922 TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
2924 *pfltOut = (FLOAT) uiIn;
2929 /******************************************************************************
2930 * VarR4FromUI4 [OLEAUT32.215]
2932 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
2934 TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
2936 *pfltOut = (FLOAT) ulIn;
2941 /******************************************************************************
2942 * VarR4FromStr [OLEAUT32.74]
2944 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
2946 double dValue = 0.0;
2947 LPSTR pNewString = NULL;
2949 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
2951 /* Check if we have a valid argument
2953 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2954 RemoveCharacterFromString( pNewString, "," );
2955 if( IsValidRealString( pNewString ) == FALSE )
2957 return DISP_E_TYPEMISMATCH;
2960 /* Convert the valid string to a floating point number.
2962 dValue = atof( pNewString );
2964 /* We don't need the string anymore so free it.
2966 HeapFree( GetProcessHeap(), 0, pNewString );
2968 /* Check range of value.
2970 if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
2972 return DISP_E_OVERFLOW;
2975 *pfltOut = (FLOAT) dValue;
2980 /**********************************************************************
2981 * VarR4FromCy [OLEAUT32.72]
2982 * Convert currency to float
2984 HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
2985 *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2990 /******************************************************************************
2991 * VarR8FromUI1 [OLEAUT32.78]
2993 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
2995 TRACE("( %d, %p ), stub\n", bIn, pdblOut );
2997 *pdblOut = (double) bIn;
3002 /******************************************************************************
3003 * VarR8FromI2 [OLEAUT32.79]
3005 HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
3007 TRACE("( %d, %p ), stub\n", sIn, pdblOut );
3009 *pdblOut = (double) sIn;
3014 /******************************************************************************
3015 * VarR8FromI4 [OLEAUT32.80]
3017 HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
3019 TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
3021 *pdblOut = (double) lIn;
3026 /******************************************************************************
3027 * VarR8FromR4 [OLEAUT32.81]
3029 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
3031 TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
3033 *pdblOut = (double) fltIn;
3038 /******************************************************************************
3039 * VarR8FromDate [OLEAUT32.83]
3041 HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
3043 TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
3045 *pdblOut = (double) dateIn;
3050 /******************************************************************************
3051 * VarR8FromBool [OLEAUT32.86]
3053 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
3055 TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
3057 *pdblOut = (double) boolIn;
3062 /******************************************************************************
3063 * VarR8FromI1 [OLEAUT32.217]
3065 HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
3067 TRACE("( %c, %p ), stub\n", cIn, pdblOut );
3069 *pdblOut = (double) cIn;
3074 /******************************************************************************
3075 * VarR8FromUI2 [OLEAUT32.218]
3077 HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
3079 TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
3081 *pdblOut = (double) uiIn;
3086 /******************************************************************************
3087 * VarR8FromUI4 [OLEAUT32.219]
3089 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
3091 TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
3093 *pdblOut = (double) ulIn;
3098 /******************************************************************************
3099 * VarR8FromStr [OLEAUT32.84]
3101 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
3103 double dValue = 0.0;
3104 LPSTR pNewString = NULL;
3106 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3107 TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString, lcid, dwFlags, pdblOut );
3109 /* Check if we have a valid argument
3111 RemoveCharacterFromString( pNewString, "," );
3112 if( IsValidRealString( pNewString ) == FALSE )
3114 return DISP_E_TYPEMISMATCH;
3117 /* Convert the valid string to a floating point number.
3119 dValue = atof( pNewString );
3121 /* We don't need the string anymore so free it.
3123 HeapFree( GetProcessHeap(), 0, pNewString );
3130 /**********************************************************************
3131 * VarR8FromCy [OLEAUT32.82]
3132 * Convert currency to double
3134 HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
3135 *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3136 TRACE("%lu %ld -> %f\n", cyIn.s.Hi, cyIn.s.Lo, *pdblOut);
3140 /******************************************************************************
3141 * VarDateFromUI1 [OLEAUT32.88]
3143 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
3145 TRACE("( %d, %p ), stub\n", bIn, pdateOut );
3147 *pdateOut = (DATE) bIn;
3152 /******************************************************************************
3153 * VarDateFromI2 [OLEAUT32.89]
3155 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
3157 TRACE("( %d, %p ), stub\n", sIn, pdateOut );
3159 *pdateOut = (DATE) sIn;
3164 /******************************************************************************
3165 * VarDateFromI4 [OLEAUT32.90]
3167 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3169 TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
3171 if( lIn < DATE_MIN || lIn > DATE_MAX )
3173 return DISP_E_OVERFLOW;
3176 *pdateOut = (DATE) lIn;
3181 /******************************************************************************
3182 * VarDateFromR4 [OLEAUT32.91]
3184 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3186 TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3188 if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
3190 return DISP_E_OVERFLOW;
3193 *pdateOut = (DATE) fltIn;
3198 /******************************************************************************
3199 * VarDateFromR8 [OLEAUT32.92]
3201 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3203 TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3205 if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3207 return DISP_E_OVERFLOW;
3210 *pdateOut = (DATE) dblIn;
3215 /******************************************************************************
3216 * VarDateFromStr [OLEAUT32.94]
3217 * The string representing the date is composed of two parts, a date and time.
3219 * The format of the time is has follows:
3220 * hh[:mm][:ss][AM|PM]
3221 * Whitespace can be inserted anywhere between these tokens. A whitespace consists
3222 * of space and/or tab characters, which are ignored.
3224 * The formats for the date part are has follows:
3228 * January dd[,] [yy]yy
3231 * Whitespace can be inserted anywhere between these tokens.
3233 * The formats for the date and time string are has follows.
3234 * date[whitespace][time]
3235 * [time][whitespace]date
3237 * These are the only characters allowed in a string representing a date and time:
3238 * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3240 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3245 memset( &TM, 0, sizeof(TM) );
3247 TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3249 if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
3251 if( TmToDATE( &TM, pdateOut ) == FALSE )
3258 ret = DISP_E_TYPEMISMATCH;
3260 TRACE("Return value %f\n", *pdateOut);
3264 /******************************************************************************
3265 * VarDateFromI1 [OLEAUT32.221]
3267 HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
3269 TRACE("( %c, %p ), stub\n", cIn, pdateOut );
3271 *pdateOut = (DATE) cIn;
3276 /******************************************************************************
3277 * VarDateFromUI2 [OLEAUT32.222]
3279 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3281 TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
3283 if( uiIn > DATE_MAX )
3285 return DISP_E_OVERFLOW;
3288 *pdateOut = (DATE) uiIn;
3293 /******************************************************************************
3294 * VarDateFromUI4 [OLEAUT32.223]
3296 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3298 TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
3300 if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3302 return DISP_E_OVERFLOW;
3305 *pdateOut = (DATE) ulIn;
3310 /******************************************************************************
3311 * VarDateFromBool [OLEAUT32.96]
3313 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3315 TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
3317 *pdateOut = (DATE) boolIn;
3322 /**********************************************************************
3323 * VarDateFromCy [OLEAUT32.93]
3324 * Convert currency to date
3326 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
3327 *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3329 if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3333 /******************************************************************************
3334 * VarBstrFromUI1 [OLEAUT32.108]
3336 HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3338 TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3339 sprintf( pBuffer, "%d", bVal );
3341 *pbstrOut = StringDupAtoBstr( pBuffer );
3346 /******************************************************************************
3347 * VarBstrFromI2 [OLEAUT32.109]
3349 HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3351 TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3352 sprintf( pBuffer, "%d", iVal );
3353 *pbstrOut = StringDupAtoBstr( pBuffer );
3358 /******************************************************************************
3359 * VarBstrFromI4 [OLEAUT32.110]
3361 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3363 TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
3365 sprintf( pBuffer, "%ld", lIn );
3366 *pbstrOut = StringDupAtoBstr( pBuffer );
3371 /******************************************************************************
3372 * VarBstrFromR4 [OLEAUT32.111]
3374 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3376 TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
3378 sprintf( pBuffer, "%.7g", fltIn );
3379 *pbstrOut = StringDupAtoBstr( pBuffer );
3384 /******************************************************************************
3385 * VarBstrFromR8 [OLEAUT32.112]
3387 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3389 TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
3391 sprintf( pBuffer, "%.15g", dblIn );
3392 *pbstrOut = StringDupAtoBstr( pBuffer );
3397 /******************************************************************************
3398 * VarBstrFromCy [OLEAUT32.113]
3400 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
3402 double curVal = 0.0;
3404 TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid, dwFlags, pbstrOut);
3406 /* Firstly get the currency in a double, then put it in a buffer */
3407 rc = VarR8FromCy(cyIn, &curVal);
3409 sprintf(pBuffer, "%g", curVal);
3410 *pbstrOut = StringDupAtoBstr( pBuffer );
3416 /******************************************************************************
3417 * VarBstrFromDate [OLEAUT32.114]
3419 * The date is implemented using an 8 byte floating-point number.
3420 * Days are represented by whole numbers increments starting with 0.00 as
3421 * being December 30 1899, midnight.
3422 * The hours are expressed as the fractional part of the number.
3423 * December 30 1899 at midnight = 0.00
3424 * January 1 1900 at midnight = 2.00
3425 * January 4 1900 at 6 AM = 5.25
3426 * January 4 1900 at noon = 5.50
3427 * December 29 1899 at midnight = -1.00
3428 * December 18 1899 at midnight = -12.00
3429 * December 18 1899 at 6AM = -12.25
3430 * December 18 1899 at 6PM = -12.75
3431 * December 19 1899 at midnight = -11.00
3432 * The tm structure is as follows:
3434 * int tm_sec; seconds after the minute - [0,59]
3435 * int tm_min; minutes after the hour - [0,59]
3436 * int tm_hour; hours since midnight - [0,23]
3437 * int tm_mday; day of the month - [1,31]
3438 * int tm_mon; months since January - [0,11]
3439 * int tm_year; years
3440 * int tm_wday; days since Sunday - [0,6]
3441 * int tm_yday; days since January 1 - [0,365]
3442 * int tm_isdst; daylight savings time flag
3445 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3448 memset( &TM, 0, sizeof(TM) );
3450 TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
3452 if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
3454 return E_INVALIDARG;
3457 if( dwFlags & VAR_DATEVALUEONLY )
3458 strftime( pBuffer, BUFFER_MAX, "%x", &TM );
3459 else if( dwFlags & VAR_TIMEVALUEONLY )
3460 strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3462 strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3464 TRACE("result: %s\n", pBuffer);
3465 *pbstrOut = StringDupAtoBstr( pBuffer );
3469 /******************************************************************************
3470 * VarBstrFromBool [OLEAUT32.116]
3472 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3474 TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
3476 sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
3478 *pbstrOut = StringDupAtoBstr( pBuffer );
3483 /******************************************************************************
3484 * VarBstrFromI1 [OLEAUT32.229]
3486 HRESULT WINAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3488 TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3489 sprintf( pBuffer, "%d", cIn );
3490 *pbstrOut = StringDupAtoBstr( pBuffer );
3495 /******************************************************************************
3496 * VarBstrFromUI2 [OLEAUT32.230]
3498 HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3500 TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3501 sprintf( pBuffer, "%d", uiIn );
3502 *pbstrOut = StringDupAtoBstr( pBuffer );
3507 /******************************************************************************
3508 * VarBstrFromUI4 [OLEAUT32.231]
3510 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3512 TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3513 sprintf( pBuffer, "%ld", ulIn );
3514 *pbstrOut = StringDupAtoBstr( pBuffer );
3519 /******************************************************************************
3520 * VarBoolFromUI1 [OLEAUT32.118]
3522 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3524 TRACE("( %d, %p ), stub\n", bIn, pboolOut );
3528 *pboolOut = VARIANT_FALSE;
3532 *pboolOut = VARIANT_TRUE;
3538 /******************************************************************************
3539 * VarBoolFromI2 [OLEAUT32.119]
3541 HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3543 TRACE("( %d, %p ), stub\n", sIn, pboolOut );
3545 *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
3550 /******************************************************************************
3551 * VarBoolFromI4 [OLEAUT32.120]
3553 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3555 TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
3557 *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
3562 /******************************************************************************
3563 * VarBoolFromR4 [OLEAUT32.121]
3565 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3567 TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
3569 *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3574 /******************************************************************************
3575 * VarBoolFromR8 [OLEAUT32.122]
3577 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3579 TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
3581 *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3586 /******************************************************************************
3587 * VarBoolFromDate [OLEAUT32.123]
3589 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3591 TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
3593 *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3598 /******************************************************************************
3599 * VarBoolFromStr [OLEAUT32.125]
3601 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3604 char* pNewString = NULL;
3606 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
3608 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3610 if( pNewString == NULL || strlen( pNewString ) == 0 )
3612 ret = DISP_E_TYPEMISMATCH;
3617 if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
3619 *pboolOut = VARIANT_TRUE;
3621 else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
3623 *pboolOut = VARIANT_FALSE;
3627 /* Try converting the string to a floating point number.
3629 double dValue = 0.0;
3630 HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3633 ret = DISP_E_TYPEMISMATCH;
3636 *pboolOut = (dValue == 0.0) ?
3637 VARIANT_FALSE : VARIANT_TRUE;
3641 HeapFree( GetProcessHeap(), 0, pNewString );
3646 /******************************************************************************
3647 * VarBoolFromI1 [OLEAUT32.233]
3649 HRESULT WINAPI VarBoolFromI1(CHAR cIn, VARIANT_BOOL* pboolOut)
3651 TRACE("( %c, %p ), stub\n", cIn, pboolOut );
3653 *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3658 /******************************************************************************
3659 * VarBoolFromUI2 [OLEAUT32.234]
3661 HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3663 TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
3665 *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3670 /******************************************************************************
3671 * VarBoolFromUI4 [OLEAUT32.235]
3673 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3675 TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
3677 *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3682 /**********************************************************************
3683 * VarBoolFromCy [OLEAUT32.124]
3684 * Convert currency to boolean
3686 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
3687 if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
3693 /******************************************************************************
3694 * VarI1FromUI1 [OLEAUT32.244]
3696 HRESULT WINAPI VarI1FromUI1(BYTE bIn, CHAR* pcOut)
3698 TRACE("( %d, %p ), stub\n", bIn, pcOut );
3700 /* Check range of value.
3702 if( bIn > CHAR_MAX )
3704 return DISP_E_OVERFLOW;
3707 *pcOut = (CHAR) bIn;
3712 /******************************************************************************
3713 * VarI1FromI2 [OLEAUT32.245]
3715 HRESULT WINAPI VarI1FromI2(short uiIn, CHAR* pcOut)
3717 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3719 if( uiIn > CHAR_MAX )
3721 return DISP_E_OVERFLOW;
3724 *pcOut = (CHAR) uiIn;
3729 /******************************************************************************
3730 * VarI1FromI4 [OLEAUT32.246]
3732 HRESULT WINAPI VarI1FromI4(LONG lIn, CHAR* pcOut)
3734 TRACE("( %ld, %p ), stub\n", lIn, pcOut );
3736 if( lIn < CHAR_MIN || lIn > CHAR_MAX )
3738 return DISP_E_OVERFLOW;
3741 *pcOut = (CHAR) lIn;
3746 /******************************************************************************
3747 * VarI1FromR4 [OLEAUT32.247]
3749 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, CHAR* pcOut)
3751 TRACE("( %f, %p ), stub\n", fltIn, pcOut );
3753 fltIn = round( fltIn );
3754 if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
3756 return DISP_E_OVERFLOW;
3759 *pcOut = (CHAR) fltIn;
3764 /******************************************************************************
3765 * VarI1FromR8 [OLEAUT32.248]
3767 HRESULT WINAPI VarI1FromR8(double dblIn, CHAR* pcOut)
3769 TRACE("( %f, %p ), stub\n", dblIn, pcOut );
3771 dblIn = round( dblIn );
3772 if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
3774 return DISP_E_OVERFLOW;
3777 *pcOut = (CHAR) dblIn;
3782 /******************************************************************************
3783 * VarI1FromDate [OLEAUT32.249]
3785 HRESULT WINAPI VarI1FromDate(DATE dateIn, CHAR* pcOut)
3787 TRACE("( %f, %p ), stub\n", dateIn, pcOut );
3789 dateIn = round( dateIn );
3790 if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
3792 return DISP_E_OVERFLOW;
3795 *pcOut = (CHAR) dateIn;
3800 /******************************************************************************
3801 * VarI1FromStr [OLEAUT32.251]
3803 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CHAR* pcOut)
3805 double dValue = 0.0;
3806 LPSTR pNewString = NULL;
3808 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
3810 /* Check if we have a valid argument
3812 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3813 RemoveCharacterFromString( pNewString, "," );
3814 if( IsValidRealString( pNewString ) == FALSE )
3816 return DISP_E_TYPEMISMATCH;
3819 /* Convert the valid string to a floating point number.
3821 dValue = atof( pNewString );
3823 /* We don't need the string anymore so free it.
3825 HeapFree( GetProcessHeap(), 0, pNewString );
3827 /* Check range of value.
3829 dValue = round( dValue );
3830 if( dValue < CHAR_MIN || dValue > CHAR_MAX )
3832 return DISP_E_OVERFLOW;
3835 *pcOut = (CHAR) dValue;
3840 /******************************************************************************
3841 * VarI1FromBool [OLEAUT32.253]
3843 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
3845 TRACE("( %d, %p ), stub\n", boolIn, pcOut );
3847 *pcOut = (CHAR) boolIn;
3852 /******************************************************************************
3853 * VarI1FromUI2 [OLEAUT32.254]
3855 HRESULT WINAPI VarI1FromUI2(USHORT uiIn, CHAR* pcOut)
3857 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3859 if( uiIn > CHAR_MAX )
3861 return DISP_E_OVERFLOW;
3864 *pcOut = (CHAR) uiIn;
3869 /******************************************************************************
3870 * VarI1FromUI4 [OLEAUT32.255]
3872 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, CHAR* pcOut)
3874 TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
3876 if( ulIn > CHAR_MAX )
3878 return DISP_E_OVERFLOW;
3881 *pcOut = (CHAR) ulIn;
3886 /**********************************************************************
3887 * VarI1FromCy [OLEAUT32.250]
3888 * Convert currency to signed char
3890 HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
3891 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3893 if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
3899 /******************************************************************************
3900 * VarUI2FromUI1 [OLEAUT32.257]
3902 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
3904 TRACE("( %d, %p ), stub\n", bIn, puiOut );
3906 *puiOut = (USHORT) bIn;
3911 /******************************************************************************
3912 * VarUI2FromI2 [OLEAUT32.258]
3914 HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
3916 TRACE("( %d, %p ), stub\n", uiIn, puiOut );
3918 if( uiIn < UI2_MIN )
3920 return DISP_E_OVERFLOW;
3923 *puiOut = (USHORT) uiIn;
3928 /******************************************************************************
3929 * VarUI2FromI4 [OLEAUT32.259]
3931 HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
3933 TRACE("( %ld, %p ), stub\n", lIn, puiOut );
3935 if( lIn < UI2_MIN || lIn > UI2_MAX )
3937 return DISP_E_OVERFLOW;
3940 *puiOut = (USHORT) lIn;
3945 /******************************************************************************
3946 * VarUI2FromR4 [OLEAUT32.260]
3948 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
3950 TRACE("( %f, %p ), stub\n", fltIn, puiOut );
3952 fltIn = round( fltIn );
3953 if( fltIn < UI2_MIN || fltIn > UI2_MAX )
3955 return DISP_E_OVERFLOW;
3958 *puiOut = (USHORT) fltIn;
3963 /******************************************************************************
3964 * VarUI2FromR8 [OLEAUT32.261]
3966 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
3968 TRACE("( %f, %p ), stub\n", dblIn, puiOut );
3970 dblIn = round( dblIn );
3971 if( dblIn < UI2_MIN || dblIn > UI2_MAX )
3973 return DISP_E_OVERFLOW;
3976 *puiOut = (USHORT) dblIn;
3981 /******************************************************************************
3982 * VarUI2FromDate [OLEAUT32.262]
3984 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
3986 TRACE("( %f, %p ), stub\n", dateIn, puiOut );
3988 dateIn = round( dateIn );
3989 if( dateIn < UI2_MIN || dateIn > UI2_MAX )
3991 return DISP_E_OVERFLOW;
3994 *puiOut = (USHORT) dateIn;
3999 /******************************************************************************
4000 * VarUI2FromStr [OLEAUT32.264]
4002 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
4004 double dValue = 0.0;
4005 LPSTR pNewString = NULL;
4007 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
4009 /* Check if we have a valid argument
4011 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4012 RemoveCharacterFromString( pNewString, "," );
4013 if( IsValidRealString( pNewString ) == FALSE )
4015 return DISP_E_TYPEMISMATCH;
4018 /* Convert the valid string to a floating point number.
4020 dValue = atof( pNewString );
4022 /* We don't need the string anymore so free it.
4024 HeapFree( GetProcessHeap(), 0, pNewString );
4026 /* Check range of value.
4028 dValue = round( dValue );
4029 if( dValue < UI2_MIN || dValue > UI2_MAX )
4031 return DISP_E_OVERFLOW;
4034 *puiOut = (USHORT) dValue;
4039 /******************************************************************************
4040 * VarUI2FromBool [OLEAUT32.266]
4042 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
4044 TRACE("( %d, %p ), stub\n", boolIn, puiOut );
4046 *puiOut = (USHORT) boolIn;
4051 /******************************************************************************
4052 * VarUI2FromI1 [OLEAUT32.267]
4054 HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
4056 TRACE("( %c, %p ), stub\n", cIn, puiOut );
4058 *puiOut = (USHORT) cIn;
4063 /******************************************************************************
4064 * VarUI2FromUI4 [OLEAUT32.268]
4066 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
4068 TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
4070 if( ulIn > UI2_MAX )
4072 return DISP_E_OVERFLOW;
4075 *puiOut = (USHORT) ulIn;
4080 /******************************************************************************
4081 * VarUI4FromStr [OLEAUT32.277]
4083 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
4085 double dValue = 0.0;
4086 LPSTR pNewString = NULL;
4088 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
4090 /* Check if we have a valid argument
4092 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4093 RemoveCharacterFromString( pNewString, "," );
4094 if( IsValidRealString( pNewString ) == FALSE )
4096 return DISP_E_TYPEMISMATCH;
4099 /* Convert the valid string to a floating point number.
4101 dValue = atof( pNewString );
4103 /* We don't need the string anymore so free it.
4105 HeapFree( GetProcessHeap(), 0, pNewString );
4107 /* Check range of value.
4109 dValue = round( dValue );
4110 if( dValue < UI4_MIN || dValue > UI4_MAX )
4112 return DISP_E_OVERFLOW;
4115 *pulOut = (ULONG) dValue;
4120 /**********************************************************************
4121 * VarUI2FromCy [OLEAUT32.263]
4122 * Convert currency to unsigned short
4124 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
4125 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4127 if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
4129 *pusOut = (USHORT)t;
4134 /******************************************************************************
4135 * VarUI4FromUI1 [OLEAUT32.270]
4137 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
4139 TRACE("( %d, %p ), stub\n", bIn, pulOut );
4141 *pulOut = (USHORT) bIn;
4146 /******************************************************************************
4147 * VarUI4FromI2 [OLEAUT32.271]
4149 HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
4151 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4153 if( uiIn < UI4_MIN )
4155 return DISP_E_OVERFLOW;
4158 *pulOut = (ULONG) uiIn;
4163 /******************************************************************************
4164 * VarUI4FromI4 [OLEAUT32.272]
4166 HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
4168 TRACE("( %ld, %p ), stub\n", lIn, pulOut );
4172 return DISP_E_OVERFLOW;
4175 *pulOut = (ULONG) lIn;
4180 /******************************************************************************
4181 * VarUI4FromR4 [OLEAUT32.273]
4183 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
4185 fltIn = round( fltIn );
4186 if( fltIn < UI4_MIN || fltIn > UI4_MAX )
4188 return DISP_E_OVERFLOW;
4191 *pulOut = (ULONG) fltIn;
4196 /******************************************************************************
4197 * VarUI4FromR8 [OLEAUT32.274]
4199 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
4201 TRACE("( %f, %p ), stub\n", dblIn, pulOut );
4203 dblIn = round( dblIn );
4204 if( dblIn < UI4_MIN || dblIn > UI4_MAX )
4206 return DISP_E_OVERFLOW;
4209 *pulOut = (ULONG) dblIn;
4214 /******************************************************************************
4215 * VarUI4FromDate [OLEAUT32.275]
4217 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
4219 TRACE("( %f, %p ), stub\n", dateIn, pulOut );
4221 dateIn = round( dateIn );
4222 if( dateIn < UI4_MIN || dateIn > UI4_MAX )
4224 return DISP_E_OVERFLOW;
4227 *pulOut = (ULONG) dateIn;
4232 /******************************************************************************
4233 * VarUI4FromBool [OLEAUT32.279]
4235 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
4237 TRACE("( %d, %p ), stub\n", boolIn, pulOut );
4239 *pulOut = (ULONG) boolIn;
4244 /******************************************************************************
4245 * VarUI4FromI1 [OLEAUT32.280]
4247 HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
4249 TRACE("( %c, %p ), stub\n", cIn, pulOut );
4251 *pulOut = (ULONG) cIn;
4256 /******************************************************************************
4257 * VarUI4FromUI2 [OLEAUT32.281]
4259 HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4261 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4263 *pulOut = (ULONG) uiIn;
4268 /**********************************************************************
4269 * VarUI4FromCy [OLEAUT32.276]
4270 * Convert currency to unsigned long
4272 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
4273 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4275 if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4282 /**********************************************************************
4283 * VarCyFromUI1 [OLEAUT32.98]
4284 * Convert unsigned char to currency
4286 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
4288 pcyOut->s.Lo = ((ULONG)bIn) * 10000;
4293 /**********************************************************************
4294 * VarCyFromI2 [OLEAUT32.99]
4295 * Convert signed short to currency
4297 HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
4298 if (sIn < 0) pcyOut->s.Hi = -1;
4299 else pcyOut->s.Hi = 0;
4300 pcyOut->s.Lo = ((ULONG)sIn) * 10000;
4305 /**********************************************************************
4306 * VarCyFromI4 [OLEAUT32.100]
4307 * Convert signed long to currency
4309 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4310 double t = (double)lIn * (double)10000;
4311 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4312 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4313 if (lIn < 0) pcyOut->s.Hi--;
4318 /**********************************************************************
4319 * VarCyFromR4 [OLEAUT32.101]
4320 * Convert float to currency
4322 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
4323 double t = round((double)fltIn * (double)10000);
4324 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4325 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4326 if (fltIn < 0) pcyOut->s.Hi--;
4331 /**********************************************************************
4332 * VarCyFromR8 [OLEAUT32.102]
4333 * Convert double to currency
4335 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
4336 double t = round(dblIn * (double)10000);
4337 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4338 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4339 if (dblIn < 0) pcyOut->s.Hi--;
4344 /**********************************************************************
4345 * VarCyFromDate [OLEAUT32.103]
4346 * Convert date to currency
4348 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
4349 double t = round((double)dateIn * (double)10000);
4350 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4351 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4352 if (dateIn < 0) pcyOut->s.Hi--;
4357 /**********************************************************************
4358 * VarCyFromStr [OLEAUT32.104]
4359 * FIXME: Never tested with decimal seperator other than '.'
4361 HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
4363 LPSTR pNewString = NULL;
4364 char *decSep = NULL;
4365 char *strPtr,*curPtr = NULL;
4367 double currencyVal = 0.0;
4370 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4371 TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString, lcid, dwFlags, pcyOut );
4373 /* Get locale information - Decimal Seperator (size includes 0x00) */
4374 size = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, NULL, 0);
4375 decSep = (char *) malloc(size);
4376 rc = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, decSep, size);
4377 TRACE("Decimal Seperator is '%s'\n", decSep);
4379 /* Now copy to temporary buffer, skipping any character except 0-9 and
4380 the decimal seperator */
4381 curPtr = pBuffer; /* Current position in string being built */
4382 strPtr = pNewString; /* Current position in supplied currenct string */
4385 /* If decimal seperator, skip it and put '.' in string */
4386 if (strncmp(strPtr, decSep, (size-1)) == 0) {
4387 strPtr = strPtr + (size-1);
4390 } else if ((*strPtr == '+' || *strPtr == '-') ||
4391 (*strPtr >= '0' && *strPtr <= '9')) {
4399 /* Try to get currency into a double */
4400 currencyVal = atof(pBuffer);
4401 TRACE("Converted string '%s' to %f\n", pBuffer, currencyVal);
4403 /* Free allocated storage */
4404 HeapFree( GetProcessHeap(), 0, pNewString );
4407 /* Convert double -> currency using internal routine */
4408 return VarCyFromR8(currencyVal, pcyOut);
4412 /**********************************************************************
4413 * VarCyFromBool [OLEAUT32.106]
4414 * Convert boolean to currency
4416 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
4417 if (boolIn < 0) pcyOut->s.Hi = -1;
4418 else pcyOut->s.Hi = 0;
4419 pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
4424 /**********************************************************************
4425 * VarCyFromI1 [OLEAUT32.225]
4426 * Convert signed char to currency
4428 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
4429 if (cIn < 0) pcyOut->s.Hi = -1;
4430 else pcyOut->s.Hi = 0;
4431 pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
4436 /**********************************************************************
4437 * VarCyFromUI2 [OLEAUT32.226]
4438 * Convert unsigned short to currency
4440 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
4442 pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
4447 /**********************************************************************
4448 * VarCyFromUI4 [OLEAUT32.227]
4449 * Convert unsigned long to currency
4451 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4452 double t = (double)ulIn * (double)10000;
4453 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4454 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4460 /**********************************************************************
4461 * DosDateTimeToVariantTime [OLEAUT32.14]
4462 * Convert dos representation of time to the date and time representation
4463 * stored in a variant.
4465 INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4470 TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
4472 t.tm_sec = (wDosTime & 0x001f) * 2;
4473 t.tm_min = (wDosTime & 0x07e0) >> 5;
4474 t.tm_hour = (wDosTime & 0xf800) >> 11;
4476 t.tm_mday = (wDosDate & 0x001f);
4477 t.tm_mon = (wDosDate & 0x01e0) >> 5;
4478 t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
4480 return TmToDATE( &t, pvtime );
4484 /**********************************************************************
4485 * VarParseNumFromStr [OLEAUT32.46]
4487 HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
4488 NUMPARSE * pnumprs, BYTE * rgbDig)
4492 BOOL foundNum=FALSE;
4494 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
4495 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
4497 /* The other struct components are to be set by us */
4498 memset(rgbDig,0,pnumprs->cDig);
4500 /* FIXME: Just patching some values in */
4501 pnumprs->nPwr10 = 0;
4502 pnumprs->nBaseShift = 0;
4503 pnumprs->cchUsed = lastent;
4504 pnumprs->dwOutFlags = NUMPRS_DECIMAL;
4507 for (i=0; strIn[i] ;i++) {
4508 if ((strIn[i]>='0') && (strIn[i]<='9')) {
4510 if (pnumprs->cDig > cDig) {
4511 *(rgbDig++)=strIn[i]-'0';
4515 } else if ((strIn[i]=='-') && (foundNum==FALSE)) {
4516 pnumprs->dwOutFlags |= NUMPRS_NEG;
4519 pnumprs->cDig = cDig;
4520 TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags);
4525 /**********************************************************************
4526 * VarNumFromParseNum [OLEAUT32.47]
4528 HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
4529 ULONG dwVtBits, VARIANT * pvar)
4533 FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
4536 for (i=0;i<pnumprs->cDig;i++)
4537 xint = xint*10 + rgbDig[i];
4539 if (pnumprs->dwOutFlags & NUMPRS_NEG) {
4544 if (dwVtBits & VTBIT_I4) {
4546 V_UNION(pvar,intVal) = xint;
4549 if (dwVtBits & VTBIT_R8) {
4551 V_UNION(pvar,dblVal) = xint;
4554 if (dwVtBits & VTBIT_R4) {
4556 V_UNION(pvar,fltVal) = xint;
4559 if (dwVtBits & VTBIT_I2) {
4561 V_UNION(pvar,iVal) = xint;
4564 /* FIXME: Currency should be from a double */
4565 if (dwVtBits & VTBIT_CY) {
4567 TRACE("Calculated currency is xint=%ld\n", xint);
4568 VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4569 TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar,cyVal).s.Hi, V_UNION(pvar,cyVal).s.Lo);
4570 return VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
4573 FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint);
4578 /**********************************************************************
4579 * VarFormatDateTime [OLEAUT32.97]
4581 HRESULT WINAPI VarFormatDateTime(LPVARIANT var, INT format, ULONG dwFlags, BSTR *out)
4583 FIXME("%p %d %lx %p\n", var, format, dwFlags, out);
4587 /**********************************************************************
4588 * VarFormatCurrency [OLEAUT32.127]
4590 HRESULT WINAPI VarFormatCurrency(LPVARIANT var, INT digits, INT lead, INT paren, INT group, ULONG dwFlags, BSTR *out)
4592 FIXME("%p %d %d %d %d %lx %p\n", var, digits, lead, paren, group, dwFlags, out);
4596 /**********************************************************************
4597 * VariantTimeToDosDateTime [OLEAUT32.13]
4598 * Convert variant representation of time to the date and time representation
4601 INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
4607 TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate, *wDosTime, &pvtime );
4609 if (DateToTm(pvtime, 0, &t) < 0) return 0;
4611 *wDosTime = *wDosTime | (t.tm_sec / 2);
4612 *wDosTime = *wDosTime | (t.tm_min << 5);
4613 *wDosTime = *wDosTime | (t.tm_hour << 11);
4615 *wDosDate = *wDosDate | t.tm_mday ;
4616 *wDosDate = *wDosDate | t.tm_mon << 5;
4617 *wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
4623 /***********************************************************************
4624 * SystemTimeToVariantTime [OLEAUT32.184]
4626 HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime, double *pvtime )
4630 TRACE(" %d/%d/%d %d:%d:%d\n",
4631 lpSystemTime->wMonth, lpSystemTime->wDay,
4632 lpSystemTime->wYear, lpSystemTime->wHour,
4633 lpSystemTime->wMinute, lpSystemTime->wSecond);
4635 if (lpSystemTime->wYear >= 1900)
4637 t.tm_sec = lpSystemTime->wSecond;
4638 t.tm_min = lpSystemTime->wMinute;
4639 t.tm_hour = lpSystemTime->wHour;
4641 t.tm_mday = lpSystemTime->wDay;
4642 t.tm_mon = lpSystemTime->wMonth - 1; /* tm_mon is 0..11, wMonth is 1..12 */
4643 t.tm_year = lpSystemTime->wYear;
4645 return TmToDATE( &t, pvtime );
4650 long firstDayOfNextYear;
4655 double decimalPart = 0.0;
4657 t.tm_sec = lpSystemTime->wSecond;
4658 t.tm_min = lpSystemTime->wMinute;
4659 t.tm_hour = lpSystemTime->wHour;
4661 /* Step year forward the same number of years before 1900 */
4662 t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
4663 t.tm_mon = lpSystemTime->wMonth - 1;
4664 t.tm_mday = lpSystemTime->wDay;
4666 /* Calculate date */
4667 TmToDATE( &t, pvtime );
4669 thisDay = (double) floor( *pvtime );
4670 decimalPart = fmod( *pvtime, thisDay );
4672 /* Now, calculate the same time for the first of Jan that year */
4678 t.tm_year = t.tm_year+1;
4679 TmToDATE( &t, &tmpDate );
4680 firstDayOfNextYear = (long) floor(tmpDate);
4682 /* Finally since we know the size of the year, subtract the two to get
4683 remaining time in the year */
4684 leftInYear = firstDayOfNextYear - thisDay;
4686 /* Now we want full years up to the year in question, and remainder of year
4687 of the year in question */
4688 if (isleap(lpSystemTime->wYear) ) {
4689 TRACE("Extra day due to leap year\n");
4690 result = 2.0 - ((firstDayOfNextYear - 366) + leftInYear - 2.0);
4692 result = 2.0 - ((firstDayOfNextYear - 365) + leftInYear - 2.0);
4694 *pvtime = (double) result + decimalPart;
4695 TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime, firstDayOfNextYear, thisDay, leftInYear);
4703 /***********************************************************************
4704 * VariantTimeToSystemTime [OLEAUT32.185]
4706 HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME lpSystemTime )
4708 double t = 0, timeofday = 0;
4710 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4711 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4713 /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4714 static const BYTE Month_Code[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4715 static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4717 /* The Century_Code is used to find the Day of the Week */
4718 static const BYTE Century_Code[] = {0, 6, 4, 2};
4722 TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime);
4727 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4729 lpSystemTime->wSecond = r.tm_sec;
4730 lpSystemTime->wMinute = r.tm_min;
4731 lpSystemTime->wHour = r.tm_hour;
4732 lpSystemTime->wDay = r.tm_mday;
4733 lpSystemTime->wMonth = r.tm_mon;
4735 if (lpSystemTime->wMonth == 12)
4736 lpSystemTime->wMonth = 1;
4738 lpSystemTime->wMonth++;
4740 lpSystemTime->wYear = r.tm_year;
4746 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4748 lpSystemTime->wSecond = r.tm_sec;
4749 lpSystemTime->wMinute = r.tm_min;
4750 lpSystemTime->wHour = r.tm_hour;
4752 lpSystemTime->wMonth = 13 - r.tm_mon;
4754 if (lpSystemTime->wMonth == 1)
4755 lpSystemTime->wMonth = 12;
4757 lpSystemTime->wMonth--;
4759 lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
4761 if (!isleap(lpSystemTime->wYear) )
4762 lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
4764 lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
4769 if (!isleap(lpSystemTime->wYear))
4772 (Century_Code+Month_Code+Year_Code+Day) % 7
4774 The century code repeats every 400 years , so the array
4775 works out like this,
4777 Century_Code[0] is for 16th/20th Centry
4778 Century_Code[1] is for 17th/21th Centry
4779 Century_Code[2] is for 18th/22th Centry
4780 Century_Code[3] is for 19th/23th Centry
4782 The year code is found with the formula (year + (year / 4))
4783 the "year" must be between 0 and 99 .
4785 The Month Code (Month_Code[1]) starts with January and
4789 lpSystemTime->wDayOfWeek = (
4790 Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
4791 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4792 Month_Code[lpSystemTime->wMonth]+
4793 lpSystemTime->wDay) % 7;
4795 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4796 else lpSystemTime->wDayOfWeek -= 1;
4800 lpSystemTime->wDayOfWeek = (
4801 Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
4802 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4803 Month_Code_LY[lpSystemTime->wMonth]+
4804 lpSystemTime->wDay) % 7;
4806 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4807 else lpSystemTime->wDayOfWeek -= 1;
4811 timeofday = vtime - t;
4813 lpSystemTime->wMilliseconds = (timeofday
4814 - lpSystemTime->wHour*(1/24)
4815 - lpSystemTime->wMinute*(1/1440)
4816 - lpSystemTime->wSecond*(1/86400) )*(1/5184000);
4821 /***********************************************************************
4822 * VarUdateFromDate [OLEAUT32.331]
4824 HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
4827 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4828 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4830 TRACE("DATE = %f\n", (double)datein);
4831 i = VariantTimeToSystemTime(datein, &(pudateout->st) );
4835 pudateout->wDayOfYear = 0;
4837 if (isleap(pudateout->st.wYear))
4839 for (i =1; i<pudateout->st.wMonth; i++)
4840 pudateout->wDayOfYear += Days_Per_Month[i];
4844 for (i =1; i<pudateout->st.wMonth; i++)
4845 pudateout->wDayOfYear += Days_Per_Month_LY[i];
4848 pudateout->wDayOfYear += pudateout->st.wDay;
4849 dwFlags = 0; /*VAR_VALIDDATE*/
4856 /***********************************************************************
4857 * VarDateFromUdate [OLEAUT32.330]
4859 HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
4860 ULONG dwFlags, DATE *datein)
4864 TRACE(" %d/%d/%d %d:%d:%d\n",
4865 pudateout->st.wMonth, pudateout->st.wDay,
4866 pudateout->st.wYear, pudateout->st.wHour,
4867 pudateout->st.wMinute, pudateout->st.wSecond);
4870 i = SystemTimeToVariantTime(&(pudateout->st), &t);
4874 else return E_INVALIDARG;
4878 /**********************************************************************
4879 * VarBstrCmp [OLEAUT32.440]
4882 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4883 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4886 HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
4890 TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
4892 /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
4893 if((!left) || (!right)) {
4895 if (!left && (!right || *right==0)) return VARCMP_EQ;
4896 else if (!right && (!left || *left==0)) return VARCMP_EQ;
4897 else return VARCMP_NULL;
4900 if(flags&NORM_IGNORECASE)
4901 r = lstrcmpiW(left,right);
4903 r = lstrcmpW(left,right);
4913 /**********************************************************************
4914 * VarBstrCat [OLEAUT32.439]
4916 HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
4921 TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
4923 /* On Windows, NULL parms are still handled (as empty strings) */
4924 if (left) size=size + lstrlenW(left);
4925 if (right) size=size + lstrlenW(right);
4928 result = SysAllocStringLen(NULL, size);
4930 if (left) lstrcatW(result,left);
4931 if (right) lstrcatW(result,right);
4932 TRACE("result = %s, [%p]\n", debugstr_w(result), result);
4937 /**********************************************************************
4938 * VarCat [OLEAUT32.441]
4940 HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
4942 /* Should we VariantClear out? */
4943 /* Can we handle array, vector, by ref etc. */
4944 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL &&
4945 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
4947 V_VT(out) = VT_NULL;
4950 else if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR)
4952 V_VT(out) = VT_BSTR;
4953 VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out));
4957 FIXME ("types not supported\n");
4961 /**********************************************************************
4962 * VarCmp [OLEAUT32.442]
4965 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4966 * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4969 HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
4978 TRACE("Left Var:\n");
4980 TRACE("Right Var:\n");
4981 dump_Variant(right);
4983 /* If either are null, then return VARCMP_NULL */
4984 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL ||
4985 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
4988 /* Strings - use VarBstrCmp */
4989 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
4990 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
4991 return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags);
4994 /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
4995 Use LONGLONG to maximize ranges */
4997 switch (V_VT(left)&VT_TYPEMASK) {
4998 case VT_I1 : lVal = V_UNION(left,cVal); break;
4999 case VT_I2 : lVal = V_UNION(left,iVal); break;
5000 case VT_I4 : lVal = V_UNION(left,lVal); break;
5001 case VT_INT : lVal = V_UNION(left,lVal); break;
5002 case VT_UI1 : lVal = V_UNION(left,bVal); break;
5003 case VT_UI2 : lVal = V_UNION(left,uiVal); break;
5004 case VT_UI4 : lVal = V_UNION(left,ulVal); break;
5005 case VT_UINT : lVal = V_UNION(left,ulVal); break;
5006 default: lOk = FALSE;
5010 switch (V_VT(right)&VT_TYPEMASK) {
5011 case VT_I1 : rVal = V_UNION(right,cVal); break;
5012 case VT_I2 : rVal = V_UNION(right,iVal); break;
5013 case VT_I4 : rVal = V_UNION(right,lVal); break;
5014 case VT_INT : rVal = V_UNION(right,lVal); break;
5015 case VT_UI1 : rVal = V_UNION(right,bVal); break;
5016 case VT_UI2 : rVal = V_UNION(right,uiVal); break;
5017 case VT_UI4 : rVal = V_UNION(right,ulVal); break;
5018 case VT_UINT : rVal = V_UNION(right,ulVal); break;
5019 default: rOk = FALSE;
5025 } else if (lVal > rVal) {
5032 /* Strings - use VarBstrCmp */
5033 if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
5034 (V_VT(right)&VT_TYPEMASK) == VT_DATE) {
5036 if (floor(V_UNION(left,date)) == floor(V_UNION(right,date))) {
5037 /* Due to floating point rounding errors, calculate varDate in whole numbers) */
5038 double wholePart = 0.0;
5042 /* Get the fraction * 24*60*60 to make it into whole seconds */
5043 wholePart = (double) floor( V_UNION(left,date) );
5044 if (wholePart == 0) wholePart = 1;
5045 leftR = floor(fmod( V_UNION(left,date), wholePart ) * (24*60*60));
5047 wholePart = (double) floor( V_UNION(right,date) );
5048 if (wholePart == 0) wholePart = 1;
5049 rightR = floor(fmod( V_UNION(right,date), wholePart ) * (24*60*60));
5051 if (leftR < rightR) {
5053 } else if (leftR > rightR) {
5059 } else if (V_UNION(left,date) < V_UNION(right,date)) {
5061 } else if (V_UNION(left,date) > V_UNION(right,date)) {
5067 FIXME("VarCmp partial implementation, doesnt support these pair of variant types");
5071 /**********************************************************************
5072 * VarAnd [OLEAUT32.438]
5075 HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
5077 HRESULT rc = E_FAIL;
5080 TRACE("Left Var:\n");
5082 TRACE("Right Var:\n");
5083 dump_Variant(right);
5085 if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
5086 (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
5088 V_VT(result) = VT_BOOL;
5089 if (V_BOOL(left) && V_BOOL(right)) {
5090 V_BOOL(result) = VARIANT_TRUE;
5092 V_BOOL(result) = VARIANT_FALSE;
5097 FIXME("VarAnd stub\n");
5100 TRACE("rc=%d, Result:\n", (int) rc);
5101 dump_Variant(result);
5105 /**********************************************************************
5106 * VarNot [OLEAUT32.482]
5109 HRESULT WINAPI VarNot(LPVARIANT in, LPVARIANT result)
5111 HRESULT rc = E_FAIL;
5116 if ((V_VT(in)&VT_TYPEMASK) == VT_BOOL) {
5118 V_VT(result) = VT_BOOL;
5120 V_BOOL(result) = VARIANT_FALSE;
5122 V_BOOL(result) = VARIANT_TRUE;
5127 FIXME("VarNot stub\n");
5130 TRACE("rc=%d, Result:\n", (int) rc);
5131 dump_Variant(result);
5135 /**********************************************************************
5136 * VarTokenizeFormatString [OLEAUT32.490]
5138 * From investigation on W2K, a list is built up which is:
5140 * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
5141 * <token> - Insert appropriate token
5144 HRESULT VarTokenizeFormatString(LPOLESTR format, LPBYTE rgbTok,
5145 int cbTok, int iFirstDay, int iFirstWeek,
5146 LCID lcid, int *pcbActual) {
5149 int realLen, formatLeft;
5151 LPSTR pFormatA, pStart;
5153 BOOL insertCopy = FALSE;
5154 LPSTR copyFrom = NULL;
5156 TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format), rgbTok, cbTok,
5157 iFirstDay, iFirstWeek);
5159 /* Big enough for header? */
5160 if (cbTok < sizeof(FORMATHDR)) {
5161 return TYPE_E_BUFFERTOOSMALL;
5165 hdr = (FORMATHDR *) rgbTok;
5166 memset(hdr, 0x00, sizeof(FORMATHDR));
5167 hdr->hex3 = 0x03; /* No idea what these are */
5170 /* Start parsing string */
5171 realLen = sizeof(FORMATHDR);
5172 pData = rgbTok + realLen;
5173 pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5175 formatLeft = strlen(pFormatA);
5177 /* Work through the format */
5178 while (*pFormatA != 0x00) {
5181 while (checkStr>=0 && (formatTokens[checkStr].tokenSize != 0x00)) {
5182 if (formatLeft >= formatTokens[checkStr].tokenSize &&
5183 strncmp(formatTokens[checkStr].str, pFormatA,
5184 formatTokens[checkStr].tokenSize) == 0) {
5185 TRACE("match on '%s'\n", formatTokens[checkStr].str);
5189 /* If we have skipped chars, insert the copy */
5190 if (insertCopy == TRUE) {
5192 if ((realLen + 3) > cbTok) {
5193 HeapFree( GetProcessHeap(), 0, pFormatA );
5194 return TYPE_E_BUFFERTOOSMALL;
5199 *pData = (BYTE)(copyFrom - pStart);
5201 *pData = (BYTE)(pFormatA - copyFrom);
5203 realLen = realLen + 3;
5207 /* Now insert the token itself */
5208 if ((realLen + 1) > cbTok) {
5209 HeapFree( GetProcessHeap(), 0, pFormatA );
5210 return TYPE_E_BUFFERTOOSMALL;
5212 *pData = formatTokens[checkStr].tokenId;
5214 realLen = realLen + 1;
5216 pFormatA = pFormatA + formatTokens[checkStr].tokenSize;
5217 formatLeft = formatLeft - formatTokens[checkStr].tokenSize;
5218 checkStr = -1; /* Flag as found and break out of while loop */
5224 /* Did we ever match a token? */
5225 if (checkStr != -1 && insertCopy == FALSE) {
5226 TRACE("No match - need to insert copy from %p [%p]\n", pFormatA, pStart);
5228 copyFrom = pFormatA;
5229 } else if (checkStr != -1) {
5230 pFormatA = pFormatA + 1;
5235 /* Finally, if we have skipped chars, insert the copy */
5236 if (insertCopy == TRUE) {
5238 TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom, pStart, pFormatA);
5239 if ((realLen + 3) > cbTok) {
5240 HeapFree( GetProcessHeap(), 0, pFormatA );
5241 return TYPE_E_BUFFERTOOSMALL;
5246 *pData = (BYTE)(copyFrom - pStart);
5248 *pData = (BYTE)(pFormatA - copyFrom);
5250 realLen = realLen + 3;
5253 /* Finally insert the terminator */
5254 if ((realLen + 1) > cbTok) {
5255 HeapFree( GetProcessHeap(), 0, pFormatA );
5256 return TYPE_E_BUFFERTOOSMALL;
5259 realLen = realLen + 1;
5261 /* Finally fill in the length */
5263 *pcbActual = realLen;
5267 for (i=0; i<realLen; i=i+0x10) {
5268 printf(" %4.4x : ", i);
5269 for (j=0; j<0x10 && (i+j < realLen); j++) {
5270 printf("%2.2x ", rgbTok[i+j]);
5276 HeapFree( GetProcessHeap(), 0, pFormatA );
5281 /**********************************************************************
5282 * VarFormatFromTokens [OLEAUT32.472]
5283 * FIXME: No account of flags or iFirstDay etc
5285 HRESULT VarFormatFromTokens(LPVARIANT varIn, LPOLESTR format,
5286 LPBYTE pbTokCur, ULONG dwFlags, BSTR *pbstrOut,
5289 FORMATHDR *hdr = (FORMATHDR *)pbTokCur;
5290 BYTE *pData = pbTokCur + sizeof (FORMATHDR);
5291 LPSTR pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5292 char output[BUFFER_MAX];
5294 int size, whichToken;
5300 TRACE("'%s', %p %lx %p only date support\n", pFormatA, pbTokCur, dwFlags, pbstrOut);
5302 dump_Variant(varIn);
5304 memset(output, 0x00, BUFFER_MAX);
5307 while (*pData != TOK_END && ((pData - pbTokCur) <= (hdr->len))) {
5309 TRACE("Output looks like : '%s'\n", output);
5311 /* Convert varient to appropriate data type */
5313 while ((formatTokens[whichToken].tokenSize != 0x00) &&
5314 (formatTokens[whichToken].tokenId != *pData)) {
5318 /* Use Variant local from here downwards as always correct type */
5319 if (formatTokens[whichToken].tokenSize > 0 &&
5320 formatTokens[whichToken].varTypeRequired != 0) {
5321 VariantInit( &Variant );
5322 if (Coerce( &Variant, lcid, dwFlags, varIn,
5323 formatTokens[whichToken].varTypeRequired ) != S_OK) {
5324 HeapFree( GetProcessHeap(), 0, pFormatA );
5325 return DISP_E_TYPEMISMATCH;
5326 } else if (formatTokens[whichToken].varTypeRequired == VT_DATE) {
5327 if( DateToTm( V_UNION(&Variant,date), dwFlags, &TM ) == FALSE ) {
5328 HeapFree( GetProcessHeap(), 0, pFormatA );
5329 return E_INVALIDARG;
5334 TRACE("Looking for match on token '%x'\n", *pData);
5337 TRACE("Copy from %d for %d bytes\n", *(pData+1), *(pData+2));
5338 memcpy(pNextPos, &pFormatA[*(pData+1)], *(pData+2));
5339 pNextPos = pNextPos + *(pData+2);
5344 /* Get locale information - Time Seperator */
5345 size = GetLocaleInfoA(lcid, LOCALE_STIME, NULL, 0);
5346 GetLocaleInfoA(lcid, LOCALE_STIME, pNextPos, size);
5347 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5348 pNextPos = pNextPos + size;
5353 /* Get locale information - Date Seperator */
5354 size = GetLocaleInfoA(lcid, LOCALE_SDATE, NULL, 0);
5355 GetLocaleInfoA(lcid, LOCALE_SDATE, pNextPos, size);
5356 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
5357 pNextPos = pNextPos + size;
5362 sprintf(pNextPos, "%d", TM.tm_mday);
5363 pNextPos = pNextPos + strlen(pNextPos);
5368 sprintf(pNextPos, "%2.2d", TM.tm_mday);
5369 pNextPos = pNextPos + strlen(pNextPos);
5374 sprintf(pNextPos, "%d", TM.tm_wday+1);
5375 pNextPos = pNextPos + strlen(pNextPos);
5380 sprintf(pNextPos, "%d", TM.tm_mon+1);
5381 pNextPos = pNextPos + strlen(pNextPos);
5386 sprintf(pNextPos, "%2.2d", TM.tm_mon+1);
5387 pNextPos = pNextPos + strlen(pNextPos);
5392 sprintf(pNextPos, "%d", ((TM.tm_mon+1)/4)+1);
5393 pNextPos = pNextPos + strlen(pNextPos);
5398 sprintf(pNextPos, "%2.2d", TM.tm_yday+1);
5399 pNextPos = pNextPos + strlen(pNextPos);
5404 sprintf(pNextPos, "%2.2d", TM.tm_year);
5405 pNextPos = pNextPos + strlen(pNextPos);
5410 sprintf(pNextPos, "%4.4d", TM.tm_year);
5411 pNextPos = pNextPos + strlen(pNextPos);
5416 sprintf(pNextPos, "%d", TM.tm_hour);
5417 pNextPos = pNextPos + strlen(pNextPos);
5422 sprintf(pNextPos, "%2.2d", TM.tm_hour);
5423 pNextPos = pNextPos + strlen(pNextPos);
5428 sprintf(pNextPos, "%d", TM.tm_min);
5429 pNextPos = pNextPos + strlen(pNextPos);
5434 sprintf(pNextPos, "%2.2d", TM.tm_min);
5435 pNextPos = pNextPos + strlen(pNextPos);
5440 sprintf(pNextPos, "%d", TM.tm_sec);
5441 pNextPos = pNextPos + strlen(pNextPos);
5446 sprintf(pNextPos, "%2.2d", TM.tm_sec);
5447 pNextPos = pNextPos + strlen(pNextPos);
5467 FIXME("Unhandled token for VarFormat %d\n", *pData);
5468 HeapFree( GetProcessHeap(), 0, pFormatA );
5469 return E_INVALIDARG;
5474 *pbstrOut = StringDupAtoBstr( output );
5475 HeapFree( GetProcessHeap(), 0, pFormatA );
5479 /**********************************************************************
5480 * VarFormat [OLEAUT32.469]
5483 HRESULT WINAPI VarFormat(LPVARIANT varIn, LPOLESTR format,
5484 int firstDay, int firstWeek, ULONG dwFlags,
5487 LPSTR pNewString = NULL;
5490 TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
5491 debugstr_w(format), firstDay, firstWeek, dwFlags);
5493 dump_Variant(varIn);
5495 /* Get format string */
5496 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
5498 /* FIXME: Handle some simple pre-definted format strings : */
5499 if (((V_VT(varIn)&VT_TYPEMASK) == VT_CY) && (lstrcmpiA(pNewString, "Currency") == 0)) {
5501 /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
5503 rc = VarR8FromCy(V_UNION(varIn,cyVal), &curVal);
5505 char tmpStr[BUFFER_MAX];
5506 sprintf(tmpStr, "%f", curVal);
5507 if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags, tmpStr, NULL, pBuffer, BUFFER_MAX) == 0) {
5510 *pbstrOut = StringDupAtoBstr( pBuffer );
5514 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_DATE) {
5516 /* Attempt to do proper formatting! */
5517 int firstToken = -1;
5519 rc = VarTokenizeFormatString(format, pBuffer, sizeof(pBuffer), firstDay,
5520 firstWeek, GetUserDefaultLCID(), &firstToken);
5522 rc = VarFormatFromTokens(varIn, format, pBuffer, dwFlags, pbstrOut, GetUserDefaultLCID());
5527 FIXME("Unsupported format!\n");
5528 *pbstrOut = StringDupAtoBstr( "??" );
5531 /* Free allocated storage */
5532 HeapFree( GetProcessHeap(), 0, pNewString );
5533 TRACE("result: '%s'\n", debugstr_w(*pbstrOut));