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
);
642 size
= sizeof(void*);
649 FIXME("Add size information for type vt=%d\n", V_VT(parg
) & VT_TYPEMASK
);
655 /******************************************************************************
656 * StringDupAtoBstr [INTERNAL]
659 static BSTR
StringDupAtoBstr( char* strIn
)
662 OLECHAR
* pNewString
= NULL
;
663 pNewString
= HEAP_strdupAtoW( GetProcessHeap(), 0, strIn
);
664 bstr
= SysAllocString( pNewString
);
665 HeapFree( GetProcessHeap(), 0, pNewString
);
669 /******************************************************************************
672 * Round the double value to the nearest integer value.
674 static double round( double d
)
676 double decimals
= 0.0, integerValue
= 0.0, roundedValue
= 0.0;
677 BOOL bEvenNumber
= FALSE
;
680 /* Save the sign of the number
682 nSign
= (d
>= 0.0) ? 1 : -1;
685 /* Remove the decimals.
687 integerValue
= floor( d
);
689 /* Set the Even flag. This is used to round the number when
690 * the decimals are exactly 1/2. If the integer part is
691 * odd the number is rounded up. If the integer part
692 * is even the number is rounded down. Using this method
693 * numbers are rounded up|down half the time.
695 bEvenNumber
= (((short)fmod(integerValue
, 2)) == 0) ? TRUE
: FALSE
;
697 /* Remove the integral part of the number.
699 decimals
= d
- integerValue
;
701 /* Note: Ceil returns the smallest integer that is greater that x.
702 * and floor returns the largest integer that is less than or equal to x.
706 /* If the decimal part is greater than 1/2
708 roundedValue
= ceil( d
);
710 else if( decimals
< 0.5 )
712 /* If the decimal part is smaller than 1/2
714 roundedValue
= floor( d
);
718 /* the decimals are exactly 1/2 so round according to
719 * the bEvenNumber flag.
723 roundedValue
= floor( d
);
727 roundedValue
= ceil( d
);
731 return roundedValue
* nSign
;
734 /******************************************************************************
735 * RemoveCharacterFromString [INTERNAL]
737 * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
739 static void RemoveCharacterFromString( LPSTR str
, LPSTR strOfCharToRemove
)
741 LPSTR pNewString
= NULL
;
742 LPSTR strToken
= NULL
;
744 /* Check if we have a valid argument
748 pNewString
= strdup( str
);
750 strToken
= strtok( pNewString
, strOfCharToRemove
);
751 while( strToken
!= NULL
) {
752 strcat( str
, strToken
);
753 strToken
= strtok( NULL
, strOfCharToRemove
);
760 /******************************************************************************
761 * GetValidRealString [INTERNAL]
763 * Checks if the string is of proper format to be converted to a real value.
765 static BOOL
IsValidRealString( LPSTR strRealString
)
767 /* Real values that have a decimal point are required to either have
768 * digits before or after the decimal point. We will assume that
769 * we do not have any digits at either position. If we do encounter
770 * some we will disable this flag.
772 BOOL bDigitsRequired
= TRUE
;
773 /* Processed fields in the string representation of the real number.
775 BOOL bWhiteSpaceProcessed
= FALSE
;
776 BOOL bFirstSignProcessed
= FALSE
;
777 BOOL bFirstDigitsProcessed
= FALSE
;
778 BOOL bDecimalPointProcessed
= FALSE
;
779 BOOL bSecondDigitsProcessed
= FALSE
;
780 BOOL bExponentProcessed
= FALSE
;
781 BOOL bSecondSignProcessed
= FALSE
;
782 BOOL bThirdDigitsProcessed
= FALSE
;
783 /* Assume string parameter "strRealString" is valid and try to disprove it.
785 BOOL bValidRealString
= TRUE
;
787 /* Used to count the number of tokens in the "strRealString".
789 LPSTR strToken
= NULL
;
793 /* Check if we have a valid argument
795 if( strRealString
== NULL
)
797 bValidRealString
= FALSE
;
800 if( bValidRealString
== TRUE
)
802 /* Make sure we only have ONE token in the string.
804 strToken
= strtok( strRealString
, " " );
805 while( strToken
!= NULL
) {
807 strToken
= strtok( NULL
, " " );
812 bValidRealString
= FALSE
;
817 /* Make sure this token contains only valid characters.
818 * The string argument to atof has the following form:
819 * [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
820 * Whitespace consists of space and|or <TAB> characters, which are ignored.
821 * Sign is either plus '+' or minus '-'.
822 * Digits are one or more decimal digits.
823 * Note: If no digits appear before the decimal point, at least one must
824 * appear after the decimal point.
825 * The decimal digits may be followed by an exponent.
826 * An Exponent consists of an introductory letter ( D, d, E, or e) and
827 * an optionally signed decimal integer.
829 pChar
= strRealString
;
830 while( bValidRealString
== TRUE
&& *pChar
!= '\0' )
838 if( bWhiteSpaceProcessed
||
839 bFirstSignProcessed
||
840 bFirstDigitsProcessed
||
841 bDecimalPointProcessed
||
842 bSecondDigitsProcessed
||
843 bExponentProcessed
||
844 bSecondSignProcessed
||
845 bThirdDigitsProcessed
)
847 bValidRealString
= FALSE
;
854 if( bFirstSignProcessed
== FALSE
)
856 if( bFirstDigitsProcessed
||
857 bDecimalPointProcessed
||
858 bSecondDigitsProcessed
||
859 bExponentProcessed
||
860 bSecondSignProcessed
||
861 bThirdDigitsProcessed
)
863 bValidRealString
= FALSE
;
865 bWhiteSpaceProcessed
= TRUE
;
866 bFirstSignProcessed
= TRUE
;
868 else if( bSecondSignProcessed
== FALSE
)
870 /* Note: The exponent must be present in
871 * order to accept the second sign...
873 if( bExponentProcessed
== FALSE
||
874 bThirdDigitsProcessed
||
877 bValidRealString
= FALSE
;
879 bFirstSignProcessed
= TRUE
;
880 bWhiteSpaceProcessed
= TRUE
;
881 bFirstDigitsProcessed
= TRUE
;
882 bDecimalPointProcessed
= TRUE
;
883 bSecondDigitsProcessed
= TRUE
;
884 bSecondSignProcessed
= TRUE
;
900 if( bFirstDigitsProcessed
== FALSE
)
902 if( bDecimalPointProcessed
||
903 bSecondDigitsProcessed
||
904 bExponentProcessed
||
905 bSecondSignProcessed
||
906 bThirdDigitsProcessed
)
908 bValidRealString
= FALSE
;
910 bFirstSignProcessed
= TRUE
;
911 bWhiteSpaceProcessed
= TRUE
;
912 /* We have found some digits before the decimal point
913 * so disable the "Digits required" flag.
915 bDigitsRequired
= FALSE
;
917 else if( bSecondDigitsProcessed
== FALSE
)
919 if( bExponentProcessed
||
920 bSecondSignProcessed
||
921 bThirdDigitsProcessed
)
923 bValidRealString
= FALSE
;
925 bFirstSignProcessed
= TRUE
;
926 bWhiteSpaceProcessed
= TRUE
;
927 bFirstDigitsProcessed
= TRUE
;
928 bDecimalPointProcessed
= TRUE
;
929 /* We have found some digits after the decimal point
930 * so disable the "Digits required" flag.
932 bDigitsRequired
= FALSE
;
934 else if( bThirdDigitsProcessed
== FALSE
)
936 /* Getting here means everything else should be processed.
937 * If we get anything else than a decimal following this
938 * digit it will be flagged by the other cases, so
939 * we do not really need to do anything in here.
943 /* If DecimalPoint...
946 if( bDecimalPointProcessed
||
947 bSecondDigitsProcessed
||
948 bExponentProcessed
||
949 bSecondSignProcessed
||
950 bThirdDigitsProcessed
)
952 bValidRealString
= FALSE
;
954 bFirstSignProcessed
= TRUE
;
955 bWhiteSpaceProcessed
= TRUE
;
956 bFirstDigitsProcessed
= TRUE
;
957 bDecimalPointProcessed
= TRUE
;
965 if( bExponentProcessed
||
966 bSecondSignProcessed
||
967 bThirdDigitsProcessed
||
970 bValidRealString
= FALSE
;
972 bFirstSignProcessed
= TRUE
;
973 bWhiteSpaceProcessed
= TRUE
;
974 bFirstDigitsProcessed
= TRUE
;
975 bDecimalPointProcessed
= TRUE
;
976 bSecondDigitsProcessed
= TRUE
;
977 bExponentProcessed
= TRUE
;
980 bValidRealString
= FALSE
;
983 /* Process next character.
988 /* If the required digits were not present we have an invalid
989 * string representation of a real number.
991 if( bDigitsRequired
== TRUE
)
993 bValidRealString
= FALSE
;
996 return bValidRealString
;
1000 /******************************************************************************
1003 * This function dispatches execution to the proper conversion API
1004 * to do the necessary coercion.
1006 * FIXME: Passing down dwFlags to the conversion functions is wrong, this
1007 * is a different flagmask. Check MSDN.
1009 static HRESULT
Coerce( VARIANTARG
* pd
, LCID lcid
, ULONG dwFlags
, VARIANTARG
* ps
, VARTYPE vt
)
1012 unsigned short vtFrom
= 0;
1013 vtFrom
= V_VT(ps
) & VT_TYPEMASK
;
1016 /* Note: Since "long" and "int" values both have 4 bytes and are
1017 * both signed integers "int" will be treated as "long" in the
1019 * The same goes for their unsigned versions.
1022 /* Trivial Case: If the coercion is from two types that are
1023 * identical then we can blindly copy from one argument to another.*/
1026 return VariantCopy(pd
,ps
);
1029 /* Cases requiring thought*/
1034 res
= VariantClear( pd
);
1037 res
= VariantClear( pd
);
1047 res
= VariantCopy( pd
, ps
);
1050 res
= VarI1FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,cVal
) );
1054 res
= VarI1FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,cVal
) );
1057 res
= VarI1FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,cVal
) );
1060 res
= VarI1FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,cVal
) );
1064 res
= VarI1FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,cVal
) );
1067 res
= VarI1FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,cVal
) );
1070 res
= VarI1FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,cVal
) );
1073 res
= VarI1FromDate( V_UNION(ps
,date
), &V_UNION(pd
,cVal
) );
1076 res
= VarI1FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,cVal
) );
1079 res
= VarI1FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,cVal
) );
1082 res
= VarI1FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,cVal
) );
1084 case( VT_DISPATCH
):
1085 /*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
1087 /*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
1090 res
= DISP_E_TYPEMISMATCH
;
1091 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1100 res
= VarI2FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,iVal
) );
1103 res
= VariantCopy( pd
, ps
);
1107 res
= VarI2FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,iVal
) );
1110 res
= VarI2FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,iVal
) );
1113 res
= VarI2FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,iVal
) );
1117 res
= VarI2FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,iVal
) );
1120 res
= VarI2FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,iVal
) );
1123 res
= VarI2FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,iVal
) );
1126 res
= VarI2FromDate( V_UNION(ps
,date
), &V_UNION(pd
,iVal
) );
1129 res
= VarI2FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,iVal
) );
1132 res
= VarI2FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,iVal
) );
1135 res
= VarI2FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,iVal
) );
1137 case( VT_DISPATCH
):
1138 /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
1140 /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
1143 res
= DISP_E_TYPEMISMATCH
;
1144 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1154 V_UNION(pd
,lVal
) = 0;
1158 res
= VarI4FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,lVal
) );
1161 res
= VarI4FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,lVal
) );
1165 res
= VariantCopy( pd
, ps
);
1168 res
= VarI4FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,lVal
) );
1171 res
= VarI4FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,lVal
) );
1175 res
= VarI4FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,lVal
) );
1178 res
= VarI4FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,lVal
) );
1181 res
= VarI4FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,lVal
) );
1184 res
= VarI4FromDate( V_UNION(ps
,date
), &V_UNION(pd
,lVal
) );
1187 res
= VarI4FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,lVal
) );
1190 res
= VarI4FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,lVal
) );
1193 res
= VarI4FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,lVal
) );
1195 case( VT_DISPATCH
):
1196 /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1198 /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1201 res
= DISP_E_TYPEMISMATCH
;
1202 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1211 res
= VarUI1FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,bVal
) );
1214 res
= VarUI1FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,bVal
) );
1218 res
= VarUI1FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,bVal
) );
1221 res
= VariantCopy( pd
, ps
);
1224 res
= VarUI1FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,bVal
) );
1228 res
= VarUI1FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,bVal
) );
1231 res
= VarUI1FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,bVal
) );
1234 res
= VarUI1FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,bVal
) );
1237 res
= VarUI1FromDate( V_UNION(ps
,date
), &V_UNION(pd
,bVal
) );
1240 res
= VarUI1FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,bVal
) );
1243 res
= VarUI1FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,bVal
) );
1246 res
= VarUI1FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,bVal
) );
1248 case( VT_DISPATCH
):
1249 /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1251 /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1254 res
= DISP_E_TYPEMISMATCH
;
1255 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1264 res
= VarUI2FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,uiVal
) );
1267 res
= VarUI2FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,uiVal
) );
1271 res
= VarUI2FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,uiVal
) );
1274 res
= VarUI2FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,uiVal
) );
1277 res
= VariantCopy( pd
, ps
);
1281 res
= VarUI2FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,uiVal
) );
1284 res
= VarUI2FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,uiVal
) );
1287 res
= VarUI2FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,uiVal
) );
1290 res
= VarUI2FromDate( V_UNION(ps
,date
), &V_UNION(pd
,uiVal
) );
1293 res
= VarUI2FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,uiVal
) );
1296 res
= VarUI2FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,uiVal
) );
1299 res
= VarUI2FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,uiVal
) );
1301 case( VT_DISPATCH
):
1302 /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1304 /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1307 res
= DISP_E_TYPEMISMATCH
;
1308 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1318 res
= VarUI4FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,ulVal
) );
1321 res
= VarUI4FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,ulVal
) );
1325 res
= VarUI4FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,ulVal
) );
1328 res
= VarUI4FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,ulVal
) );
1331 res
= VarUI4FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,ulVal
) );
1334 res
= VariantCopy( pd
, ps
);
1337 res
= VarUI4FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,ulVal
) );
1340 res
= VarUI4FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,ulVal
) );
1343 res
= VarUI4FromDate( V_UNION(ps
,date
), &V_UNION(pd
,ulVal
) );
1346 res
= VarUI4FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,ulVal
) );
1349 res
= VarUI4FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,ulVal
) );
1352 res
= VarUI4FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,ulVal
) );
1354 case( VT_DISPATCH
):
1355 /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1357 /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1360 res
= DISP_E_TYPEMISMATCH
;
1361 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1370 res
= VarR4FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,fltVal
) );
1373 res
= VarR4FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,fltVal
) );
1377 res
= VarR4FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,fltVal
) );
1380 res
= VarR4FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,fltVal
) );
1383 res
= VarR4FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,fltVal
) );
1387 res
= VarR4FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,fltVal
) );
1390 res
= VariantCopy( pd
, ps
);
1393 res
= VarR4FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,fltVal
) );
1396 res
= VarR4FromDate( V_UNION(ps
,date
), &V_UNION(pd
,fltVal
) );
1399 res
= VarR4FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,fltVal
) );
1402 res
= VarR4FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,fltVal
) );
1405 res
= VarR4FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,fltVal
) );
1407 case( VT_DISPATCH
):
1408 /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1410 /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1413 res
= DISP_E_TYPEMISMATCH
;
1414 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1423 res
= VarR8FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,dblVal
) );
1426 res
= VarR8FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,dblVal
) );
1430 res
= VarR8FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,dblVal
) );
1433 res
= VarR8FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,dblVal
) );
1436 res
= VarR8FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,dblVal
) );
1440 res
= VarR8FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,dblVal
) );
1443 res
= VarR8FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,dblVal
) );
1446 res
= VariantCopy( pd
, ps
);
1449 res
= VarR8FromDate( V_UNION(ps
,date
), &V_UNION(pd
,dblVal
) );
1452 res
= VarR8FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,dblVal
) );
1455 res
= VarR8FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,dblVal
) );
1458 res
= VarR8FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,dblVal
) );
1460 case( VT_DISPATCH
):
1461 /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1463 /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1466 res
= DISP_E_TYPEMISMATCH
;
1467 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1476 res
= VarDateFromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,date
) );
1479 res
= VarDateFromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,date
) );
1482 res
= VarDateFromInt( V_UNION(ps
,intVal
), &V_UNION(pd
,date
) );
1485 res
= VarDateFromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,date
) );
1488 res
= VarDateFromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,date
) );
1491 res
= VarDateFromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,date
) );
1494 res
= VarDateFromUint( V_UNION(ps
,uintVal
), &V_UNION(pd
,date
) );
1497 res
= VarDateFromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,date
) );
1500 res
= VarDateFromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,date
) );
1503 res
= VarDateFromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,date
) );
1506 res
= VariantCopy( pd
, ps
);
1509 res
= VarDateFromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,date
) );
1512 res
= VarDateFromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,date
) );
1515 res
= VarDateFromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,date
) );
1517 case( VT_DISPATCH
):
1518 /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1520 /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1523 res
= DISP_E_TYPEMISMATCH
;
1524 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1534 V_UNION(pd
,boolVal
) = VARIANT_FALSE
;
1537 res
= VarBoolFromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,boolVal
) );
1540 res
= VarBoolFromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,boolVal
) );
1543 res
= VarBoolFromInt( V_UNION(ps
,intVal
), &V_UNION(pd
,boolVal
) );
1546 res
= VarBoolFromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,boolVal
) );
1549 res
= VarBoolFromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,boolVal
) );
1552 res
= VarBoolFromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,boolVal
) );
1555 res
= VarBoolFromUint( V_UNION(ps
,uintVal
), &V_UNION(pd
,boolVal
) );
1558 res
= VarBoolFromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,boolVal
) );
1561 res
= VarBoolFromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,boolVal
) );
1564 res
= VarBoolFromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,boolVal
) );
1567 res
= VarBoolFromDate( V_UNION(ps
,date
), &V_UNION(pd
,boolVal
) );
1570 res
= VariantCopy( pd
, ps
);
1573 res
= VarBoolFromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,boolVal
) );
1576 res
= VarBoolFromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,boolVal
) );
1578 case( VT_DISPATCH
):
1579 /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1581 /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1584 res
= DISP_E_TYPEMISMATCH
;
1585 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1594 if ((V_UNION(pd
,bstrVal
) = SysAllocStringLen(NULL
, 0)))
1597 res
= E_OUTOFMEMORY
;
1600 res
= VarBstrFromI1( V_UNION(ps
,cVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1603 res
= VarBstrFromI2( V_UNION(ps
,iVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1606 res
= VarBstrFromInt( V_UNION(ps
,intVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1609 res
= VarBstrFromI4( V_UNION(ps
,lVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1612 res
= VarBstrFromUI1( V_UNION(ps
,bVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1615 res
= VarBstrFromUI2( V_UNION(ps
,uiVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1618 res
= VarBstrFromUint( V_UNION(ps
,uintVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1621 res
= VarBstrFromUI4( V_UNION(ps
,ulVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1624 res
= VarBstrFromR4( V_UNION(ps
,fltVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1627 res
= VarBstrFromR8( V_UNION(ps
,dblVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1630 res
= VarBstrFromDate( V_UNION(ps
,date
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1633 res
= VarBstrFromBool( V_UNION(ps
,boolVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1636 res
= VariantCopy( pd
, ps
);
1639 res
= VarBstrFromCy( V_UNION(ps
,cyVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1641 case( VT_DISPATCH
):
1642 /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1644 /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1647 res
= DISP_E_TYPEMISMATCH
;
1648 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1657 res
= VarCyFromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,cyVal
) );
1660 res
= VarCyFromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,cyVal
) );
1663 res
= VarCyFromInt( V_UNION(ps
,intVal
), &V_UNION(pd
,cyVal
) );
1666 res
= VarCyFromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,cyVal
) );
1669 res
= VarCyFromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,cyVal
) );
1672 res
= VarCyFromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,cyVal
) );
1675 res
= VarCyFromUint( V_UNION(ps
,uintVal
), &V_UNION(pd
,cyVal
) );
1678 res
= VarCyFromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,cyVal
) );
1681 res
= VarCyFromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,cyVal
) );
1684 res
= VarCyFromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,cyVal
) );
1687 res
= VarCyFromDate( V_UNION(ps
,date
), &V_UNION(pd
,cyVal
) );
1690 res
= VarCyFromBool( V_UNION(ps
,date
), &V_UNION(pd
,cyVal
) );
1693 res
= VariantCopy( pd
, ps
);
1696 res
= VarCyFromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,cyVal
) );
1698 case( VT_DISPATCH
):
1699 /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1701 /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1705 res
= DISP_E_TYPEMISMATCH
;
1706 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1712 if (vtFrom
== VT_DISPATCH
)
1714 res
= IDispatch_QueryInterface(V_DISPATCH(ps
), &IID_IUnknown
, (LPVOID
*)&V_UNKNOWN(pd
));
1718 res
= DISP_E_TYPEMISMATCH
;
1719 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1724 res
= DISP_E_TYPEMISMATCH
;
1725 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1732 /******************************************************************************
1733 * ValidateVtRange [INTERNAL]
1735 * Used internally by the hi-level Variant API to determine
1736 * if the vartypes are valid.
1738 static HRESULT WINAPI
ValidateVtRange( VARTYPE vt
)
1740 /* if by value we must make sure it is in the
1741 * range of the valid types.
1743 if( ( vt
& VT_TYPEMASK
) > VT_MAXVALIDTYPE
)
1745 return DISP_E_BADVARTYPE
;
1751 /******************************************************************************
1752 * ValidateVartype [INTERNAL]
1754 * Used internally by the hi-level Variant API to determine
1755 * if the vartypes are valid.
1757 static HRESULT WINAPI
ValidateVariantType( VARTYPE vt
)
1761 /* check if we have a valid argument.
1765 /* if by reference check that the type is in
1766 * the valid range and that it is not of empty or null type
1768 if( ( vt
& VT_TYPEMASK
) == VT_EMPTY
||
1769 ( vt
& VT_TYPEMASK
) == VT_NULL
||
1770 ( vt
& VT_TYPEMASK
) > VT_MAXVALIDTYPE
)
1772 res
= DISP_E_BADVARTYPE
;
1778 res
= ValidateVtRange( vt
);
1784 /******************************************************************************
1785 * ValidateVt [INTERNAL]
1787 * Used internally by the hi-level Variant API to determine
1788 * if the vartypes are valid.
1790 static HRESULT WINAPI
ValidateVt( VARTYPE vt
)
1794 /* check if we have a valid argument.
1798 /* if by reference check that the type is in
1799 * the valid range and that it is not of empty or null type
1801 if( ( vt
& VT_TYPEMASK
) == VT_EMPTY
||
1802 ( vt
& VT_TYPEMASK
) == VT_NULL
||
1803 ( vt
& VT_TYPEMASK
) > VT_MAXVALIDTYPE
)
1805 res
= DISP_E_BADVARTYPE
;
1811 res
= ValidateVtRange( vt
);
1821 /******************************************************************************
1822 * VariantInit [OLEAUT32.8]
1824 * Initializes the Variant. Unlike VariantClear it does not interpret
1825 * the current contents of the Variant.
1827 void WINAPI
VariantInit(VARIANTARG
* pvarg
)
1829 TRACE("(%p)\n",pvarg
);
1831 memset(pvarg
, 0, sizeof (VARIANTARG
));
1832 V_VT(pvarg
) = VT_EMPTY
;
1837 /******************************************************************************
1838 * VariantClear [OLEAUT32.9]
1840 * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1841 * sets the wReservedX field to 0. The current contents of the VARIANT are
1842 * freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1843 * released. If VT_ARRAY the array is freed.
1845 HRESULT WINAPI
VariantClear(VARIANTARG
* pvarg
)
1848 TRACE("(%p)\n",pvarg
);
1850 res
= ValidateVariantType( V_VT(pvarg
) );
1853 if( !( V_VT(pvarg
) & VT_BYREF
) )
1856 * The VT_ARRAY flag is a special case of a safe array.
1858 if ( (V_VT(pvarg
) & VT_ARRAY
) != 0)
1860 SafeArrayDestroy(V_UNION(pvarg
,parray
));
1864 switch( V_VT(pvarg
) & VT_TYPEMASK
)
1867 SysFreeString( V_UNION(pvarg
,bstrVal
) );
1869 case( VT_DISPATCH
):
1870 if(V_UNION(pvarg
,pdispVal
)!=NULL
)
1871 ICOM_CALL(Release
,V_UNION(pvarg
,pdispVal
));
1874 VariantClear(V_UNION(pvarg
,pvarVal
));
1877 if(V_UNION(pvarg
,punkVal
)!=NULL
)
1878 ICOM_CALL(Release
,V_UNION(pvarg
,punkVal
));
1880 case( VT_SAFEARRAY
):
1881 SafeArrayDestroy(V_UNION(pvarg
,parray
));
1890 * Empty all the fields and mark the type as empty.
1892 memset(pvarg
, 0, sizeof (VARIANTARG
));
1893 V_VT(pvarg
) = VT_EMPTY
;
1899 /******************************************************************************
1900 * VariantCopy [OLEAUT32.10]
1902 * Frees up the designation variant and makes a copy of the source.
1904 HRESULT WINAPI
VariantCopy(VARIANTARG
* pvargDest
, VARIANTARG
* pvargSrc
)
1908 TRACE("(%p, %p), vt=%d\n", pvargDest
, pvargSrc
, V_VT(pvargSrc
));
1910 res
= ValidateVariantType( V_VT(pvargSrc
) );
1912 /* If the pointer are to the same variant we don't need
1915 if( pvargDest
!= pvargSrc
&& res
== S_OK
)
1917 res
= VariantClear( pvargDest
);
1921 if( V_VT(pvargSrc
) & VT_BYREF
)
1923 /* In the case of byreference we only need
1924 * to copy the pointer.
1926 pvargDest
->n1
.n2
.n3
= pvargSrc
->n1
.n2
.n3
;
1927 V_VT(pvargDest
) = V_VT(pvargSrc
);
1932 * The VT_ARRAY flag is another way to designate a safe array.
1934 if (V_VT(pvargSrc
) & VT_ARRAY
)
1936 SafeArrayCopy(V_UNION(pvargSrc
,parray
), &V_UNION(pvargDest
,parray
));
1940 /* In the case of by value we need to
1941 * copy the actual value. In the case of
1942 * VT_BSTR a copy of the string is made,
1943 * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1944 * called to increment the object's reference count.
1946 switch( V_VT(pvargSrc
) & VT_TYPEMASK
)
1949 V_UNION(pvargDest
,bstrVal
) = SYSDUPSTRING( V_UNION(pvargSrc
,bstrVal
) );
1951 case( VT_DISPATCH
):
1952 V_UNION(pvargDest
,pdispVal
) = V_UNION(pvargSrc
,pdispVal
);
1953 if (V_UNION(pvargDest
,pdispVal
)!=NULL
)
1954 ICOM_CALL(AddRef
,V_UNION(pvargDest
,pdispVal
));
1957 VariantCopy(V_UNION(pvargDest
,pvarVal
),V_UNION(pvargSrc
,pvarVal
));
1960 V_UNION(pvargDest
,punkVal
) = V_UNION(pvargSrc
,punkVal
);
1961 if (V_UNION(pvargDest
,pdispVal
)!=NULL
)
1962 ICOM_CALL(AddRef
,V_UNION(pvargDest
,punkVal
));
1964 case( VT_SAFEARRAY
):
1965 SafeArrayCopy(V_UNION(pvargSrc
,parray
), &V_UNION(pvargDest
,parray
));
1968 pvargDest
->n1
.n2
.n3
= pvargSrc
->n1
.n2
.n3
;
1973 V_VT(pvargDest
) = V_VT(pvargSrc
);
1982 /******************************************************************************
1983 * VariantCopyInd [OLEAUT32.11]
1985 * Frees up the destination variant and makes a copy of the source. If
1986 * the source is of type VT_BYREF it performs the necessary indirections.
1988 HRESULT WINAPI
VariantCopyInd(VARIANT
* pvargDest
, VARIANTARG
* pvargSrc
)
1992 TRACE("(%p, %p)\n", pvargDest
, pvargSrc
);
1994 res
= ValidateVariantType( V_VT(pvargSrc
) );
1999 if( V_VT(pvargSrc
) & VT_BYREF
)
2002 VariantInit( &varg
);
2004 /* handle the in place copy.
2006 if( pvargDest
== pvargSrc
)
2008 /* we will use a copy of the source instead.
2010 res
= VariantCopy( &varg
, pvargSrc
);
2016 res
= VariantClear( pvargDest
);
2021 * The VT_ARRAY flag is another way to designate a safearray variant.
2023 if ( V_VT(pvargSrc
) & VT_ARRAY
)
2025 SafeArrayCopy(*V_UNION(pvargSrc
,pparray
), &V_UNION(pvargDest
,parray
));
2029 /* In the case of by reference we need
2030 * to copy the date pointed to by the variant.
2033 /* Get the variant type.
2035 switch( V_VT(pvargSrc
) & VT_TYPEMASK
)
2038 V_UNION(pvargDest
,bstrVal
) = SYSDUPSTRING( *(V_UNION(pvargSrc
,pbstrVal
)) );
2040 case( VT_DISPATCH
):
2044 /* Prevent from cycling. According to tests on
2045 * VariantCopyInd in Windows and the documentation
2046 * this API dereferences the inner Variants to only one depth.
2047 * If the inner Variant itself contains an
2048 * other inner variant the E_INVALIDARG error is
2051 if( pvargSrc
->n1
.n2
.wReserved1
& PROCESSING_INNER_VARIANT
)
2053 /* If we get here we are attempting to deference
2054 * an inner variant that that is itself contained
2055 * in an inner variant so report E_INVALIDARG error.
2061 /* Set the processing inner variant flag.
2062 * We will set this flag in the inner variant
2063 * that will be passed to the VariantCopyInd function.
2065 (V_UNION(pvargSrc
,pvarVal
))->n1
.n2
.wReserved1
|= PROCESSING_INNER_VARIANT
;
2067 /* Dereference the inner variant.
2069 res
= VariantCopyInd( pvargDest
, V_UNION(pvargSrc
,pvarVal
) );
2070 /* We must also copy its type, I think.
2072 V_VT(pvargSrc
) = V_VT(V_UNION(pvargSrc
,pvarVal
));
2078 case( VT_SAFEARRAY
):
2079 SafeArrayCopy(*V_UNION(pvargSrc
,pparray
), &V_UNION(pvargDest
,parray
));
2082 /* This is a by reference Variant which means that the union
2083 * part of the Variant contains a pointer to some data of
2084 * type "V_VT(pvargSrc) & VT_TYPEMASK".
2085 * We will deference this data in a generic fashion using
2086 * the void pointer "Variant.u.byref".
2087 * We will copy this data into the union of the destination
2090 memcpy( &pvargDest
->n1
.n2
.n3
, V_UNION(pvargSrc
,byref
), SizeOfVariantData( pvargSrc
) );
2095 if (res
== S_OK
) V_VT(pvargDest
) = V_VT(pvargSrc
) & VT_TYPEMASK
;
2099 /* this should not fail.
2101 VariantClear( &varg
);
2105 res
= VariantCopy( pvargDest
, pvargSrc
);
2111 /******************************************************************************
2112 * VariantChangeType [OLEAUT32.12]
2114 HRESULT WINAPI
VariantChangeType(VARIANTARG
* pvargDest
, VARIANTARG
* pvargSrc
,
2115 USHORT wFlags
, VARTYPE vt
)
2117 return VariantChangeTypeEx( pvargDest
, pvargSrc
, 0, wFlags
, vt
);
2120 /******************************************************************************
2121 * VariantChangeTypeEx [OLEAUT32.147]
2123 HRESULT WINAPI
VariantChangeTypeEx(VARIANTARG
* pvargDest
, VARIANTARG
* pvargSrc
,
2124 LCID lcid
, USHORT wFlags
, VARTYPE vt
)
2128 VariantInit( &varg
);
2130 TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest
, pvargSrc
, lcid
, wFlags
, vt
, V_VT(pvargSrc
));
2131 TRACE("Src Var:\n");
2132 dump_Variant(pvargSrc
);
2134 /* validate our source argument.
2136 res
= ValidateVariantType( V_VT(pvargSrc
) );
2138 /* validate the vartype.
2142 res
= ValidateVt( vt
);
2145 /* if we are doing an in-place conversion make a copy of the source.
2147 if( res
== S_OK
&& pvargDest
== pvargSrc
)
2149 res
= VariantCopy( &varg
, pvargSrc
);
2155 /* free up the destination variant.
2157 res
= VariantClear( pvargDest
);
2162 if( V_VT(pvargSrc
) & VT_BYREF
)
2164 /* Convert the source variant to a "byvalue" variant.
2167 VariantInit( &Variant
);
2168 res
= VariantCopyInd( &Variant
, pvargSrc
);
2171 res
= Coerce( pvargDest
, lcid
, wFlags
, &Variant
, vt
);
2172 /* this should not fail.
2174 VariantClear( &Variant
);
2180 /* Use the current "byvalue" source variant.
2182 res
= Coerce( pvargDest
, lcid
, wFlags
, pvargSrc
, vt
);
2185 /* this should not fail.
2187 VariantClear( &varg
);
2189 /* set the type of the destination
2192 V_VT(pvargDest
) = vt
;
2194 TRACE("Dest Var:\n");
2195 dump_Variant(pvargDest
);
2203 /******************************************************************************
2204 * VarUI1FromI2 [OLEAUT32.130]
2206 HRESULT WINAPI
VarUI1FromI2(short sIn
, BYTE
* pbOut
)
2208 TRACE("( %d, %p ), stub\n", sIn
, pbOut
);
2210 /* Check range of value.
2212 if( sIn
< UI1_MIN
|| sIn
> UI1_MAX
)
2214 return DISP_E_OVERFLOW
;
2217 *pbOut
= (BYTE
) sIn
;
2222 /******************************************************************************
2223 * VarUI1FromI4 [OLEAUT32.131]
2225 HRESULT WINAPI
VarUI1FromI4(LONG lIn
, BYTE
* pbOut
)
2227 TRACE("( %ld, %p ), stub\n", lIn
, pbOut
);
2229 /* Check range of value.
2231 if( lIn
< UI1_MIN
|| lIn
> UI1_MAX
)
2233 return DISP_E_OVERFLOW
;
2236 *pbOut
= (BYTE
) lIn
;
2242 /******************************************************************************
2243 * VarUI1FromR4 [OLEAUT32.132]
2245 HRESULT WINAPI
VarUI1FromR4(FLOAT fltIn
, BYTE
* pbOut
)
2247 TRACE("( %f, %p ), stub\n", fltIn
, pbOut
);
2249 /* Check range of value.
2251 fltIn
= round( fltIn
);
2252 if( fltIn
< UI1_MIN
|| fltIn
> UI1_MAX
)
2254 return DISP_E_OVERFLOW
;
2257 *pbOut
= (BYTE
) fltIn
;
2262 /******************************************************************************
2263 * VarUI1FromR8 [OLEAUT32.133]
2265 HRESULT WINAPI
VarUI1FromR8(double dblIn
, BYTE
* pbOut
)
2267 TRACE("( %f, %p ), stub\n", dblIn
, pbOut
);
2269 /* Check range of value.
2271 dblIn
= round( dblIn
);
2272 if( dblIn
< UI1_MIN
|| dblIn
> UI1_MAX
)
2274 return DISP_E_OVERFLOW
;
2277 *pbOut
= (BYTE
) dblIn
;
2282 /******************************************************************************
2283 * VarUI1FromDate [OLEAUT32.135]
2285 HRESULT WINAPI
VarUI1FromDate(DATE dateIn
, BYTE
* pbOut
)
2287 TRACE("( %f, %p ), stub\n", dateIn
, pbOut
);
2289 /* Check range of value.
2291 dateIn
= round( dateIn
);
2292 if( dateIn
< UI1_MIN
|| dateIn
> UI1_MAX
)
2294 return DISP_E_OVERFLOW
;
2297 *pbOut
= (BYTE
) dateIn
;
2302 /******************************************************************************
2303 * VarUI1FromBool [OLEAUT32.138]
2305 HRESULT WINAPI
VarUI1FromBool(VARIANT_BOOL boolIn
, BYTE
* pbOut
)
2307 TRACE("( %d, %p ), stub\n", boolIn
, pbOut
);
2309 *pbOut
= (BYTE
) boolIn
;
2314 /******************************************************************************
2315 * VarUI1FromI1 [OLEAUT32.237]
2317 HRESULT WINAPI
VarUI1FromI1(CHAR cIn
, BYTE
* pbOut
)
2319 TRACE("( %c, %p ), stub\n", cIn
, pbOut
);
2326 /******************************************************************************
2327 * VarUI1FromUI2 [OLEAUT32.238]
2329 HRESULT WINAPI
VarUI1FromUI2(USHORT uiIn
, BYTE
* pbOut
)
2331 TRACE("( %d, %p ), stub\n", uiIn
, pbOut
);
2333 /* Check range of value.
2335 if( uiIn
> UI1_MAX
)
2337 return DISP_E_OVERFLOW
;
2340 *pbOut
= (BYTE
) uiIn
;
2345 /******************************************************************************
2346 * VarUI1FromUI4 [OLEAUT32.239]
2348 HRESULT WINAPI
VarUI1FromUI4(ULONG ulIn
, BYTE
* pbOut
)
2350 TRACE("( %ld, %p ), stub\n", ulIn
, pbOut
);
2352 /* Check range of value.
2354 if( ulIn
> UI1_MAX
)
2356 return DISP_E_OVERFLOW
;
2359 *pbOut
= (BYTE
) ulIn
;
2365 /******************************************************************************
2366 * VarUI1FromStr [OLEAUT32.136]
2368 HRESULT WINAPI
VarUI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, BYTE
* pbOut
)
2370 double dValue
= 0.0;
2371 LPSTR pNewString
= NULL
;
2373 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn
, lcid
, dwFlags
, pbOut
);
2375 /* Check if we have a valid argument
2377 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
2378 RemoveCharacterFromString( pNewString
, "," );
2379 if( IsValidRealString( pNewString
) == FALSE
)
2381 return DISP_E_TYPEMISMATCH
;
2384 /* Convert the valid string to a floating point number.
2386 dValue
= atof( pNewString
);
2388 /* We don't need the string anymore so free it.
2390 HeapFree( GetProcessHeap(), 0 , pNewString
);
2392 /* Check range of value.
2394 dValue
= round( dValue
);
2395 if( dValue
< UI1_MIN
|| dValue
> UI1_MAX
)
2397 return DISP_E_OVERFLOW
;
2400 *pbOut
= (BYTE
) dValue
;
2405 /**********************************************************************
2406 * VarUI1FromCy [OLEAUT32.134]
2407 * Convert currency to unsigned char
2409 HRESULT WINAPI
VarUI1FromCy(CY cyIn
, BYTE
* pbOut
) {
2410 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
2412 if (t
> UI1_MAX
|| t
< UI1_MIN
) return DISP_E_OVERFLOW
;
2418 /******************************************************************************
2419 * VarI2FromUI1 [OLEAUT32.48]
2421 HRESULT WINAPI
VarI2FromUI1(BYTE bIn
, short* psOut
)
2423 TRACE("( 0x%08x, %p ), stub\n", bIn
, psOut
);
2425 *psOut
= (short) bIn
;
2430 /******************************************************************************
2431 * VarI2FromI4 [OLEAUT32.49]
2433 HRESULT WINAPI
VarI2FromI4(LONG lIn
, short* psOut
)
2435 TRACE("( %lx, %p ), stub\n", lIn
, psOut
);
2437 /* Check range of value.
2439 if( lIn
< I2_MIN
|| lIn
> I2_MAX
)
2441 return DISP_E_OVERFLOW
;
2444 *psOut
= (short) lIn
;
2449 /******************************************************************************
2450 * VarI2FromR4 [OLEAUT32.50]
2452 HRESULT WINAPI
VarI2FromR4(FLOAT fltIn
, short* psOut
)
2454 TRACE("( %f, %p ), stub\n", fltIn
, psOut
);
2456 /* Check range of value.
2458 fltIn
= round( fltIn
);
2459 if( fltIn
< I2_MIN
|| fltIn
> I2_MAX
)
2461 return DISP_E_OVERFLOW
;
2464 *psOut
= (short) fltIn
;
2469 /******************************************************************************
2470 * VarI2FromR8 [OLEAUT32.51]
2472 HRESULT WINAPI
VarI2FromR8(double dblIn
, short* psOut
)
2474 TRACE("( %f, %p ), stub\n", dblIn
, psOut
);
2476 /* Check range of value.
2478 dblIn
= round( dblIn
);
2479 if( dblIn
< I2_MIN
|| dblIn
> I2_MAX
)
2481 return DISP_E_OVERFLOW
;
2484 *psOut
= (short) dblIn
;
2489 /******************************************************************************
2490 * VarI2FromDate [OLEAUT32.53]
2492 HRESULT WINAPI
VarI2FromDate(DATE dateIn
, short* psOut
)
2494 TRACE("( %f, %p ), stub\n", dateIn
, psOut
);
2496 /* Check range of value.
2498 dateIn
= round( dateIn
);
2499 if( dateIn
< I2_MIN
|| dateIn
> I2_MAX
)
2501 return DISP_E_OVERFLOW
;
2504 *psOut
= (short) dateIn
;
2509 /******************************************************************************
2510 * VarI2FromBool [OLEAUT32.56]
2512 HRESULT WINAPI
VarI2FromBool(VARIANT_BOOL boolIn
, short* psOut
)
2514 TRACE("( %d, %p ), stub\n", boolIn
, psOut
);
2516 *psOut
= (short) boolIn
;
2521 /******************************************************************************
2522 * VarI2FromI1 [OLEAUT32.205]
2524 HRESULT WINAPI
VarI2FromI1(CHAR cIn
, short* psOut
)
2526 TRACE("( %c, %p ), stub\n", cIn
, psOut
);
2528 *psOut
= (short) cIn
;
2533 /******************************************************************************
2534 * VarI2FromUI2 [OLEAUT32.206]
2536 HRESULT WINAPI
VarI2FromUI2(USHORT uiIn
, short* psOut
)
2538 TRACE("( %d, %p ), stub\n", uiIn
, psOut
);
2540 /* Check range of value.
2544 return DISP_E_OVERFLOW
;
2547 *psOut
= (short) uiIn
;
2552 /******************************************************************************
2553 * VarI2FromUI4 [OLEAUT32.207]
2555 HRESULT WINAPI
VarI2FromUI4(ULONG ulIn
, short* psOut
)
2557 TRACE("( %lx, %p ), stub\n", ulIn
, psOut
);
2559 /* Check range of value.
2561 if( ulIn
< I2_MIN
|| ulIn
> I2_MAX
)
2563 return DISP_E_OVERFLOW
;
2566 *psOut
= (short) ulIn
;
2571 /******************************************************************************
2572 * VarI2FromStr [OLEAUT32.54]
2574 HRESULT WINAPI
VarI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, short* psOut
)
2576 double dValue
= 0.0;
2577 LPSTR pNewString
= NULL
;
2579 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn
, lcid
, dwFlags
, psOut
);
2581 /* Check if we have a valid argument
2583 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
2584 RemoveCharacterFromString( pNewString
, "," );
2585 if( IsValidRealString( pNewString
) == FALSE
)
2587 return DISP_E_TYPEMISMATCH
;
2590 /* Convert the valid string to a floating point number.
2592 dValue
= atof( pNewString
);
2594 /* We don't need the string anymore so free it.
2596 HeapFree( GetProcessHeap(), 0, pNewString
);
2598 /* Check range of value.
2600 dValue
= round( dValue
);
2601 if( dValue
< I2_MIN
|| dValue
> I2_MAX
)
2603 return DISP_E_OVERFLOW
;
2606 *psOut
= (short) dValue
;
2611 /**********************************************************************
2612 * VarI2FromCy [OLEAUT32.52]
2613 * Convert currency to signed short
2615 HRESULT WINAPI
VarI2FromCy(CY cyIn
, short* psOut
) {
2616 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
2618 if (t
> I2_MAX
|| t
< I2_MIN
) return DISP_E_OVERFLOW
;
2624 /******************************************************************************
2625 * VarI4FromUI1 [OLEAUT32.58]
2627 HRESULT WINAPI
VarI4FromUI1(BYTE bIn
, LONG
* plOut
)
2629 TRACE("( %X, %p ), stub\n", bIn
, plOut
);
2631 *plOut
= (LONG
) bIn
;
2637 /******************************************************************************
2638 * VarI4FromR4 [OLEAUT32.60]
2640 HRESULT WINAPI
VarI4FromR4(FLOAT fltIn
, LONG
* plOut
)
2642 TRACE("( %f, %p ), stub\n", fltIn
, plOut
);
2644 /* Check range of value.
2646 fltIn
= round( fltIn
);
2647 if( fltIn
< I4_MIN
|| fltIn
> I4_MAX
)
2649 return DISP_E_OVERFLOW
;
2652 *plOut
= (LONG
) fltIn
;
2657 /******************************************************************************
2658 * VarI4FromR8 [OLEAUT32.61]
2660 HRESULT WINAPI
VarI4FromR8(double dblIn
, LONG
* plOut
)
2662 TRACE("( %f, %p ), stub\n", dblIn
, plOut
);
2664 /* Check range of value.
2666 dblIn
= round( dblIn
);
2667 if( dblIn
< I4_MIN
|| dblIn
> I4_MAX
)
2669 return DISP_E_OVERFLOW
;
2672 *plOut
= (LONG
) dblIn
;
2677 /******************************************************************************
2678 * VarI4FromDate [OLEAUT32.63]
2680 HRESULT WINAPI
VarI4FromDate(DATE dateIn
, LONG
* plOut
)
2682 TRACE("( %f, %p ), stub\n", dateIn
, plOut
);
2684 /* Check range of value.
2686 dateIn
= round( dateIn
);
2687 if( dateIn
< I4_MIN
|| dateIn
> I4_MAX
)
2689 return DISP_E_OVERFLOW
;
2692 *plOut
= (LONG
) dateIn
;
2697 /******************************************************************************
2698 * VarI4FromBool [OLEAUT32.66]
2700 HRESULT WINAPI
VarI4FromBool(VARIANT_BOOL boolIn
, LONG
* plOut
)
2702 TRACE("( %d, %p ), stub\n", boolIn
, plOut
);
2704 *plOut
= (LONG
) boolIn
;
2709 /******************************************************************************
2710 * VarI4FromI1 [OLEAUT32.209]
2712 HRESULT WINAPI
VarI4FromI1(CHAR cIn
, LONG
* plOut
)
2714 TRACE("( %c, %p ), stub\n", cIn
, plOut
);
2716 *plOut
= (LONG
) cIn
;
2721 /******************************************************************************
2722 * VarI4FromUI2 [OLEAUT32.210]
2724 HRESULT WINAPI
VarI4FromUI2(USHORT uiIn
, LONG
* plOut
)
2726 TRACE("( %d, %p ), stub\n", uiIn
, plOut
);
2728 *plOut
= (LONG
) uiIn
;
2733 /******************************************************************************
2734 * VarI4FromUI4 [OLEAUT32.211]
2736 HRESULT WINAPI
VarI4FromUI4(ULONG ulIn
, LONG
* plOut
)
2738 TRACE("( %lx, %p ), stub\n", ulIn
, plOut
);
2740 /* Check range of value.
2742 if( ulIn
< I4_MIN
|| ulIn
> I4_MAX
)
2744 return DISP_E_OVERFLOW
;
2747 *plOut
= (LONG
) ulIn
;
2752 /******************************************************************************
2753 * VarI4FromI2 [OLEAUT32.59]
2755 HRESULT WINAPI
VarI4FromI2(short sIn
, LONG
* plOut
)
2757 TRACE("( %d, %p ), stub\n", sIn
, plOut
);
2759 *plOut
= (LONG
) sIn
;
2764 /******************************************************************************
2765 * VarI4FromStr [OLEAUT32.64]
2767 HRESULT WINAPI
VarI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG
* plOut
)
2769 double dValue
= 0.0;
2770 LPSTR pNewString
= NULL
;
2772 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn
, lcid
, dwFlags
, plOut
);
2774 /* Check if we have a valid argument
2776 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
2777 RemoveCharacterFromString( pNewString
, "," );
2778 if( IsValidRealString( pNewString
) == FALSE
)
2780 return DISP_E_TYPEMISMATCH
;
2783 /* Convert the valid string to a floating point number.
2785 dValue
= atof( pNewString
);
2787 /* We don't need the string anymore so free it.
2789 HeapFree( GetProcessHeap(), 0, pNewString
);
2791 /* Check range of value.
2793 dValue
= round( dValue
);
2794 if( dValue
< I4_MIN
|| dValue
> I4_MAX
)
2796 return DISP_E_OVERFLOW
;
2799 *plOut
= (LONG
) dValue
;
2804 /**********************************************************************
2805 * VarI4FromCy [OLEAUT32.62]
2806 * Convert currency to signed long
2808 HRESULT WINAPI
VarI4FromCy(CY cyIn
, LONG
* plOut
) {
2809 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
2811 if (t
> I4_MAX
|| t
< I4_MIN
) return DISP_E_OVERFLOW
;
2817 /******************************************************************************
2818 * VarR4FromUI1 [OLEAUT32.68]
2820 HRESULT WINAPI
VarR4FromUI1(BYTE bIn
, FLOAT
* pfltOut
)
2822 TRACE("( %X, %p ), stub\n", bIn
, pfltOut
);
2824 *pfltOut
= (FLOAT
) bIn
;
2829 /******************************************************************************
2830 * VarR4FromI2 [OLEAUT32.69]
2832 HRESULT WINAPI
VarR4FromI2(short sIn
, FLOAT
* pfltOut
)
2834 TRACE("( %d, %p ), stub\n", sIn
, pfltOut
);
2836 *pfltOut
= (FLOAT
) sIn
;
2841 /******************************************************************************
2842 * VarR4FromI4 [OLEAUT32.70]
2844 HRESULT WINAPI
VarR4FromI4(LONG lIn
, FLOAT
* pfltOut
)
2846 TRACE("( %lx, %p ), stub\n", lIn
, pfltOut
);
2848 *pfltOut
= (FLOAT
) lIn
;
2853 /******************************************************************************
2854 * VarR4FromR8 [OLEAUT32.71]
2856 HRESULT WINAPI
VarR4FromR8(double dblIn
, FLOAT
* pfltOut
)
2858 TRACE("( %f, %p ), stub\n", dblIn
, pfltOut
);
2860 /* Check range of value.
2862 if( dblIn
< -(FLT_MAX
) || dblIn
> FLT_MAX
)
2864 return DISP_E_OVERFLOW
;
2867 *pfltOut
= (FLOAT
) dblIn
;
2872 /******************************************************************************
2873 * VarR4FromDate [OLEAUT32.73]
2875 HRESULT WINAPI
VarR4FromDate(DATE dateIn
, FLOAT
* pfltOut
)
2877 TRACE("( %f, %p ), stub\n", dateIn
, pfltOut
);
2879 /* Check range of value.
2881 if( dateIn
< -(FLT_MAX
) || dateIn
> FLT_MAX
)
2883 return DISP_E_OVERFLOW
;
2886 *pfltOut
= (FLOAT
) dateIn
;
2891 /******************************************************************************
2892 * VarR4FromBool [OLEAUT32.76]
2894 HRESULT WINAPI
VarR4FromBool(VARIANT_BOOL boolIn
, FLOAT
* pfltOut
)
2896 TRACE("( %d, %p ), stub\n", boolIn
, pfltOut
);
2898 *pfltOut
= (FLOAT
) boolIn
;
2903 /******************************************************************************
2904 * VarR4FromI1 [OLEAUT32.213]
2906 HRESULT WINAPI
VarR4FromI1(CHAR cIn
, FLOAT
* pfltOut
)
2908 TRACE("( %c, %p ), stub\n", cIn
, pfltOut
);
2910 *pfltOut
= (FLOAT
) cIn
;
2915 /******************************************************************************
2916 * VarR4FromUI2 [OLEAUT32.214]
2918 HRESULT WINAPI
VarR4FromUI2(USHORT uiIn
, FLOAT
* pfltOut
)
2920 TRACE("( %d, %p ), stub\n", uiIn
, pfltOut
);
2922 *pfltOut
= (FLOAT
) uiIn
;
2927 /******************************************************************************
2928 * VarR4FromUI4 [OLEAUT32.215]
2930 HRESULT WINAPI
VarR4FromUI4(ULONG ulIn
, FLOAT
* pfltOut
)
2932 TRACE("( %ld, %p ), stub\n", ulIn
, pfltOut
);
2934 *pfltOut
= (FLOAT
) ulIn
;
2939 /******************************************************************************
2940 * VarR4FromStr [OLEAUT32.74]
2942 HRESULT WINAPI
VarR4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, FLOAT
* pfltOut
)
2944 double dValue
= 0.0;
2945 LPSTR pNewString
= NULL
;
2947 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, pfltOut
);
2949 /* Check if we have a valid argument
2951 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
2952 RemoveCharacterFromString( pNewString
, "," );
2953 if( IsValidRealString( pNewString
) == FALSE
)
2955 return DISP_E_TYPEMISMATCH
;
2958 /* Convert the valid string to a floating point number.
2960 dValue
= atof( pNewString
);
2962 /* We don't need the string anymore so free it.
2964 HeapFree( GetProcessHeap(), 0, pNewString
);
2966 /* Check range of value.
2968 if( dValue
< -(FLT_MAX
) || dValue
> FLT_MAX
)
2970 return DISP_E_OVERFLOW
;
2973 *pfltOut
= (FLOAT
) dValue
;
2978 /**********************************************************************
2979 * VarR4FromCy [OLEAUT32.72]
2980 * Convert currency to float
2982 HRESULT WINAPI
VarR4FromCy(CY cyIn
, FLOAT
* pfltOut
) {
2983 *pfltOut
= (FLOAT
)((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
2988 /******************************************************************************
2989 * VarR8FromUI1 [OLEAUT32.78]
2991 HRESULT WINAPI
VarR8FromUI1(BYTE bIn
, double* pdblOut
)
2993 TRACE("( %d, %p ), stub\n", bIn
, pdblOut
);
2995 *pdblOut
= (double) bIn
;
3000 /******************************************************************************
3001 * VarR8FromI2 [OLEAUT32.79]
3003 HRESULT WINAPI
VarR8FromI2(short sIn
, double* pdblOut
)
3005 TRACE("( %d, %p ), stub\n", sIn
, pdblOut
);
3007 *pdblOut
= (double) sIn
;
3012 /******************************************************************************
3013 * VarR8FromI4 [OLEAUT32.80]
3015 HRESULT WINAPI
VarR8FromI4(LONG lIn
, double* pdblOut
)
3017 TRACE("( %ld, %p ), stub\n", lIn
, pdblOut
);
3019 *pdblOut
= (double) lIn
;
3024 /******************************************************************************
3025 * VarR8FromR4 [OLEAUT32.81]
3027 HRESULT WINAPI
VarR8FromR4(FLOAT fltIn
, double* pdblOut
)
3029 TRACE("( %f, %p ), stub\n", fltIn
, pdblOut
);
3031 *pdblOut
= (double) fltIn
;
3036 /******************************************************************************
3037 * VarR8FromDate [OLEAUT32.83]
3039 HRESULT WINAPI
VarR8FromDate(DATE dateIn
, double* pdblOut
)
3041 TRACE("( %f, %p ), stub\n", dateIn
, pdblOut
);
3043 *pdblOut
= (double) dateIn
;
3048 /******************************************************************************
3049 * VarR8FromBool [OLEAUT32.86]
3051 HRESULT WINAPI
VarR8FromBool(VARIANT_BOOL boolIn
, double* pdblOut
)
3053 TRACE("( %d, %p ), stub\n", boolIn
, pdblOut
);
3055 *pdblOut
= (double) boolIn
;
3060 /******************************************************************************
3061 * VarR8FromI1 [OLEAUT32.217]
3063 HRESULT WINAPI
VarR8FromI1(CHAR cIn
, double* pdblOut
)
3065 TRACE("( %c, %p ), stub\n", cIn
, pdblOut
);
3067 *pdblOut
= (double) cIn
;
3072 /******************************************************************************
3073 * VarR8FromUI2 [OLEAUT32.218]
3075 HRESULT WINAPI
VarR8FromUI2(USHORT uiIn
, double* pdblOut
)
3077 TRACE("( %d, %p ), stub\n", uiIn
, pdblOut
);
3079 *pdblOut
= (double) uiIn
;
3084 /******************************************************************************
3085 * VarR8FromUI4 [OLEAUT32.219]
3087 HRESULT WINAPI
VarR8FromUI4(ULONG ulIn
, double* pdblOut
)
3089 TRACE("( %ld, %p ), stub\n", ulIn
, pdblOut
);
3091 *pdblOut
= (double) ulIn
;
3096 /******************************************************************************
3097 * VarR8FromStr [OLEAUT32.84]
3099 HRESULT WINAPI
VarR8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, double* pdblOut
)
3101 double dValue
= 0.0;
3102 LPSTR pNewString
= NULL
;
3104 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
3105 TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString
, lcid
, dwFlags
, pdblOut
);
3107 /* Check if we have a valid argument
3109 RemoveCharacterFromString( pNewString
, "," );
3110 if( IsValidRealString( pNewString
) == FALSE
)
3112 return DISP_E_TYPEMISMATCH
;
3115 /* Convert the valid string to a floating point number.
3117 dValue
= atof( pNewString
);
3119 /* We don't need the string anymore so free it.
3121 HeapFree( GetProcessHeap(), 0, pNewString
);
3128 /**********************************************************************
3129 * VarR8FromCy [OLEAUT32.82]
3130 * Convert currency to double
3132 HRESULT WINAPI
VarR8FromCy(CY cyIn
, double* pdblOut
) {
3133 *pdblOut
= (double)((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
3134 TRACE("%lu %ld -> %f\n", cyIn
.s
.Hi
, cyIn
.s
.Lo
, *pdblOut
);
3138 /******************************************************************************
3139 * VarDateFromUI1 [OLEAUT32.88]
3141 HRESULT WINAPI
VarDateFromUI1(BYTE bIn
, DATE
* pdateOut
)
3143 TRACE("( %d, %p ), stub\n", bIn
, pdateOut
);
3145 *pdateOut
= (DATE
) bIn
;
3150 /******************************************************************************
3151 * VarDateFromI2 [OLEAUT32.89]
3153 HRESULT WINAPI
VarDateFromI2(short sIn
, DATE
* pdateOut
)
3155 TRACE("( %d, %p ), stub\n", sIn
, pdateOut
);
3157 *pdateOut
= (DATE
) sIn
;
3162 /******************************************************************************
3163 * VarDateFromI4 [OLEAUT32.90]
3165 HRESULT WINAPI
VarDateFromI4(LONG lIn
, DATE
* pdateOut
)
3167 TRACE("( %ld, %p ), stub\n", lIn
, pdateOut
);
3169 if( lIn
< DATE_MIN
|| lIn
> DATE_MAX
)
3171 return DISP_E_OVERFLOW
;
3174 *pdateOut
= (DATE
) lIn
;
3179 /******************************************************************************
3180 * VarDateFromR4 [OLEAUT32.91]
3182 HRESULT WINAPI
VarDateFromR4(FLOAT fltIn
, DATE
* pdateOut
)
3184 TRACE("( %f, %p ), stub\n", fltIn
, pdateOut
);
3186 if( ceil(fltIn
) < DATE_MIN
|| floor(fltIn
) > DATE_MAX
)
3188 return DISP_E_OVERFLOW
;
3191 *pdateOut
= (DATE
) fltIn
;
3196 /******************************************************************************
3197 * VarDateFromR8 [OLEAUT32.92]
3199 HRESULT WINAPI
VarDateFromR8(double dblIn
, DATE
* pdateOut
)
3201 TRACE("( %f, %p ), stub\n", dblIn
, pdateOut
);
3203 if( ceil(dblIn
) < DATE_MIN
|| floor(dblIn
) > DATE_MAX
)
3205 return DISP_E_OVERFLOW
;
3208 *pdateOut
= (DATE
) dblIn
;
3213 /******************************************************************************
3214 * VarDateFromStr [OLEAUT32.94]
3215 * The string representing the date is composed of two parts, a date and time.
3217 * The format of the time is has follows:
3218 * hh[:mm][:ss][AM|PM]
3219 * Whitespace can be inserted anywhere between these tokens. A whitespace consists
3220 * of space and/or tab characters, which are ignored.
3222 * The formats for the date part are has follows:
3226 * January dd[,] [yy]yy
3229 * Whitespace can be inserted anywhere between these tokens.
3231 * The formats for the date and time string are has follows.
3232 * date[whitespace][time]
3233 * [time][whitespace]date
3235 * These are the only characters allowed in a string representing a date and time:
3236 * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3238 HRESULT WINAPI
VarDateFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DATE
* pdateOut
)
3243 memset( &TM
, 0, sizeof(TM
) );
3245 TRACE("( %p, %lx, %lx, %p ), stub\n", strIn
, lcid
, dwFlags
, pdateOut
);
3247 if( DateTimeStringToTm( strIn
, dwFlags
, &TM
) )
3249 if( TmToDATE( &TM
, pdateOut
) == FALSE
)
3256 ret
= DISP_E_TYPEMISMATCH
;
3258 TRACE("Return value %f\n", *pdateOut
);
3262 /******************************************************************************
3263 * VarDateFromI1 [OLEAUT32.221]
3265 HRESULT WINAPI
VarDateFromI1(CHAR cIn
, DATE
* pdateOut
)
3267 TRACE("( %c, %p ), stub\n", cIn
, pdateOut
);
3269 *pdateOut
= (DATE
) cIn
;
3274 /******************************************************************************
3275 * VarDateFromUI2 [OLEAUT32.222]
3277 HRESULT WINAPI
VarDateFromUI2(USHORT uiIn
, DATE
* pdateOut
)
3279 TRACE("( %d, %p ), stub\n", uiIn
, pdateOut
);
3281 if( uiIn
> DATE_MAX
)
3283 return DISP_E_OVERFLOW
;
3286 *pdateOut
= (DATE
) uiIn
;
3291 /******************************************************************************
3292 * VarDateFromUI4 [OLEAUT32.223]
3294 HRESULT WINAPI
VarDateFromUI4(ULONG ulIn
, DATE
* pdateOut
)
3296 TRACE("( %ld, %p ), stub\n", ulIn
, pdateOut
);
3298 if( ulIn
< DATE_MIN
|| ulIn
> DATE_MAX
)
3300 return DISP_E_OVERFLOW
;
3303 *pdateOut
= (DATE
) ulIn
;
3308 /******************************************************************************
3309 * VarDateFromBool [OLEAUT32.96]
3311 HRESULT WINAPI
VarDateFromBool(VARIANT_BOOL boolIn
, DATE
* pdateOut
)
3313 TRACE("( %d, %p ), stub\n", boolIn
, pdateOut
);
3315 *pdateOut
= (DATE
) boolIn
;
3320 /**********************************************************************
3321 * VarDateFromCy [OLEAUT32.93]
3322 * Convert currency to date
3324 HRESULT WINAPI
VarDateFromCy(CY cyIn
, DATE
* pdateOut
) {
3325 *pdateOut
= (DATE
)((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
3327 if (*pdateOut
> DATE_MAX
|| *pdateOut
< DATE_MIN
) return DISP_E_TYPEMISMATCH
;
3331 /******************************************************************************
3332 * VarBstrFromUI1 [OLEAUT32.108]
3334 HRESULT WINAPI
VarBstrFromUI1(BYTE bVal
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3336 TRACE("( %d, %ld, %ld, %p ), stub\n", bVal
, lcid
, dwFlags
, pbstrOut
);
3337 sprintf( pBuffer
, "%d", bVal
);
3339 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3344 /******************************************************************************
3345 * VarBstrFromI2 [OLEAUT32.109]
3347 HRESULT WINAPI
VarBstrFromI2(short iVal
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3349 TRACE("( %d, %ld, %ld, %p ), stub\n", iVal
, lcid
, dwFlags
, pbstrOut
);
3350 sprintf( pBuffer
, "%d", iVal
);
3351 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3356 /******************************************************************************
3357 * VarBstrFromI4 [OLEAUT32.110]
3359 HRESULT WINAPI
VarBstrFromI4(LONG lIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3361 TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn
, lcid
, dwFlags
, pbstrOut
);
3363 sprintf( pBuffer
, "%ld", lIn
);
3364 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3369 /******************************************************************************
3370 * VarBstrFromR4 [OLEAUT32.111]
3372 HRESULT WINAPI
VarBstrFromR4(FLOAT fltIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3374 TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn
, lcid
, dwFlags
, pbstrOut
);
3376 sprintf( pBuffer
, "%.7g", fltIn
);
3377 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3382 /******************************************************************************
3383 * VarBstrFromR8 [OLEAUT32.112]
3385 HRESULT WINAPI
VarBstrFromR8(double dblIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3387 TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn
, lcid
, dwFlags
, pbstrOut
);
3389 sprintf( pBuffer
, "%.15g", dblIn
);
3390 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3395 /******************************************************************************
3396 * VarBstrFromCy [OLEAUT32.113]
3398 HRESULT WINAPI
VarBstrFromCy(CY cyIn
, LCID lcid
, ULONG dwFlags
, BSTR
*pbstrOut
) {
3400 double curVal
= 0.0;
3402 TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid
, dwFlags
, pbstrOut
);
3404 /* Firstly get the currency in a double, then put it in a buffer */
3405 rc
= VarR8FromCy(cyIn
, &curVal
);
3407 sprintf(pBuffer
, "%g", curVal
);
3408 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3414 /******************************************************************************
3415 * VarBstrFromDate [OLEAUT32.114]
3417 * The date is implemented using an 8 byte floating-point number.
3418 * Days are represented by whole numbers increments starting with 0.00 as
3419 * being December 30 1899, midnight.
3420 * The hours are expressed as the fractional part of the number.
3421 * December 30 1899 at midnight = 0.00
3422 * January 1 1900 at midnight = 2.00
3423 * January 4 1900 at 6 AM = 5.25
3424 * January 4 1900 at noon = 5.50
3425 * December 29 1899 at midnight = -1.00
3426 * December 18 1899 at midnight = -12.00
3427 * December 18 1899 at 6AM = -12.25
3428 * December 18 1899 at 6PM = -12.75
3429 * December 19 1899 at midnight = -11.00
3430 * The tm structure is as follows:
3432 * int tm_sec; seconds after the minute - [0,59]
3433 * int tm_min; minutes after the hour - [0,59]
3434 * int tm_hour; hours since midnight - [0,23]
3435 * int tm_mday; day of the month - [1,31]
3436 * int tm_mon; months since January - [0,11]
3437 * int tm_year; years
3438 * int tm_wday; days since Sunday - [0,6]
3439 * int tm_yday; days since January 1 - [0,365]
3440 * int tm_isdst; daylight savings time flag
3443 HRESULT WINAPI
VarBstrFromDate(DATE dateIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3446 memset( &TM
, 0, sizeof(TM
) );
3448 TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn
, lcid
, dwFlags
, pbstrOut
);
3450 if( DateToTm( dateIn
, dwFlags
, &TM
) == FALSE
)
3452 return E_INVALIDARG
;
3455 if( dwFlags
& VAR_DATEVALUEONLY
)
3456 strftime( pBuffer
, BUFFER_MAX
, "%x", &TM
);
3457 else if( dwFlags
& VAR_TIMEVALUEONLY
)
3458 strftime( pBuffer
, BUFFER_MAX
, "%X", &TM
);
3460 strftime( pBuffer
, BUFFER_MAX
, "%x %X", &TM
);
3462 TRACE("result: %s\n", pBuffer
);
3463 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3467 /******************************************************************************
3468 * VarBstrFromBool [OLEAUT32.116]
3470 HRESULT WINAPI
VarBstrFromBool(VARIANT_BOOL boolIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3472 TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn
, lcid
, dwFlags
, pbstrOut
);
3474 sprintf( pBuffer
, (boolIn
== VARIANT_FALSE
) ? "False" : "True" );
3476 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3481 /******************************************************************************
3482 * VarBstrFromI1 [OLEAUT32.229]
3484 HRESULT WINAPI
VarBstrFromI1(CHAR cIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3486 TRACE("( %c, %ld, %ld, %p ), stub\n", cIn
, lcid
, dwFlags
, pbstrOut
);
3487 sprintf( pBuffer
, "%d", cIn
);
3488 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3493 /******************************************************************************
3494 * VarBstrFromUI2 [OLEAUT32.230]
3496 HRESULT WINAPI
VarBstrFromUI2(USHORT uiIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3498 TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn
, lcid
, dwFlags
, pbstrOut
);
3499 sprintf( pBuffer
, "%d", uiIn
);
3500 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3505 /******************************************************************************
3506 * VarBstrFromUI4 [OLEAUT32.231]
3508 HRESULT WINAPI
VarBstrFromUI4(ULONG ulIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3510 TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn
, lcid
, dwFlags
, pbstrOut
);
3511 sprintf( pBuffer
, "%ld", ulIn
);
3512 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3517 /******************************************************************************
3518 * VarBoolFromUI1 [OLEAUT32.118]
3520 HRESULT WINAPI
VarBoolFromUI1(BYTE bIn
, VARIANT_BOOL
* pboolOut
)
3522 TRACE("( %d, %p ), stub\n", bIn
, pboolOut
);
3526 *pboolOut
= VARIANT_FALSE
;
3530 *pboolOut
= VARIANT_TRUE
;
3536 /******************************************************************************
3537 * VarBoolFromI2 [OLEAUT32.119]
3539 HRESULT WINAPI
VarBoolFromI2(short sIn
, VARIANT_BOOL
* pboolOut
)
3541 TRACE("( %d, %p ), stub\n", sIn
, pboolOut
);
3543 *pboolOut
= (sIn
) ? VARIANT_TRUE
: VARIANT_FALSE
;
3548 /******************************************************************************
3549 * VarBoolFromI4 [OLEAUT32.120]
3551 HRESULT WINAPI
VarBoolFromI4(LONG lIn
, VARIANT_BOOL
* pboolOut
)
3553 TRACE("( %ld, %p ), stub\n", lIn
, pboolOut
);
3555 *pboolOut
= (lIn
) ? VARIANT_TRUE
: VARIANT_FALSE
;
3560 /******************************************************************************
3561 * VarBoolFromR4 [OLEAUT32.121]
3563 HRESULT WINAPI
VarBoolFromR4(FLOAT fltIn
, VARIANT_BOOL
* pboolOut
)
3565 TRACE("( %f, %p ), stub\n", fltIn
, pboolOut
);
3567 *pboolOut
= (fltIn
== 0.0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3572 /******************************************************************************
3573 * VarBoolFromR8 [OLEAUT32.122]
3575 HRESULT WINAPI
VarBoolFromR8(double dblIn
, VARIANT_BOOL
* pboolOut
)
3577 TRACE("( %f, %p ), stub\n", dblIn
, pboolOut
);
3579 *pboolOut
= (dblIn
== 0.0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3584 /******************************************************************************
3585 * VarBoolFromDate [OLEAUT32.123]
3587 HRESULT WINAPI
VarBoolFromDate(DATE dateIn
, VARIANT_BOOL
* pboolOut
)
3589 TRACE("( %f, %p ), stub\n", dateIn
, pboolOut
);
3591 *pboolOut
= (dateIn
== 0.0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3596 /******************************************************************************
3597 * VarBoolFromStr [OLEAUT32.125]
3599 HRESULT WINAPI
VarBoolFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, VARIANT_BOOL
* pboolOut
)
3602 char* pNewString
= NULL
;
3604 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, pboolOut
);
3606 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
3608 if( pNewString
== NULL
|| strlen( pNewString
) == 0 )
3610 ret
= DISP_E_TYPEMISMATCH
;
3615 if( strncasecmp( pNewString
, "True", strlen( pNewString
) ) == 0 )
3617 *pboolOut
= VARIANT_TRUE
;
3619 else if( strncasecmp( pNewString
, "False", strlen( pNewString
) ) == 0 )
3621 *pboolOut
= VARIANT_FALSE
;
3625 /* Try converting the string to a floating point number.
3627 double dValue
= 0.0;
3628 HRESULT res
= VarR8FromStr( strIn
, lcid
, dwFlags
, &dValue
);
3631 ret
= DISP_E_TYPEMISMATCH
;
3634 *pboolOut
= (dValue
== 0.0) ?
3635 VARIANT_FALSE
: VARIANT_TRUE
;
3639 HeapFree( GetProcessHeap(), 0, pNewString
);
3644 /******************************************************************************
3645 * VarBoolFromI1 [OLEAUT32.233]
3647 HRESULT WINAPI
VarBoolFromI1(CHAR cIn
, VARIANT_BOOL
* pboolOut
)
3649 TRACE("( %c, %p ), stub\n", cIn
, pboolOut
);
3651 *pboolOut
= (cIn
== 0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3656 /******************************************************************************
3657 * VarBoolFromUI2 [OLEAUT32.234]
3659 HRESULT WINAPI
VarBoolFromUI2(USHORT uiIn
, VARIANT_BOOL
* pboolOut
)
3661 TRACE("( %d, %p ), stub\n", uiIn
, pboolOut
);
3663 *pboolOut
= (uiIn
== 0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3668 /******************************************************************************
3669 * VarBoolFromUI4 [OLEAUT32.235]
3671 HRESULT WINAPI
VarBoolFromUI4(ULONG ulIn
, VARIANT_BOOL
* pboolOut
)
3673 TRACE("( %ld, %p ), stub\n", ulIn
, pboolOut
);
3675 *pboolOut
= (ulIn
== 0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3680 /**********************************************************************
3681 * VarBoolFromCy [OLEAUT32.124]
3682 * Convert currency to boolean
3684 HRESULT WINAPI
VarBoolFromCy(CY cyIn
, VARIANT_BOOL
* pboolOut
) {
3685 if (cyIn
.s
.Hi
|| cyIn
.s
.Lo
) *pboolOut
= -1;
3691 /******************************************************************************
3692 * VarI1FromUI1 [OLEAUT32.244]
3694 HRESULT WINAPI
VarI1FromUI1(BYTE bIn
, CHAR
* pcOut
)
3696 TRACE("( %d, %p ), stub\n", bIn
, pcOut
);
3698 /* Check range of value.
3700 if( bIn
> CHAR_MAX
)
3702 return DISP_E_OVERFLOW
;
3705 *pcOut
= (CHAR
) bIn
;
3710 /******************************************************************************
3711 * VarI1FromI2 [OLEAUT32.245]
3713 HRESULT WINAPI
VarI1FromI2(short uiIn
, CHAR
* pcOut
)
3715 TRACE("( %d, %p ), stub\n", uiIn
, pcOut
);
3717 if( uiIn
> CHAR_MAX
)
3719 return DISP_E_OVERFLOW
;
3722 *pcOut
= (CHAR
) uiIn
;
3727 /******************************************************************************
3728 * VarI1FromI4 [OLEAUT32.246]
3730 HRESULT WINAPI
VarI1FromI4(LONG lIn
, CHAR
* pcOut
)
3732 TRACE("( %ld, %p ), stub\n", lIn
, pcOut
);
3734 if( lIn
< CHAR_MIN
|| lIn
> CHAR_MAX
)
3736 return DISP_E_OVERFLOW
;
3739 *pcOut
= (CHAR
) lIn
;
3744 /******************************************************************************
3745 * VarI1FromR4 [OLEAUT32.247]
3747 HRESULT WINAPI
VarI1FromR4(FLOAT fltIn
, CHAR
* pcOut
)
3749 TRACE("( %f, %p ), stub\n", fltIn
, pcOut
);
3751 fltIn
= round( fltIn
);
3752 if( fltIn
< CHAR_MIN
|| fltIn
> CHAR_MAX
)
3754 return DISP_E_OVERFLOW
;
3757 *pcOut
= (CHAR
) fltIn
;
3762 /******************************************************************************
3763 * VarI1FromR8 [OLEAUT32.248]
3765 HRESULT WINAPI
VarI1FromR8(double dblIn
, CHAR
* pcOut
)
3767 TRACE("( %f, %p ), stub\n", dblIn
, pcOut
);
3769 dblIn
= round( dblIn
);
3770 if( dblIn
< CHAR_MIN
|| dblIn
> CHAR_MAX
)
3772 return DISP_E_OVERFLOW
;
3775 *pcOut
= (CHAR
) dblIn
;
3780 /******************************************************************************
3781 * VarI1FromDate [OLEAUT32.249]
3783 HRESULT WINAPI
VarI1FromDate(DATE dateIn
, CHAR
* pcOut
)
3785 TRACE("( %f, %p ), stub\n", dateIn
, pcOut
);
3787 dateIn
= round( dateIn
);
3788 if( dateIn
< CHAR_MIN
|| dateIn
> CHAR_MAX
)
3790 return DISP_E_OVERFLOW
;
3793 *pcOut
= (CHAR
) dateIn
;
3798 /******************************************************************************
3799 * VarI1FromStr [OLEAUT32.251]
3801 HRESULT WINAPI
VarI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, CHAR
* pcOut
)
3803 double dValue
= 0.0;
3804 LPSTR pNewString
= NULL
;
3806 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, pcOut
);
3808 /* Check if we have a valid argument
3810 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
3811 RemoveCharacterFromString( pNewString
, "," );
3812 if( IsValidRealString( pNewString
) == FALSE
)
3814 return DISP_E_TYPEMISMATCH
;
3817 /* Convert the valid string to a floating point number.
3819 dValue
= atof( pNewString
);
3821 /* We don't need the string anymore so free it.
3823 HeapFree( GetProcessHeap(), 0, pNewString
);
3825 /* Check range of value.
3827 dValue
= round( dValue
);
3828 if( dValue
< CHAR_MIN
|| dValue
> CHAR_MAX
)
3830 return DISP_E_OVERFLOW
;
3833 *pcOut
= (CHAR
) dValue
;
3838 /******************************************************************************
3839 * VarI1FromBool [OLEAUT32.253]
3841 HRESULT WINAPI
VarI1FromBool(VARIANT_BOOL boolIn
, CHAR
* pcOut
)
3843 TRACE("( %d, %p ), stub\n", boolIn
, pcOut
);
3845 *pcOut
= (CHAR
) boolIn
;
3850 /******************************************************************************
3851 * VarI1FromUI2 [OLEAUT32.254]
3853 HRESULT WINAPI
VarI1FromUI2(USHORT uiIn
, CHAR
* pcOut
)
3855 TRACE("( %d, %p ), stub\n", uiIn
, pcOut
);
3857 if( uiIn
> CHAR_MAX
)
3859 return DISP_E_OVERFLOW
;
3862 *pcOut
= (CHAR
) uiIn
;
3867 /******************************************************************************
3868 * VarI1FromUI4 [OLEAUT32.255]
3870 HRESULT WINAPI
VarI1FromUI4(ULONG ulIn
, CHAR
* pcOut
)
3872 TRACE("( %ld, %p ), stub\n", ulIn
, pcOut
);
3874 if( ulIn
> CHAR_MAX
)
3876 return DISP_E_OVERFLOW
;
3879 *pcOut
= (CHAR
) ulIn
;
3884 /**********************************************************************
3885 * VarI1FromCy [OLEAUT32.250]
3886 * Convert currency to signed char
3888 HRESULT WINAPI
VarI1FromCy(CY cyIn
, CHAR
* pcOut
) {
3889 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
3891 if (t
> CHAR_MAX
|| t
< CHAR_MIN
) return DISP_E_OVERFLOW
;
3897 /******************************************************************************
3898 * VarUI2FromUI1 [OLEAUT32.257]
3900 HRESULT WINAPI
VarUI2FromUI1(BYTE bIn
, USHORT
* puiOut
)
3902 TRACE("( %d, %p ), stub\n", bIn
, puiOut
);
3904 *puiOut
= (USHORT
) bIn
;
3909 /******************************************************************************
3910 * VarUI2FromI2 [OLEAUT32.258]
3912 HRESULT WINAPI
VarUI2FromI2(short uiIn
, USHORT
* puiOut
)
3914 TRACE("( %d, %p ), stub\n", uiIn
, puiOut
);
3916 if( uiIn
< UI2_MIN
)
3918 return DISP_E_OVERFLOW
;
3921 *puiOut
= (USHORT
) uiIn
;
3926 /******************************************************************************
3927 * VarUI2FromI4 [OLEAUT32.259]
3929 HRESULT WINAPI
VarUI2FromI4(LONG lIn
, USHORT
* puiOut
)
3931 TRACE("( %ld, %p ), stub\n", lIn
, puiOut
);
3933 if( lIn
< UI2_MIN
|| lIn
> UI2_MAX
)
3935 return DISP_E_OVERFLOW
;
3938 *puiOut
= (USHORT
) lIn
;
3943 /******************************************************************************
3944 * VarUI2FromR4 [OLEAUT32.260]
3946 HRESULT WINAPI
VarUI2FromR4(FLOAT fltIn
, USHORT
* puiOut
)
3948 TRACE("( %f, %p ), stub\n", fltIn
, puiOut
);
3950 fltIn
= round( fltIn
);
3951 if( fltIn
< UI2_MIN
|| fltIn
> UI2_MAX
)
3953 return DISP_E_OVERFLOW
;
3956 *puiOut
= (USHORT
) fltIn
;
3961 /******************************************************************************
3962 * VarUI2FromR8 [OLEAUT32.261]
3964 HRESULT WINAPI
VarUI2FromR8(double dblIn
, USHORT
* puiOut
)
3966 TRACE("( %f, %p ), stub\n", dblIn
, puiOut
);
3968 dblIn
= round( dblIn
);
3969 if( dblIn
< UI2_MIN
|| dblIn
> UI2_MAX
)
3971 return DISP_E_OVERFLOW
;
3974 *puiOut
= (USHORT
) dblIn
;
3979 /******************************************************************************
3980 * VarUI2FromDate [OLEAUT32.262]
3982 HRESULT WINAPI
VarUI2FromDate(DATE dateIn
, USHORT
* puiOut
)
3984 TRACE("( %f, %p ), stub\n", dateIn
, puiOut
);
3986 dateIn
= round( dateIn
);
3987 if( dateIn
< UI2_MIN
|| dateIn
> UI2_MAX
)
3989 return DISP_E_OVERFLOW
;
3992 *puiOut
= (USHORT
) dateIn
;
3997 /******************************************************************************
3998 * VarUI2FromStr [OLEAUT32.264]
4000 HRESULT WINAPI
VarUI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, USHORT
* puiOut
)
4002 double dValue
= 0.0;
4003 LPSTR pNewString
= NULL
;
4005 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, puiOut
);
4007 /* Check if we have a valid argument
4009 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
4010 RemoveCharacterFromString( pNewString
, "," );
4011 if( IsValidRealString( pNewString
) == FALSE
)
4013 return DISP_E_TYPEMISMATCH
;
4016 /* Convert the valid string to a floating point number.
4018 dValue
= atof( pNewString
);
4020 /* We don't need the string anymore so free it.
4022 HeapFree( GetProcessHeap(), 0, pNewString
);
4024 /* Check range of value.
4026 dValue
= round( dValue
);
4027 if( dValue
< UI2_MIN
|| dValue
> UI2_MAX
)
4029 return DISP_E_OVERFLOW
;
4032 *puiOut
= (USHORT
) dValue
;
4037 /******************************************************************************
4038 * VarUI2FromBool [OLEAUT32.266]
4040 HRESULT WINAPI
VarUI2FromBool(VARIANT_BOOL boolIn
, USHORT
* puiOut
)
4042 TRACE("( %d, %p ), stub\n", boolIn
, puiOut
);
4044 *puiOut
= (USHORT
) boolIn
;
4049 /******************************************************************************
4050 * VarUI2FromI1 [OLEAUT32.267]
4052 HRESULT WINAPI
VarUI2FromI1(CHAR cIn
, USHORT
* puiOut
)
4054 TRACE("( %c, %p ), stub\n", cIn
, puiOut
);
4056 *puiOut
= (USHORT
) cIn
;
4061 /******************************************************************************
4062 * VarUI2FromUI4 [OLEAUT32.268]
4064 HRESULT WINAPI
VarUI2FromUI4(ULONG ulIn
, USHORT
* puiOut
)
4066 TRACE("( %ld, %p ), stub\n", ulIn
, puiOut
);
4068 if( ulIn
< UI2_MIN
|| ulIn
> UI2_MAX
)
4070 return DISP_E_OVERFLOW
;
4073 *puiOut
= (USHORT
) ulIn
;
4078 /******************************************************************************
4079 * VarUI4FromStr [OLEAUT32.277]
4081 HRESULT WINAPI
VarUI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG
* pulOut
)
4083 double dValue
= 0.0;
4084 LPSTR pNewString
= NULL
;
4086 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, pulOut
);
4088 /* Check if we have a valid argument
4090 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
4091 RemoveCharacterFromString( pNewString
, "," );
4092 if( IsValidRealString( pNewString
) == FALSE
)
4094 return DISP_E_TYPEMISMATCH
;
4097 /* Convert the valid string to a floating point number.
4099 dValue
= atof( pNewString
);
4101 /* We don't need the string anymore so free it.
4103 HeapFree( GetProcessHeap(), 0, pNewString
);
4105 /* Check range of value.
4107 dValue
= round( dValue
);
4108 if( dValue
< UI4_MIN
|| dValue
> UI4_MAX
)
4110 return DISP_E_OVERFLOW
;
4113 *pulOut
= (ULONG
) dValue
;
4118 /**********************************************************************
4119 * VarUI2FromCy [OLEAUT32.263]
4120 * Convert currency to unsigned short
4122 HRESULT WINAPI
VarUI2FromCy(CY cyIn
, USHORT
* pusOut
) {
4123 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
4125 if (t
> UI2_MAX
|| t
< UI2_MIN
) return DISP_E_OVERFLOW
;
4127 *pusOut
= (USHORT
)t
;
4132 /******************************************************************************
4133 * VarUI4FromUI1 [OLEAUT32.270]
4135 HRESULT WINAPI
VarUI4FromUI1(BYTE bIn
, ULONG
* pulOut
)
4137 TRACE("( %d, %p ), stub\n", bIn
, pulOut
);
4139 *pulOut
= (USHORT
) bIn
;
4144 /******************************************************************************
4145 * VarUI4FromI2 [OLEAUT32.271]
4147 HRESULT WINAPI
VarUI4FromI2(short uiIn
, ULONG
* pulOut
)
4149 TRACE("( %d, %p ), stub\n", uiIn
, pulOut
);
4151 if( uiIn
< UI4_MIN
)
4153 return DISP_E_OVERFLOW
;
4156 *pulOut
= (ULONG
) uiIn
;
4161 /******************************************************************************
4162 * VarUI4FromI4 [OLEAUT32.272]
4164 HRESULT WINAPI
VarUI4FromI4(LONG lIn
, ULONG
* pulOut
)
4166 TRACE("( %ld, %p ), stub\n", lIn
, pulOut
);
4170 return DISP_E_OVERFLOW
;
4173 *pulOut
= (ULONG
) lIn
;
4178 /******************************************************************************
4179 * VarUI4FromR4 [OLEAUT32.273]
4181 HRESULT WINAPI
VarUI4FromR4(FLOAT fltIn
, ULONG
* pulOut
)
4183 fltIn
= round( fltIn
);
4184 if( fltIn
< UI4_MIN
|| fltIn
> UI4_MAX
)
4186 return DISP_E_OVERFLOW
;
4189 *pulOut
= (ULONG
) fltIn
;
4194 /******************************************************************************
4195 * VarUI4FromR8 [OLEAUT32.274]
4197 HRESULT WINAPI
VarUI4FromR8(double dblIn
, ULONG
* pulOut
)
4199 TRACE("( %f, %p ), stub\n", dblIn
, pulOut
);
4201 dblIn
= round( dblIn
);
4202 if( dblIn
< UI4_MIN
|| dblIn
> UI4_MAX
)
4204 return DISP_E_OVERFLOW
;
4207 *pulOut
= (ULONG
) dblIn
;
4212 /******************************************************************************
4213 * VarUI4FromDate [OLEAUT32.275]
4215 HRESULT WINAPI
VarUI4FromDate(DATE dateIn
, ULONG
* pulOut
)
4217 TRACE("( %f, %p ), stub\n", dateIn
, pulOut
);
4219 dateIn
= round( dateIn
);
4220 if( dateIn
< UI4_MIN
|| dateIn
> UI4_MAX
)
4222 return DISP_E_OVERFLOW
;
4225 *pulOut
= (ULONG
) dateIn
;
4230 /******************************************************************************
4231 * VarUI4FromBool [OLEAUT32.279]
4233 HRESULT WINAPI
VarUI4FromBool(VARIANT_BOOL boolIn
, ULONG
* pulOut
)
4235 TRACE("( %d, %p ), stub\n", boolIn
, pulOut
);
4237 *pulOut
= (ULONG
) boolIn
;
4242 /******************************************************************************
4243 * VarUI4FromI1 [OLEAUT32.280]
4245 HRESULT WINAPI
VarUI4FromI1(CHAR cIn
, ULONG
* pulOut
)
4247 TRACE("( %c, %p ), stub\n", cIn
, pulOut
);
4249 *pulOut
= (ULONG
) cIn
;
4254 /******************************************************************************
4255 * VarUI4FromUI2 [OLEAUT32.281]
4257 HRESULT WINAPI
VarUI4FromUI2(USHORT uiIn
, ULONG
* pulOut
)
4259 TRACE("( %d, %p ), stub\n", uiIn
, pulOut
);
4261 *pulOut
= (ULONG
) uiIn
;
4266 /**********************************************************************
4267 * VarUI4FromCy [OLEAUT32.276]
4268 * Convert currency to unsigned long
4270 HRESULT WINAPI
VarUI4FromCy(CY cyIn
, ULONG
* pulOut
) {
4271 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
4273 if (t
> UI4_MAX
|| t
< UI4_MIN
) return DISP_E_OVERFLOW
;
4280 /**********************************************************************
4281 * VarCyFromUI1 [OLEAUT32.98]
4282 * Convert unsigned char to currency
4284 HRESULT WINAPI
VarCyFromUI1(BYTE bIn
, CY
* pcyOut
) {
4286 pcyOut
->s
.Lo
= ((ULONG
)bIn
) * 10000;
4291 /**********************************************************************
4292 * VarCyFromI2 [OLEAUT32.99]
4293 * Convert signed short to currency
4295 HRESULT WINAPI
VarCyFromI2(short sIn
, CY
* pcyOut
) {
4296 if (sIn
< 0) pcyOut
->s
.Hi
= -1;
4297 else pcyOut
->s
.Hi
= 0;
4298 pcyOut
->s
.Lo
= ((ULONG
)sIn
) * 10000;
4303 /**********************************************************************
4304 * VarCyFromI4 [OLEAUT32.100]
4305 * Convert signed long to currency
4307 HRESULT WINAPI
VarCyFromI4(LONG lIn
, CY
* pcyOut
) {
4308 double t
= (double)lIn
* (double)10000;
4309 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4310 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4311 if (lIn
< 0) pcyOut
->s
.Hi
--;
4316 /**********************************************************************
4317 * VarCyFromR4 [OLEAUT32.101]
4318 * Convert float to currency
4320 HRESULT WINAPI
VarCyFromR4(FLOAT fltIn
, CY
* pcyOut
) {
4321 double t
= round((double)fltIn
* (double)10000);
4322 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4323 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4324 if (fltIn
< 0) pcyOut
->s
.Hi
--;
4329 /**********************************************************************
4330 * VarCyFromR8 [OLEAUT32.102]
4331 * Convert double to currency
4333 HRESULT WINAPI
VarCyFromR8(double dblIn
, CY
* pcyOut
) {
4334 double t
= round(dblIn
* (double)10000);
4335 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4336 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4337 if (dblIn
< 0) pcyOut
->s
.Hi
--;
4342 /**********************************************************************
4343 * VarCyFromDate [OLEAUT32.103]
4344 * Convert date to currency
4346 HRESULT WINAPI
VarCyFromDate(DATE dateIn
, CY
* pcyOut
) {
4347 double t
= round((double)dateIn
* (double)10000);
4348 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4349 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4350 if (dateIn
< 0) pcyOut
->s
.Hi
--;
4355 /**********************************************************************
4356 * VarCyFromStr [OLEAUT32.104]
4357 * FIXME: Never tested with decimal seperator other than '.'
4359 HRESULT WINAPI
VarCyFromStr(OLECHAR
*strIn
, LCID lcid
, ULONG dwFlags
, CY
*pcyOut
) {
4361 LPSTR pNewString
= NULL
;
4362 char *decSep
= NULL
;
4363 char *strPtr
,*curPtr
= NULL
;
4365 double currencyVal
= 0.0;
4368 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
4369 TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString
, lcid
, dwFlags
, pcyOut
);
4371 /* Get locale information - Decimal Seperator (size includes 0x00) */
4372 size
= GetLocaleInfoA(lcid
, LOCALE_SDECIMAL
, NULL
, 0);
4373 decSep
= (char *) malloc(size
);
4374 rc
= GetLocaleInfoA(lcid
, LOCALE_SDECIMAL
, decSep
, size
);
4375 TRACE("Decimal Seperator is '%s'\n", decSep
);
4377 /* Now copy to temporary buffer, skipping any character except 0-9 and
4378 the decimal seperator */
4379 curPtr
= pBuffer
; /* Current position in string being built */
4380 strPtr
= pNewString
; /* Current position in supplied currenct string */
4383 /* If decimal seperator, skip it and put '.' in string */
4384 if (strncmp(strPtr
, decSep
, (size
-1)) == 0) {
4385 strPtr
= strPtr
+ (size
-1);
4388 } else if ((*strPtr
== '+' || *strPtr
== '-') ||
4389 (*strPtr
>= '0' && *strPtr
<= '9')) {
4397 /* Try to get currency into a double */
4398 currencyVal
= atof(pBuffer
);
4399 TRACE("Converted string '%s' to %f\n", pBuffer
, currencyVal
);
4401 /* Free allocated storage */
4402 HeapFree( GetProcessHeap(), 0, pNewString
);
4405 /* Convert double -> currency using internal routine */
4406 return VarCyFromR8(currencyVal
, pcyOut
);
4410 /**********************************************************************
4411 * VarCyFromBool [OLEAUT32.106]
4412 * Convert boolean to currency
4414 HRESULT WINAPI
VarCyFromBool(VARIANT_BOOL boolIn
, CY
* pcyOut
) {
4415 if (boolIn
< 0) pcyOut
->s
.Hi
= -1;
4416 else pcyOut
->s
.Hi
= 0;
4417 pcyOut
->s
.Lo
= (ULONG
)boolIn
* (ULONG
)10000;
4422 /**********************************************************************
4423 * VarCyFromI1 [OLEAUT32.225]
4424 * Convert signed char to currency
4426 HRESULT WINAPI
VarCyFromI1(signed char cIn
, CY
* pcyOut
) {
4427 if (cIn
< 0) pcyOut
->s
.Hi
= -1;
4428 else pcyOut
->s
.Hi
= 0;
4429 pcyOut
->s
.Lo
= (ULONG
)cIn
* (ULONG
)10000;
4434 /**********************************************************************
4435 * VarCyFromUI2 [OLEAUT32.226]
4436 * Convert unsigned short to currency
4438 HRESULT WINAPI
VarCyFromUI2(USHORT usIn
, CY
* pcyOut
) {
4440 pcyOut
->s
.Lo
= (ULONG
)usIn
* (ULONG
)10000;
4445 /**********************************************************************
4446 * VarCyFromUI4 [OLEAUT32.227]
4447 * Convert unsigned long to currency
4449 HRESULT WINAPI
VarCyFromUI4(ULONG ulIn
, CY
* pcyOut
) {
4450 double t
= (double)ulIn
* (double)10000;
4451 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4452 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4458 /**********************************************************************
4459 * DosDateTimeToVariantTime [OLEAUT32.14]
4460 * Convert dos representation of time to the date and time representation
4461 * stored in a variant.
4463 INT WINAPI
DosDateTimeToVariantTime(USHORT wDosDate
, USHORT wDosTime
,
4468 TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate
, wDosTime
, pvtime
);
4470 t
.tm_sec
= (wDosTime
& 0x001f) * 2;
4471 t
.tm_min
= (wDosTime
& 0x07e0) >> 5;
4472 t
.tm_hour
= (wDosTime
& 0xf800) >> 11;
4474 t
.tm_mday
= (wDosDate
& 0x001f);
4475 t
.tm_mon
= (wDosDate
& 0x01e0) >> 5;
4476 t
.tm_year
= ((wDosDate
& 0xfe00) >> 9) + 1980;
4478 return TmToDATE( &t
, pvtime
);
4482 /**********************************************************************
4483 * VarParseNumFromStr [OLEAUT32.46]
4485 HRESULT WINAPI
VarParseNumFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
,
4486 NUMPARSE
* pnumprs
, BYTE
* rgbDig
)
4490 BOOL foundNum
=FALSE
;
4492 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn
),dwFlags
);
4493 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs
->cDig
,pnumprs
->dwInFlags
);
4495 /* The other struct components are to be set by us */
4496 memset(rgbDig
,0,pnumprs
->cDig
);
4498 /* FIXME: Just patching some values in */
4499 pnumprs
->nPwr10
= 0;
4500 pnumprs
->nBaseShift
= 0;
4501 pnumprs
->cchUsed
= lastent
;
4502 pnumprs
->dwOutFlags
= NUMPRS_DECIMAL
;
4505 for (i
=0; strIn
[i
] ;i
++) {
4506 if ((strIn
[i
]>='0') && (strIn
[i
]<='9')) {
4508 if (pnumprs
->cDig
> cDig
) {
4509 *(rgbDig
++)=strIn
[i
]-'0';
4513 } else if ((strIn
[i
]=='-') && (foundNum
==FALSE
)) {
4514 pnumprs
->dwOutFlags
|= NUMPRS_NEG
;
4517 pnumprs
->cDig
= cDig
;
4518 TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs
->cDig
,pnumprs
->dwOutFlags
);
4523 /**********************************************************************
4524 * VarNumFromParseNum [OLEAUT32.47]
4526 HRESULT WINAPI
VarNumFromParseNum(NUMPARSE
* pnumprs
, BYTE
* rgbDig
,
4527 ULONG dwVtBits
, VARIANT
* pvar
)
4531 FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits
);
4534 for (i
=0;i
<pnumprs
->cDig
;i
++)
4535 xint
= xint
*10 + rgbDig
[i
];
4537 if (pnumprs
->dwOutFlags
& NUMPRS_NEG
) {
4542 if (dwVtBits
& VTBIT_I4
) {
4544 V_UNION(pvar
,intVal
) = xint
;
4547 if (dwVtBits
& VTBIT_R8
) {
4549 V_UNION(pvar
,dblVal
) = xint
;
4552 if (dwVtBits
& VTBIT_R4
) {
4554 V_UNION(pvar
,fltVal
) = xint
;
4557 if (dwVtBits
& VTBIT_I2
) {
4559 V_UNION(pvar
,iVal
) = xint
;
4562 /* FIXME: Currency should be from a double */
4563 if (dwVtBits
& VTBIT_CY
) {
4565 TRACE("Calculated currency is xint=%ld\n", xint
);
4566 VarCyFromInt( (int) xint
, &V_UNION(pvar
,cyVal
) );
4567 TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar
,cyVal
).s
.Hi
, V_UNION(pvar
,cyVal
).s
.Lo
);
4568 return VarCyFromInt( (int) xint
, &V_UNION(pvar
,cyVal
) );
4571 FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits
, (int) xint
);
4576 /**********************************************************************
4577 * VariantTimeToDosDateTime [OLEAUT32.13]
4578 * Convert variant representation of time to the date and time representation
4581 INT WINAPI
VariantTimeToDosDateTime(DATE pvtime
, USHORT
*wDosDate
, USHORT
*wDosTime
)
4587 TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate
, *wDosTime
, &pvtime
);
4589 if (DateToTm(pvtime
, 0, &t
) < 0) return 0;
4591 *wDosTime
= *wDosTime
| (t
.tm_sec
/ 2);
4592 *wDosTime
= *wDosTime
| (t
.tm_min
<< 5);
4593 *wDosTime
= *wDosTime
| (t
.tm_hour
<< 11);
4595 *wDosDate
= *wDosDate
| t
.tm_mday
;
4596 *wDosDate
= *wDosDate
| t
.tm_mon
<< 5;
4597 *wDosDate
= *wDosDate
| ((t
.tm_year
- 1980) << 9) ;
4603 /***********************************************************************
4604 * SystemTimeToVariantTime [OLEAUT32.184]
4606 HRESULT WINAPI
SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime
, double *pvtime
)
4610 TRACE(" %d/%d/%d %d:%d:%d\n",
4611 lpSystemTime
->wMonth
, lpSystemTime
->wDay
,
4612 lpSystemTime
->wYear
, lpSystemTime
->wHour
,
4613 lpSystemTime
->wMinute
, lpSystemTime
->wSecond
);
4615 if (lpSystemTime
->wYear
>= 1900)
4617 t
.tm_sec
= lpSystemTime
->wSecond
;
4618 t
.tm_min
= lpSystemTime
->wMinute
;
4619 t
.tm_hour
= lpSystemTime
->wHour
;
4621 t
.tm_mday
= lpSystemTime
->wDay
;
4622 t
.tm_mon
= lpSystemTime
->wMonth
- 1; /* tm_mon is 0..11, wMonth is 1..12 */
4623 t
.tm_year
= lpSystemTime
->wYear
;
4625 return TmToDATE( &t
, pvtime
);
4630 long firstDayOfNextYear
;
4635 double decimalPart
= 0.0;
4637 t
.tm_sec
= lpSystemTime
->wSecond
;
4638 t
.tm_min
= lpSystemTime
->wMinute
;
4639 t
.tm_hour
= lpSystemTime
->wHour
;
4641 /* Step year forward the same number of years before 1900 */
4642 t
.tm_year
= 1900 + 1899 - lpSystemTime
->wYear
;
4643 t
.tm_mon
= lpSystemTime
->wMonth
- 1;
4644 t
.tm_mday
= lpSystemTime
->wDay
;
4646 /* Calculate date */
4647 TmToDATE( &t
, pvtime
);
4649 thisDay
= (double) floor( *pvtime
);
4650 decimalPart
= fmod( *pvtime
, thisDay
);
4652 /* Now, calculate the same time for the first of Jan that year */
4658 t
.tm_year
= t
.tm_year
+1;
4659 TmToDATE( &t
, &tmpDate
);
4660 firstDayOfNextYear
= (long) floor(tmpDate
);
4662 /* Finally since we know the size of the year, subtract the two to get
4663 remaining time in the year */
4664 leftInYear
= firstDayOfNextYear
- thisDay
;
4666 /* Now we want full years up to the year in question, and remainder of year
4667 of the year in question */
4668 if (isleap(lpSystemTime
->wYear
) ) {
4669 TRACE("Extra day due to leap year\n");
4670 result
= 2.0 - ((firstDayOfNextYear
- 366) + leftInYear
- 2.0);
4672 result
= 2.0 - ((firstDayOfNextYear
- 365) + leftInYear
- 2.0);
4674 *pvtime
= (double) result
+ decimalPart
;
4675 TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime
, firstDayOfNextYear
, thisDay
, leftInYear
);
4683 /***********************************************************************
4684 * VariantTimeToSystemTime [OLEAUT32.185]
4686 HRESULT WINAPI
VariantTimeToSystemTime( double vtime
, LPSYSTEMTIME lpSystemTime
)
4688 double t
= 0, timeofday
= 0;
4690 static const BYTE Days_Per_Month
[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4691 static const BYTE Days_Per_Month_LY
[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4693 /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4694 static const BYTE Month_Code
[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4695 static const BYTE Month_Code_LY
[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4697 /* The Century_Code is used to find the Day of the Week */
4698 static const BYTE Century_Code
[] = {0, 6, 4, 2};
4702 TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime
, lpSystemTime
);
4707 if (DateToTm(vtime
, 0, &r
) <= 0) return 0;
4709 lpSystemTime
->wSecond
= r
.tm_sec
;
4710 lpSystemTime
->wMinute
= r
.tm_min
;
4711 lpSystemTime
->wHour
= r
.tm_hour
;
4712 lpSystemTime
->wDay
= r
.tm_mday
;
4713 lpSystemTime
->wMonth
= r
.tm_mon
;
4715 if (lpSystemTime
->wMonth
== 12)
4716 lpSystemTime
->wMonth
= 1;
4718 lpSystemTime
->wMonth
++;
4720 lpSystemTime
->wYear
= r
.tm_year
;
4726 if (DateToTm(vtime
, 0, &r
) <= 0) return 0;
4728 lpSystemTime
->wSecond
= r
.tm_sec
;
4729 lpSystemTime
->wMinute
= r
.tm_min
;
4730 lpSystemTime
->wHour
= r
.tm_hour
;
4732 lpSystemTime
->wMonth
= 13 - r
.tm_mon
;
4734 if (lpSystemTime
->wMonth
== 1)
4735 lpSystemTime
->wMonth
= 12;
4737 lpSystemTime
->wMonth
--;
4739 lpSystemTime
->wYear
= 1899 - (r
.tm_year
- 1900);
4741 if (!isleap(lpSystemTime
->wYear
) )
4742 lpSystemTime
->wDay
= Days_Per_Month
[13 - lpSystemTime
->wMonth
] - r
.tm_mday
;
4744 lpSystemTime
->wDay
= Days_Per_Month_LY
[13 - lpSystemTime
->wMonth
] - r
.tm_mday
;
4749 if (!isleap(lpSystemTime
->wYear
))
4752 (Century_Code+Month_Code+Year_Code+Day) % 7
4754 The century code repeats every 400 years , so the array
4755 works out like this,
4757 Century_Code[0] is for 16th/20th Centry
4758 Century_Code[1] is for 17th/21th Centry
4759 Century_Code[2] is for 18th/22th Centry
4760 Century_Code[3] is for 19th/23th Centry
4762 The year code is found with the formula (year + (year / 4))
4763 the "year" must be between 0 and 99 .
4765 The Month Code (Month_Code[1]) starts with January and
4769 lpSystemTime
->wDayOfWeek
= (
4770 Century_Code
[(( (lpSystemTime
->wYear
+100) - lpSystemTime
->wYear
%100) /100) %4]+
4771 ((lpSystemTime
->wYear
%100)+(lpSystemTime
->wYear
%100)/4)+
4772 Month_Code
[lpSystemTime
->wMonth
]+
4773 lpSystemTime
->wDay
) % 7;
4775 if (lpSystemTime
->wDayOfWeek
== 0) lpSystemTime
->wDayOfWeek
= 7;
4776 else lpSystemTime
->wDayOfWeek
-= 1;
4780 lpSystemTime
->wDayOfWeek
= (
4781 Century_Code
[(((lpSystemTime
->wYear
+100) - lpSystemTime
->wYear
%100)/100)%4]+
4782 ((lpSystemTime
->wYear
%100)+(lpSystemTime
->wYear
%100)/4)+
4783 Month_Code_LY
[lpSystemTime
->wMonth
]+
4784 lpSystemTime
->wDay
) % 7;
4786 if (lpSystemTime
->wDayOfWeek
== 0) lpSystemTime
->wDayOfWeek
= 7;
4787 else lpSystemTime
->wDayOfWeek
-= 1;
4791 timeofday
= vtime
- t
;
4793 lpSystemTime
->wMilliseconds
= (timeofday
4794 - lpSystemTime
->wHour
*(1/24)
4795 - lpSystemTime
->wMinute
*(1/1440)
4796 - lpSystemTime
->wSecond
*(1/86400) )*(1/5184000);
4801 /***********************************************************************
4802 * VarUdateFromDate [OLEAUT32.331]
4804 HRESULT WINAPI
VarUdateFromDate( DATE datein
, ULONG dwFlags
, UDATE
*pudateout
)
4807 static const BYTE Days_Per_Month
[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4808 static const BYTE Days_Per_Month_LY
[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4810 TRACE("DATE = %f\n", (double)datein
);
4811 i
= VariantTimeToSystemTime(datein
, &(pudateout
->st
) );
4815 pudateout
->wDayOfYear
= 0;
4817 if (isleap(pudateout
->st
.wYear
))
4819 for (i
=1; i
<pudateout
->st
.wMonth
; i
++)
4820 pudateout
->wDayOfYear
+= Days_Per_Month
[i
];
4824 for (i
=1; i
<pudateout
->st
.wMonth
; i
++)
4825 pudateout
->wDayOfYear
+= Days_Per_Month_LY
[i
];
4828 pudateout
->wDayOfYear
+= pudateout
->st
.wDay
;
4829 dwFlags
= 0; /*VAR_VALIDDATE*/
4836 /***********************************************************************
4837 * VarDateFromUdate [OLEAUT32.330]
4839 HRESULT WINAPI
VarDateFromUdate(UDATE
*pudateout
,
4840 ULONG dwFlags
, DATE
*datein
)
4844 TRACE(" %d/%d/%d %d:%d:%d\n",
4845 pudateout
->st
.wMonth
, pudateout
->st
.wDay
,
4846 pudateout
->st
.wYear
, pudateout
->st
.wHour
,
4847 pudateout
->st
.wMinute
, pudateout
->st
.wSecond
);
4850 i
= SystemTimeToVariantTime(&(pudateout
->st
), &t
);
4854 else return E_INVALIDARG
;
4858 /**********************************************************************
4859 * VarBstrCmp [OLEAUT32.440]
4862 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4863 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4866 HRESULT WINAPI
VarBstrCmp(BSTR left
, BSTR right
, LCID lcid
, DWORD flags
)
4870 TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left
), debugstr_w(right
), lcid
, flags
);
4872 /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
4873 if((!left
) || (!right
)) {
4875 if (!left
&& (!right
|| *right
==0)) return VARCMP_EQ
;
4876 else if (!right
&& (!left
|| *left
==0)) return VARCMP_EQ
;
4877 else return VARCMP_NULL
;
4880 if(flags
&NORM_IGNORECASE
)
4881 r
= lstrcmpiW(left
,right
);
4883 r
= lstrcmpW(left
,right
);
4893 /**********************************************************************
4894 * VarBstrCat [OLEAUT32.439]
4896 HRESULT WINAPI
VarBstrCat(BSTR left
, BSTR right
, BSTR
*out
)
4900 TRACE("( %s %s %p )\n", debugstr_w(left
), debugstr_w(right
), out
);
4902 if( (!left
) || (!right
) || (!out
) )
4905 result
= SysAllocStringLen(left
, lstrlenW(left
)+lstrlenW(right
));
4906 lstrcatW(result
,right
);
4913 /**********************************************************************
4914 * VarCat [OLEAUT32.441]
4916 HRESULT WINAPI
VarCat(LPVARIANT left
, LPVARIANT right
, LPVARIANT out
)
4918 /* Should we VariantClear out? */
4919 /* Can we handle array, vector, by ref etc. */
4920 if ((V_VT(left
)&VT_TYPEMASK
) == VT_NULL
&&
4921 (V_VT(right
)&VT_TYPEMASK
) == VT_NULL
)
4923 V_VT(out
) = VT_NULL
;
4926 else if (V_VT(left
) == VT_BSTR
&& V_VT(right
) == VT_BSTR
)
4928 V_VT(out
) = VT_BSTR
;
4929 VarBstrCat (V_BSTR(left
), V_BSTR(right
), &V_BSTR(out
));
4933 FIXME ("types not supported\n");
4937 /**********************************************************************
4938 * VarCmp [OLEAUT32.442]
4941 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4942 * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4945 HRESULT WINAPI
VarCmp(LPVARIANT left
, LPVARIANT right
, LCID lcid
, DWORD flags
)
4954 TRACE("Left Var:\n");
4956 TRACE("Right Var:\n");
4957 dump_Variant(right
);
4959 /* If either are null, then return VARCMP_NULL */
4960 if ((V_VT(left
)&VT_TYPEMASK
) == VT_NULL
||
4961 (V_VT(right
)&VT_TYPEMASK
) == VT_NULL
)
4964 /* Strings - use VarBstrCmp */
4965 if ((V_VT(left
)&VT_TYPEMASK
) == VT_BSTR
&&
4966 (V_VT(right
)&VT_TYPEMASK
) == VT_BSTR
) {
4967 return VarBstrCmp(V_BSTR(left
), V_BSTR(right
), lcid
, flags
);
4970 /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
4971 Use LONGLONG to maximize ranges */
4973 switch (V_VT(left
)&VT_TYPEMASK
) {
4974 case VT_I1
: lVal
= V_UNION(left
,cVal
); break;
4975 case VT_I2
: lVal
= V_UNION(left
,iVal
); break;
4976 case VT_I4
: lVal
= V_UNION(left
,lVal
); break;
4977 case VT_INT
: lVal
= V_UNION(left
,lVal
); break;
4978 case VT_UI1
: lVal
= V_UNION(left
,bVal
); break;
4979 case VT_UI2
: lVal
= V_UNION(left
,uiVal
); break;
4980 case VT_UI4
: lVal
= V_UNION(left
,ulVal
); break;
4981 case VT_UINT
: lVal
= V_UNION(left
,ulVal
); break;
4982 default: lOk
= FALSE
;
4986 switch (V_VT(right
)&VT_TYPEMASK
) {
4987 case VT_I1
: rVal
= V_UNION(right
,cVal
); break;
4988 case VT_I2
: rVal
= V_UNION(right
,iVal
); break;
4989 case VT_I4
: rVal
= V_UNION(right
,lVal
); break;
4990 case VT_INT
: rVal
= V_UNION(right
,lVal
); break;
4991 case VT_UI1
: rVal
= V_UNION(right
,bVal
); break;
4992 case VT_UI2
: rVal
= V_UNION(right
,uiVal
); break;
4993 case VT_UI4
: rVal
= V_UNION(right
,ulVal
); break;
4994 case VT_UINT
: rVal
= V_UNION(right
,ulVal
); break;
4995 default: rOk
= FALSE
;
5001 } else if (lVal
> rVal
) {
5008 /* Strings - use VarBstrCmp */
5009 if ((V_VT(left
)&VT_TYPEMASK
) == VT_DATE
&&
5010 (V_VT(right
)&VT_TYPEMASK
) == VT_DATE
) {
5012 if (floor(V_UNION(left
,date
)) == floor(V_UNION(right
,date
))) {
5013 /* Due to floating point rounding errors, calculate varDate in whole numbers) */
5014 double wholePart
= 0.0;
5018 /* Get the fraction * 24*60*60 to make it into whole seconds */
5019 wholePart
= (double) floor( V_UNION(left
,date
) );
5020 if (wholePart
== 0) wholePart
= 1;
5021 leftR
= floor(fmod( V_UNION(left
,date
), wholePart
) * (24*60*60));
5023 wholePart
= (double) floor( V_UNION(right
,date
) );
5024 if (wholePart
== 0) wholePart
= 1;
5025 rightR
= floor(fmod( V_UNION(right
,date
), wholePart
) * (24*60*60));
5027 if (leftR
< rightR
) {
5029 } else if (leftR
> rightR
) {
5035 } else if (V_UNION(left
,date
) < V_UNION(right
,date
)) {
5037 } else if (V_UNION(left
,date
) > V_UNION(right
,date
)) {
5043 FIXME("VarCmp partial implementation, doesnt support these pair of variant types");
5047 /**********************************************************************
5048 * VarAnd [OLEAUT32.438]
5051 HRESULT WINAPI
VarAnd(LPVARIANT left
, LPVARIANT right
, LPVARIANT result
)
5053 HRESULT rc
= E_FAIL
;
5056 TRACE("Left Var:\n");
5058 TRACE("Right Var:\n");
5059 dump_Variant(right
);
5061 if ((V_VT(left
)&VT_TYPEMASK
) == VT_BOOL
&&
5062 (V_VT(right
)&VT_TYPEMASK
) == VT_BOOL
) {
5064 V_VT(result
) = VT_BOOL
;
5065 if (V_BOOL(left
) && V_BOOL(right
)) {
5066 V_BOOL(result
) = VARIANT_TRUE
;
5068 V_BOOL(result
) = VARIANT_FALSE
;
5073 FIXME("VarAnd stub\n");
5076 TRACE("rc=%d, Result:\n", (int) rc
);
5077 dump_Variant(result
);
5081 /**********************************************************************
5082 * VarNot [OLEAUT32.482]
5085 HRESULT WINAPI
VarNot(LPVARIANT in
, LPVARIANT result
)
5087 HRESULT rc
= E_FAIL
;
5092 if ((V_VT(in
)&VT_TYPEMASK
) == VT_BOOL
) {
5094 V_VT(result
) = VT_BOOL
;
5096 V_BOOL(result
) = VARIANT_FALSE
;
5098 V_BOOL(result
) = VARIANT_TRUE
;
5103 FIXME("VarNot stub\n");
5106 TRACE("rc=%d, Result:\n", (int) rc
);
5107 dump_Variant(result
);
5111 /**********************************************************************
5112 * VarTokenizeFormatString [OLEAUT32.490]
5114 * From investigation on W2K, a list is built up which is:
5116 * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
5117 * <token> - Insert appropriate token
5120 HRESULT
VarTokenizeFormatString(LPOLESTR format
, LPBYTE rgbTok
,
5121 int cbTok
, int iFirstDay
, int iFirstWeek
,
5122 LCID lcid
, int *pcbActual
) {
5125 int realLen
, formatLeft
;
5127 LPSTR pFormatA
, pStart
;
5129 BOOL insertCopy
= FALSE
;
5130 LPSTR copyFrom
= NULL
;
5132 TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format
), rgbTok
, cbTok
,
5133 iFirstDay
, iFirstWeek
);
5135 /* Big enough for header? */
5136 if (cbTok
< sizeof(FORMATHDR
)) {
5137 return TYPE_E_BUFFERTOOSMALL
;
5141 hdr
= (FORMATHDR
*) rgbTok
;
5142 memset(hdr
, 0x00, sizeof(FORMATHDR
));
5143 hdr
->hex3
= 0x03; /* No idea what these are */
5146 /* Start parsing string */
5147 realLen
= sizeof(FORMATHDR
);
5148 pData
= rgbTok
+ realLen
;
5149 pFormatA
= HEAP_strdupWtoA( GetProcessHeap(), 0, format
);
5151 formatLeft
= strlen(pFormatA
);
5153 /* Work through the format */
5154 while (*pFormatA
!= 0x00) {
5157 while (checkStr
>=0 && (formatTokens
[checkStr
].tokenSize
!= 0x00)) {
5158 if (formatLeft
>= formatTokens
[checkStr
].tokenSize
&&
5159 strncmp(formatTokens
[checkStr
].str
, pFormatA
,
5160 formatTokens
[checkStr
].tokenSize
) == 0) {
5161 TRACE("match on '%s'\n", formatTokens
[checkStr
].str
);
5165 /* If we have skipped chars, insert the copy */
5166 if (insertCopy
== TRUE
) {
5168 if ((realLen
+ 3) > cbTok
) {
5169 HeapFree( GetProcessHeap(), 0, pFormatA
);
5170 return TYPE_E_BUFFERTOOSMALL
;
5175 *pData
= (BYTE
)(copyFrom
- pStart
);
5177 *pData
= (BYTE
)(pFormatA
- copyFrom
);
5179 realLen
= realLen
+ 3;
5183 /* Now insert the token itself */
5184 if ((realLen
+ 1) > cbTok
) {
5185 HeapFree( GetProcessHeap(), 0, pFormatA
);
5186 return TYPE_E_BUFFERTOOSMALL
;
5188 *pData
= formatTokens
[checkStr
].tokenId
;
5190 realLen
= realLen
+ 1;
5192 pFormatA
= pFormatA
+ formatTokens
[checkStr
].tokenSize
;
5193 formatLeft
= formatLeft
- formatTokens
[checkStr
].tokenSize
;
5194 checkStr
= -1; /* Flag as found and break out of while loop */
5200 /* Did we ever match a token? */
5201 if (checkStr
!= -1 && insertCopy
== FALSE
) {
5202 TRACE("No match - need to insert copy from %p [%p]\n", pFormatA
, pStart
);
5204 copyFrom
= pFormatA
;
5205 } else if (checkStr
!= -1) {
5206 pFormatA
= pFormatA
+ 1;
5211 /* Finally, if we have skipped chars, insert the copy */
5212 if (insertCopy
== TRUE
) {
5214 TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom
, pStart
, pFormatA
);
5215 if ((realLen
+ 3) > cbTok
) {
5216 HeapFree( GetProcessHeap(), 0, pFormatA
);
5217 return TYPE_E_BUFFERTOOSMALL
;
5222 *pData
= (BYTE
)(copyFrom
- pStart
);
5224 *pData
= (BYTE
)(pFormatA
- copyFrom
);
5226 realLen
= realLen
+ 3;
5229 /* Finally insert the terminator */
5230 if ((realLen
+ 1) > cbTok
) {
5231 HeapFree( GetProcessHeap(), 0, pFormatA
);
5232 return TYPE_E_BUFFERTOOSMALL
;
5235 realLen
= realLen
+ 1;
5237 /* Finally fill in the length */
5239 *pcbActual
= realLen
;
5243 for (i
=0; i
<realLen
; i
=i
+0x10) {
5244 printf(" %4.4x : ", i
);
5245 for (j
=0; j
<0x10 && (i
+j
< realLen
); j
++) {
5246 printf("%2.2x ", rgbTok
[i
+j
]);
5252 HeapFree( GetProcessHeap(), 0, pFormatA
);
5257 /**********************************************************************
5258 * VarFormatFromTokens [OLEAUT32.472]
5259 * FIXME: No account of flags or iFirstDay etc
5261 HRESULT
VarFormatFromTokens(LPVARIANT varIn
, LPOLESTR format
,
5262 LPBYTE pbTokCur
, ULONG dwFlags
, BSTR
*pbstrOut
,
5265 FORMATHDR
*hdr
= (FORMATHDR
*)pbTokCur
;
5266 BYTE
*pData
= pbTokCur
+ sizeof (FORMATHDR
);
5267 LPSTR pFormatA
= HEAP_strdupWtoA( GetProcessHeap(), 0, format
);
5268 char output
[BUFFER_MAX
];
5270 int size
, whichToken
;
5276 TRACE("'%s', %p %lx %p only date support\n", pFormatA
, pbTokCur
, dwFlags
, pbstrOut
);
5278 dump_Variant(varIn
);
5280 memset(output
, 0x00, BUFFER_MAX
);
5283 while (*pData
!= TOK_END
&& ((pData
- pbTokCur
) <= (hdr
->len
))) {
5285 TRACE("Output looks like : '%s'\n", output
);
5287 /* Convert varient to appropriate data type */
5289 while ((formatTokens
[whichToken
].tokenSize
!= 0x00) &&
5290 (formatTokens
[whichToken
].tokenId
!= *pData
)) {
5294 /* Use Variant local from here downwards as always correct type */
5295 if (formatTokens
[whichToken
].tokenSize
> 0 &&
5296 formatTokens
[whichToken
].varTypeRequired
!= 0) {
5297 VariantInit( &Variant
);
5298 if (Coerce( &Variant
, lcid
, dwFlags
, varIn
,
5299 formatTokens
[whichToken
].varTypeRequired
) != S_OK
) {
5300 HeapFree( GetProcessHeap(), 0, pFormatA
);
5301 return DISP_E_TYPEMISMATCH
;
5302 } else if (formatTokens
[whichToken
].varTypeRequired
== VT_DATE
) {
5303 if( DateToTm( V_UNION(&Variant
,date
), dwFlags
, &TM
) == FALSE
) {
5304 HeapFree( GetProcessHeap(), 0, pFormatA
);
5305 return E_INVALIDARG
;
5310 TRACE("Looking for match on token '%x'\n", *pData
);
5313 TRACE("Copy from %d for %d bytes\n", *(pData
+1), *(pData
+2));
5314 memcpy(pNextPos
, &pFormatA
[*(pData
+1)], *(pData
+2));
5315 pNextPos
= pNextPos
+ *(pData
+2);
5320 /* Get locale information - Time Seperator */
5321 size
= GetLocaleInfoA(lcid
, LOCALE_STIME
, NULL
, 0);
5322 GetLocaleInfoA(lcid
, LOCALE_STIME
, pNextPos
, size
);
5323 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos
);
5324 pNextPos
= pNextPos
+ size
;
5329 /* Get locale information - Date Seperator */
5330 size
= GetLocaleInfoA(lcid
, LOCALE_SDATE
, NULL
, 0);
5331 GetLocaleInfoA(lcid
, LOCALE_SDATE
, pNextPos
, size
);
5332 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos
);
5333 pNextPos
= pNextPos
+ size
;
5338 sprintf(pNextPos
, "%d", TM
.tm_mday
);
5339 pNextPos
= pNextPos
+ strlen(pNextPos
);
5344 sprintf(pNextPos
, "%2.2d", TM
.tm_mday
);
5345 pNextPos
= pNextPos
+ strlen(pNextPos
);
5350 sprintf(pNextPos
, "%d", TM
.tm_wday
+1);
5351 pNextPos
= pNextPos
+ strlen(pNextPos
);
5356 sprintf(pNextPos
, "%d", TM
.tm_mon
+1);
5357 pNextPos
= pNextPos
+ strlen(pNextPos
);
5362 sprintf(pNextPos
, "%2.2d", TM
.tm_mon
+1);
5363 pNextPos
= pNextPos
+ strlen(pNextPos
);
5368 sprintf(pNextPos
, "%d", ((TM
.tm_mon
+1)/4)+1);
5369 pNextPos
= pNextPos
+ strlen(pNextPos
);
5374 sprintf(pNextPos
, "%2.2d", TM
.tm_yday
+1);
5375 pNextPos
= pNextPos
+ strlen(pNextPos
);
5380 sprintf(pNextPos
, "%2.2d", TM
.tm_year
);
5381 pNextPos
= pNextPos
+ strlen(pNextPos
);
5386 sprintf(pNextPos
, "%4.4d", TM
.tm_year
);
5387 pNextPos
= pNextPos
+ strlen(pNextPos
);
5392 sprintf(pNextPos
, "%d", TM
.tm_hour
);
5393 pNextPos
= pNextPos
+ strlen(pNextPos
);
5398 sprintf(pNextPos
, "%2.2d", TM
.tm_hour
);
5399 pNextPos
= pNextPos
+ strlen(pNextPos
);
5404 sprintf(pNextPos
, "%d", TM
.tm_min
);
5405 pNextPos
= pNextPos
+ strlen(pNextPos
);
5410 sprintf(pNextPos
, "%2.2d", TM
.tm_min
);
5411 pNextPos
= pNextPos
+ strlen(pNextPos
);
5416 sprintf(pNextPos
, "%d", TM
.tm_sec
);
5417 pNextPos
= pNextPos
+ strlen(pNextPos
);
5422 sprintf(pNextPos
, "%2.2d", TM
.tm_sec
);
5423 pNextPos
= pNextPos
+ strlen(pNextPos
);
5443 FIXME("Unhandled token for VarFormat %d\n", *pData
);
5444 HeapFree( GetProcessHeap(), 0, pFormatA
);
5445 return E_INVALIDARG
;
5450 *pbstrOut
= StringDupAtoBstr( output
);
5451 HeapFree( GetProcessHeap(), 0, pFormatA
);
5455 /**********************************************************************
5456 * VarFormat [OLEAUT32.469]
5459 HRESULT WINAPI
VarFormat(LPVARIANT varIn
, LPOLESTR format
,
5460 int firstDay
, int firstWeek
, ULONG dwFlags
,
5463 LPSTR pNewString
= NULL
;
5466 TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
5467 debugstr_w(format
), firstDay
, firstWeek
, dwFlags
);
5469 dump_Variant(varIn
);
5471 /* Get format string */
5472 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, format
);
5474 /* FIXME: Handle some simple pre-definted format strings : */
5475 if (((V_VT(varIn
)&VT_TYPEMASK
) == VT_CY
) && (lstrcmpiA(pNewString
, "Currency") == 0)) {
5477 /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
5479 rc
= VarR8FromCy(V_UNION(varIn
,cyVal
), &curVal
);
5481 char tmpStr
[BUFFER_MAX
];
5482 sprintf(tmpStr
, "%f", curVal
);
5483 if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags
, tmpStr
, NULL
, pBuffer
, BUFFER_MAX
) == 0) {
5486 *pbstrOut
= StringDupAtoBstr( pBuffer
);
5490 } else if ((V_VT(varIn
)&VT_TYPEMASK
) == VT_DATE
) {
5492 /* Attempt to do proper formatting! */
5493 int firstToken
= -1;
5495 rc
= VarTokenizeFormatString(format
, pBuffer
, sizeof(pBuffer
), firstDay
,
5496 firstWeek
, GetUserDefaultLCID(), &firstToken
);
5498 rc
= VarFormatFromTokens(varIn
, format
, pBuffer
, dwFlags
, pbstrOut
, GetUserDefaultLCID());
5503 FIXME("Unsupported format!\n");
5504 *pbstrOut
= StringDupAtoBstr( "??" );
5507 /* Free allocated storage */
5508 HeapFree( GetProcessHeap(), 0, pNewString
);
5509 TRACE("result: '%s'\n", debugstr_w(*pbstrOut
));