4 * Copyright 1998 Jean-Claude Cote
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * This implements the low-level and hi-level APIs for manipulating VARIANTs.
22 * The low-level APIs are used to do data coercion between different data types.
23 * The hi-level APIs are built on top of these low-level APIs and handle
24 * initialization, copying, destroying and changing the type of VARIANTs.
27 * - The Variant APIs do not support international languages, currency
28 * types, number formating and calendar. They only support U.S. English format.
29 * - The Variant APIs do not the following types: IUknown, IDispatch, DECIMAL and SafeArray.
30 * The prototypes for these are commented out in the oleauto.h file. They need
31 * to be implemented and cases need to be added to the switches of the existing APIs.
32 * - The parsing of date for the VarDateFromStr is not complete.
33 * - The date manipulations do not support dates prior to 1900.
34 * - The parsing does not accept as many formats as the Windows implementation.
49 #define NONAMELESSUNION
50 #define NONAMELESSSTRUCT
54 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
62 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
66 # define FLT_MAX MAXFLOAT
68 # error "Can't find #define for MAXFLOAT/FLT_MAX"
74 static const char CHAR_MAX
= 127;
75 static const char CHAR_MIN
= -128;
76 static const BYTE UI1_MAX
= 255;
77 static const BYTE UI1_MIN
= 0;
78 static const unsigned short UI2_MAX
= 65535;
79 static const unsigned short UI2_MIN
= 0;
80 static const short I2_MAX
= 32767;
81 static const short I2_MIN
= -32768;
82 static const unsigned long UI4_MAX
= 4294967295U;
83 static const unsigned long UI4_MIN
= 0;
84 static const long I4_MAX
= 2147483647;
85 static const long I4_MIN
= -(2147483648U);
86 static const DATE DATE_MIN
= -657434;
87 static const DATE DATE_MAX
= 2958465;
89 /* the largest valid type
91 #define VT_MAXVALIDTYPE VT_CLSID
93 /* This mask is used to set a flag in wReserved1 of
94 * the VARIANTARG structure. The flag indicates if
95 * the API function is using an inner variant or not.
97 #define PROCESSING_INNER_VARIANT 0x0001
99 /* General use buffer.
101 #define BUFFER_MAX 1024
102 static char pBuffer
[BUFFER_MAX
];
105 * Note a leap year is one that is a multiple of 4
106 * but not of a 100. Except if it is a multiple of
107 * 400 then it is a leap year.
111 * Use 365 days/year and a manual calculation for leap year days
112 * to keep arithmetic simple
114 static const double DAYS_IN_ONE_YEAR
= 365.0;
117 * Token definitions for Varient Formatting
118 * Worked out by experimentation on a w2k machine. Doesnt appear to be
119 * documented anywhere obviously so keeping definitions internally
122 /* Pre defined tokens */
123 #define TOK_COPY 0x00
125 #define LARGEST_TOKENID 6
127 /* Mapping of token name to id put into the tokenized form
128 Note testing on W2K shows aaaa and oooo are not parsed??!! */
129 #define TOK_COLON 0x03
130 #define TOK_SLASH 0x04
135 #define TOK_dddd 0x0b
136 #define TOK_ddddd 0x0c
137 #define TOK_dddddd 0x0d
143 #define TOK_mmmm 0x14
147 #define TOK_yyyy 0x18
154 #define TOK_ttttt 0x07
155 #define TOK_AMsPM 0x2f
156 #define TOK_amspm 0x32
159 #define TOK_AMPM 0x2e
161 typedef struct tagFORMATTOKEN
{
168 typedef struct tagFORMATHDR
{
175 FORMATTOKEN formatTokens
[] = { /* FIXME: Only date formats so far */
176 {":" , 1, TOK_COLON
, 0},
177 {"/" , 1, TOK_SLASH
, 0},
178 {"c" , 1, TOK_c
, VT_DATE
},
179 {"dddddd", 6, TOK_dddddd
, VT_DATE
},
180 {"ddddd" , 5, TOK_ddddd
, VT_DATE
},
181 {"dddd" , 4, TOK_dddd
, VT_DATE
},
182 {"ddd" , 3, TOK_ddd
, VT_DATE
},
183 {"dd" , 2, TOK_dd
, VT_DATE
},
184 {"d" , 1, TOK_d
, VT_DATE
},
185 {"ww" , 2, TOK_ww
, VT_DATE
},
186 {"w" , 1, TOK_w
, VT_DATE
},
187 {"mmmm" , 4, TOK_mmmm
, VT_DATE
},
188 {"mmm" , 3, TOK_mmm
, VT_DATE
},
189 {"mm" , 2, TOK_mm
, VT_DATE
},
190 {"m" , 1, TOK_m
, VT_DATE
},
191 {"q" , 1, TOK_q
, VT_DATE
},
192 {"yyyy" , 4, TOK_yyyy
, VT_DATE
},
193 {"yy" , 2, TOK_yy
, VT_DATE
},
194 {"y" , 1, TOK_y
, VT_DATE
},
195 {"h" , 1, TOK_h
, VT_DATE
},
196 {"Hh" , 2, TOK_Hh
, VT_DATE
},
197 {"Nn" , 2, TOK_Nn
, VT_DATE
},
198 {"N" , 1, TOK_N
, VT_DATE
},
199 {"S" , 1, TOK_S
, VT_DATE
},
200 {"Ss" , 2, TOK_Ss
, VT_DATE
},
201 {"ttttt" , 5, TOK_ttttt
, VT_DATE
},
202 {"AM/PM" , 5, TOK_AMsPM
, VT_DATE
},
203 {"am/pm" , 5, TOK_amspm
, VT_DATE
},
204 {"A/P" , 3, TOK_AsP
, VT_DATE
},
205 {"a/p" , 3, TOK_asp
, VT_DATE
},
206 {"AMPM" , 4, TOK_AMPM
, VT_DATE
},
207 {0x00 , 0, 0 , VT_NULL
}
210 /******************************************************************************
211 * DateTimeStringToTm [INTERNAL]
213 * Converts a string representation of a date and/or time to a tm structure.
215 * Note this function uses the postgresql date parsing functions found
216 * in the parsedt.c file.
218 * Returns TRUE if successful.
220 * Note: This function does not parse the day of the week,
221 * daylight savings time. It will only fill the followin fields in
222 * the tm struct, tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
224 ******************************************************************************/
225 static BOOL
DateTimeStringToTm( OLECHAR
* strIn
, DWORD dwFlags
, struct tm
* pTm
)
232 char *field
[MAXDATEFIELDS
];
233 int ftype
[MAXDATEFIELDS
];
234 char lowstr
[MAXDATELEN
+ 1];
235 char* strDateTime
= NULL
;
237 /* Convert the string to ASCII since this is the only format
238 * postgesql can handle.
240 strDateTime
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
242 if( strDateTime
!= NULL
)
244 /* Make sure we don't go over the maximum length
245 * accepted by postgesql.
247 if( strlen( strDateTime
) <= MAXDATELEN
)
249 if( ParseDateTime( strDateTime
, lowstr
, field
, ftype
, MAXDATEFIELDS
, &nf
) == 0 )
251 if( dwFlags
& VAR_DATEVALUEONLY
)
253 /* Get the date information.
254 * It returns 0 if date information was
255 * present and 1 if only time information was present.
256 * -1 if an error occures.
258 if( DecodeDateTime(field
, ftype
, nf
, &dtype
, pTm
, &fsec
, &tzp
) == 0 )
260 /* Eliminate the time information since we
261 * were asked to get date information only.
269 if( dwFlags
& VAR_TIMEVALUEONLY
)
271 /* Get time information only.
273 if( DecodeTimeOnly(field
, ftype
, nf
, &dtype
, pTm
, &fsec
) == 0 )
280 /* Get both date and time information.
281 * It returns 0 if date information was
282 * present and 1 if only time information was present.
283 * -1 if an error occures.
285 if( DecodeDateTime(field
, ftype
, nf
, &dtype
, pTm
, &fsec
, &tzp
) != -1 )
292 HeapFree( GetProcessHeap(), 0, strDateTime
);
303 /******************************************************************************
304 * TmToDATE [INTERNAL]
306 * The date is implemented using an 8 byte floating-point number.
307 * Days are represented by whole numbers increments starting with 0.00 has
308 * being December 30 1899, midnight.
309 * The hours are expressed as the fractional part of the number.
310 * December 30 1899 at midnight = 0.00
311 * January 1 1900 at midnight = 2.00
312 * January 4 1900 at 6 AM = 5.25
313 * January 4 1900 at noon = 5.50
314 * December 29 1899 at midnight = -1.00
315 * December 18 1899 at midnight = -12.00
316 * December 18 1899 at 6AM = -12.25
317 * December 18 1899 at 6PM = -12.75
318 * December 19 1899 at midnight = -11.00
319 * The tm structure is as follows:
321 * int tm_sec; seconds after the minute - [0,59]
322 * int tm_min; minutes after the hour - [0,59]
323 * int tm_hour; hours since midnight - [0,23]
324 * int tm_mday; day of the month - [1,31]
325 * int tm_mon; months since January - [0,11]
327 * int tm_wday; days since Sunday - [0,6]
328 * int tm_yday; days since January 1 - [0,365]
329 * int tm_isdst; daylight savings time flag
332 * Note: This function does not use the tm_wday, tm_yday, tm_wday,
333 * and tm_isdst fields of the tm structure. And only converts years
336 * Returns TRUE if successful.
338 static BOOL
TmToDATE( struct tm
* pTm
, DATE
*pDateOut
)
342 /* Hmmm... An uninitialized Date in VB is December 30 1899 so
343 Start at 0. This is the way DATE is defined. */
345 /* Start at 1. This is the way DATE is defined.
346 * January 1, 1900 at Midnight is 1.00.
347 * January 1, 1900 at 6AM is 1.25.
352 if( (pTm
->tm_year
- 1900) >= 0 ) {
354 /* Add the number of days corresponding to
357 *pDateOut
+= (pTm
->tm_year
- 1900) * 365;
359 /* Add the leap days in the previous years between now and 1900.
360 * Note a leap year is one that is a multiple of 4
361 * but not of a 100. Except if it is a multiple of
362 * 400 then it is a leap year.
363 * Copied + reversed functionality into TmToDate
365 *pDateOut
+= ( (pTm
->tm_year
- 1) / 4 ) - ( 1900 / 4 );
366 *pDateOut
-= ( (pTm
->tm_year
- 1) / 100 ) - ( 1900 / 100 );
367 *pDateOut
+= ( (pTm
->tm_year
- 1) / 400 ) - ( 1900 / 400 );
369 /* Set the leap year flag if the
370 * current year specified by tm_year is a
371 * leap year. This will be used to add a day
374 if( isleap( pTm
->tm_year
) )
377 /* Add the number of days corresponding to
378 * the month. (remember tm_mon is 0..11)
380 switch( pTm
->tm_mon
)
386 *pDateOut
+= ( 59 + leapYear
);
389 *pDateOut
+= ( 90 + leapYear
);
392 *pDateOut
+= ( 120 + leapYear
);
395 *pDateOut
+= ( 151 + leapYear
);
398 *pDateOut
+= ( 181 + leapYear
);
401 *pDateOut
+= ( 212 + leapYear
);
404 *pDateOut
+= ( 243 + leapYear
);
407 *pDateOut
+= ( 273 + leapYear
);
410 *pDateOut
+= ( 304 + leapYear
);
413 *pDateOut
+= ( 334 + leapYear
);
416 /* Add the number of days in this month.
418 *pDateOut
+= pTm
->tm_mday
;
420 /* Add the number of seconds, minutes, and hours
421 * to the DATE. Note these are the fracionnal part
422 * of the DATE so seconds / number of seconds in a day.
428 *pDateOut
+= pTm
->tm_hour
/ 24.0;
429 *pDateOut
+= pTm
->tm_min
/ 1440.0;
430 *pDateOut
+= pTm
->tm_sec
/ 86400.0;
434 /******************************************************************************
435 * DateToTm [INTERNAL]
437 * This function converts a windows DATE to a tm structure.
439 * It does not fill all the fields of the tm structure.
440 * Here is a list of the fields that are filled:
441 * tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
443 * Note this function does not support dates before the January 1, 1900
444 * or ( dateIn < 2.0 ).
446 * Returns TRUE if successful.
448 BOOL
DateToTm( DATE dateIn
, DWORD dwFlags
, struct tm
* pTm
)
450 double decimalPart
= 0.0;
451 double wholePart
= 0.0;
453 memset(pTm
,0,sizeof(*pTm
));
455 /* Because of the nature of DATE format which
456 * associates 2.0 to January 1, 1900. We will
457 * remove 1.0 from the whole part of the DATE
458 * so that in the following code 1.0
459 * will correspond to January 1, 1900.
460 * This simplifies the processing of the DATE value.
462 decimalPart
= fmod( dateIn
, 1.0 ); /* Do this before the -1, otherwise 0.xx goes negative */
464 wholePart
= (double) floor( dateIn
);
466 if( !(dwFlags
& VAR_TIMEVALUEONLY
) )
468 unsigned int nDay
= 0;
470 double yearsSince1900
= 0;
472 /* Hard code dates smaller than January 1, 1900. */
475 pTm
->tm_mon
= 11; /* December as tm_mon is 0..11 */
478 dateIn
= dateIn
* -1.0; /* Ensure +ve for time calculation */
479 decimalPart
= decimalPart
* -1.0; /* Ensure +ve for time calculation */
486 /* Start at 1900, this is where the DATE time 0.0 starts.
489 /* find in what year the day in the "wholePart" falls into.
490 * add the value to the year field.
492 yearsSince1900
= floor( (wholePart
/ DAYS_IN_ONE_YEAR
) + 0.001 );
493 pTm
->tm_year
+= yearsSince1900
;
494 /* determine if this is a leap year.
496 if( isleap( pTm
->tm_year
) )
502 /* find what day of that year the "wholePart" corresponds to.
503 * Note: nDay is in [1-366] format
505 nDay
= (((unsigned int) wholePart
) - ((pTm
->tm_year
-1900) * DAYS_IN_ONE_YEAR
));
507 /* Remove the leap days in the previous years between now and 1900.
508 * Note a leap year is one that is a multiple of 4
509 * but not of a 100. Except if it is a multiple of
510 * 400 then it is a leap year.
511 * Copied + reversed functionality from TmToDate
513 nDay
-= ( (pTm
->tm_year
- 1) / 4 ) - ( 1900 / 4 );
514 nDay
+= ( (pTm
->tm_year
- 1) / 100 ) - ( 1900 / 100 );
515 nDay
-= ( (pTm
->tm_year
- 1) / 400 ) - ( 1900 / 400 );
517 /* Set the tm_yday value.
518 * Note: The day must be converted from [1-366] to [0-365]
520 /*pTm->tm_yday = nDay - 1;*/
521 /* find which month this day corresponds to.
528 else if( nDay
<= ( 59 + leapYear
) )
530 pTm
->tm_mday
= nDay
- 31;
533 else if( nDay
<= ( 90 + leapYear
) )
535 pTm
->tm_mday
= nDay
- ( 59 + leapYear
);
538 else if( nDay
<= ( 120 + leapYear
) )
540 pTm
->tm_mday
= nDay
- ( 90 + leapYear
);
543 else if( nDay
<= ( 151 + leapYear
) )
545 pTm
->tm_mday
= nDay
- ( 120 + leapYear
);
548 else if( nDay
<= ( 181 + leapYear
) )
550 pTm
->tm_mday
= nDay
- ( 151 + leapYear
);
553 else if( nDay
<= ( 212 + leapYear
) )
555 pTm
->tm_mday
= nDay
- ( 181 + leapYear
);
558 else if( nDay
<= ( 243 + leapYear
) )
560 pTm
->tm_mday
= nDay
- ( 212 + leapYear
);
563 else if( nDay
<= ( 273 + leapYear
) )
565 pTm
->tm_mday
= nDay
- ( 243 + leapYear
);
568 else if( nDay
<= ( 304 + leapYear
) )
570 pTm
->tm_mday
= nDay
- ( 273 + leapYear
);
573 else if( nDay
<= ( 334 + leapYear
) )
575 pTm
->tm_mday
= nDay
- ( 304 + leapYear
);
578 else if( nDay
<= ( 365 + leapYear
) )
580 pTm
->tm_mday
= nDay
- ( 334 + leapYear
);
585 if( !(dwFlags
& VAR_DATEVALUEONLY
) )
587 /* find the number of seconds in this day.
588 * fractional part times, hours, minutes, seconds.
589 * Note: 0.1 is hack to ensure figures come out in whole numbers
590 * due to floating point inaccuracies
592 pTm
->tm_hour
= (int) ( decimalPart
* 24 );
593 pTm
->tm_min
= (int) ( ( ( decimalPart
* 24 ) - pTm
->tm_hour
) * 60 );
594 /* Note: 0.1 is hack to ensure seconds come out in whole numbers
595 due to floating point inaccuracies */
596 pTm
->tm_sec
= (int) (( ( ( decimalPart
* 24 * 60 ) - ( pTm
->tm_hour
* 60 ) - pTm
->tm_min
) * 60 ) + 0.1);
603 /******************************************************************************
604 * SizeOfVariantData [INTERNAL]
606 * This function finds the size of the data referenced by a Variant based
607 * the type "vt" of the Variant.
609 static int SizeOfVariantData( VARIANT
* parg
)
612 switch( V_VT(parg
) & VT_TYPEMASK
)
615 size
= sizeof(short);
627 size
= sizeof(unsigned short);
630 size
= sizeof(unsigned int);
633 size
= sizeof(unsigned long);
636 size
= sizeof(float);
639 size
= sizeof(double);
645 size
= sizeof(VARIANT_BOOL
);
650 size
= sizeof(void*);
655 case( VT_DECIMAL
): /* hmm, tricky, DECIMAL is only VT_BYREF */
657 FIXME("Add size information for type vt=%d\n", V_VT(parg
) & VT_TYPEMASK
);
663 /******************************************************************************
664 * StringDupAtoBstr [INTERNAL]
667 static BSTR
StringDupAtoBstr( char* strIn
)
670 OLECHAR
* pNewString
= NULL
;
671 UNICODE_STRING usBuffer
;
673 RtlCreateUnicodeStringFromAsciiz( &usBuffer
, strIn
);
674 pNewString
= usBuffer
.Buffer
;
676 bstr
= SysAllocString( pNewString
);
677 RtlFreeUnicodeString( &usBuffer
);
681 /******************************************************************************
684 * Round the double value to the nearest integer value.
686 static double round( double d
)
688 double decimals
= 0.0, integerValue
= 0.0, roundedValue
= 0.0;
689 BOOL bEvenNumber
= FALSE
;
692 /* Save the sign of the number
694 nSign
= (d
>= 0.0) ? 1 : -1;
697 /* Remove the decimals.
699 integerValue
= floor( d
);
701 /* Set the Even flag. This is used to round the number when
702 * the decimals are exactly 1/2. If the integer part is
703 * odd the number is rounded up. If the integer part
704 * is even the number is rounded down. Using this method
705 * numbers are rounded up|down half the time.
707 bEvenNumber
= (((short)fmod(integerValue
, 2)) == 0) ? TRUE
: FALSE
;
709 /* Remove the integral part of the number.
711 decimals
= d
- integerValue
;
713 /* Note: Ceil returns the smallest integer that is greater that x.
714 * and floor returns the largest integer that is less than or equal to x.
718 /* If the decimal part is greater than 1/2
720 roundedValue
= ceil( d
);
722 else if( decimals
< 0.5 )
724 /* If the decimal part is smaller than 1/2
726 roundedValue
= floor( d
);
730 /* the decimals are exactly 1/2 so round according to
731 * the bEvenNumber flag.
735 roundedValue
= floor( d
);
739 roundedValue
= ceil( d
);
743 return roundedValue
* nSign
;
746 /******************************************************************************
747 * RemoveCharacterFromString [INTERNAL]
749 * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
751 static void RemoveCharacterFromString( LPSTR str
, LPSTR strOfCharToRemove
)
753 LPSTR pNewString
= NULL
;
754 LPSTR strToken
= NULL
;
756 /* Check if we have a valid argument
760 pNewString
= strdup( str
);
762 strToken
= strtok( pNewString
, strOfCharToRemove
);
763 while( strToken
!= NULL
) {
764 strcat( str
, strToken
);
765 strToken
= strtok( NULL
, strOfCharToRemove
);
772 /******************************************************************************
773 * GetValidRealString [INTERNAL]
775 * Checks if the string is of proper format to be converted to a real value.
777 static BOOL
IsValidRealString( LPSTR strRealString
)
779 /* Real values that have a decimal point are required to either have
780 * digits before or after the decimal point. We will assume that
781 * we do not have any digits at either position. If we do encounter
782 * some we will disable this flag.
784 BOOL bDigitsRequired
= TRUE
;
785 /* Processed fields in the string representation of the real number.
787 BOOL bWhiteSpaceProcessed
= FALSE
;
788 BOOL bFirstSignProcessed
= FALSE
;
789 BOOL bFirstDigitsProcessed
= FALSE
;
790 BOOL bDecimalPointProcessed
= FALSE
;
791 BOOL bSecondDigitsProcessed
= FALSE
;
792 BOOL bExponentProcessed
= FALSE
;
793 BOOL bSecondSignProcessed
= FALSE
;
794 BOOL bThirdDigitsProcessed
= FALSE
;
795 /* Assume string parameter "strRealString" is valid and try to disprove it.
797 BOOL bValidRealString
= TRUE
;
799 /* Used to count the number of tokens in the "strRealString".
801 LPSTR strToken
= NULL
;
805 /* Check if we have a valid argument
807 if( strRealString
== NULL
)
809 bValidRealString
= FALSE
;
812 if( bValidRealString
== TRUE
)
814 /* Make sure we only have ONE token in the string.
816 strToken
= strtok( strRealString
, " " );
817 while( strToken
!= NULL
) {
819 strToken
= strtok( NULL
, " " );
824 bValidRealString
= FALSE
;
829 /* Make sure this token contains only valid characters.
830 * The string argument to atof has the following form:
831 * [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
832 * Whitespace consists of space and|or <TAB> characters, which are ignored.
833 * Sign is either plus '+' or minus '-'.
834 * Digits are one or more decimal digits.
835 * Note: If no digits appear before the decimal point, at least one must
836 * appear after the decimal point.
837 * The decimal digits may be followed by an exponent.
838 * An Exponent consists of an introductory letter ( D, d, E, or e) and
839 * an optionally signed decimal integer.
841 pChar
= strRealString
;
842 while( bValidRealString
== TRUE
&& *pChar
!= '\0' )
850 if( bWhiteSpaceProcessed
||
851 bFirstSignProcessed
||
852 bFirstDigitsProcessed
||
853 bDecimalPointProcessed
||
854 bSecondDigitsProcessed
||
855 bExponentProcessed
||
856 bSecondSignProcessed
||
857 bThirdDigitsProcessed
)
859 bValidRealString
= FALSE
;
866 if( bFirstSignProcessed
== FALSE
)
868 if( bFirstDigitsProcessed
||
869 bDecimalPointProcessed
||
870 bSecondDigitsProcessed
||
871 bExponentProcessed
||
872 bSecondSignProcessed
||
873 bThirdDigitsProcessed
)
875 bValidRealString
= FALSE
;
877 bWhiteSpaceProcessed
= TRUE
;
878 bFirstSignProcessed
= TRUE
;
880 else if( bSecondSignProcessed
== FALSE
)
882 /* Note: The exponent must be present in
883 * order to accept the second sign...
885 if( bExponentProcessed
== FALSE
||
886 bThirdDigitsProcessed
||
889 bValidRealString
= FALSE
;
891 bFirstSignProcessed
= TRUE
;
892 bWhiteSpaceProcessed
= TRUE
;
893 bFirstDigitsProcessed
= TRUE
;
894 bDecimalPointProcessed
= TRUE
;
895 bSecondDigitsProcessed
= TRUE
;
896 bSecondSignProcessed
= TRUE
;
912 if( bFirstDigitsProcessed
== FALSE
)
914 if( bDecimalPointProcessed
||
915 bSecondDigitsProcessed
||
916 bExponentProcessed
||
917 bSecondSignProcessed
||
918 bThirdDigitsProcessed
)
920 bValidRealString
= FALSE
;
922 bFirstSignProcessed
= TRUE
;
923 bWhiteSpaceProcessed
= TRUE
;
924 /* We have found some digits before the decimal point
925 * so disable the "Digits required" flag.
927 bDigitsRequired
= FALSE
;
929 else if( bSecondDigitsProcessed
== FALSE
)
931 if( bExponentProcessed
||
932 bSecondSignProcessed
||
933 bThirdDigitsProcessed
)
935 bValidRealString
= FALSE
;
937 bFirstSignProcessed
= TRUE
;
938 bWhiteSpaceProcessed
= TRUE
;
939 bFirstDigitsProcessed
= TRUE
;
940 bDecimalPointProcessed
= TRUE
;
941 /* We have found some digits after the decimal point
942 * so disable the "Digits required" flag.
944 bDigitsRequired
= FALSE
;
946 else if( bThirdDigitsProcessed
== FALSE
)
948 /* Getting here means everything else should be processed.
949 * If we get anything else than a decimal following this
950 * digit it will be flagged by the other cases, so
951 * we do not really need to do anything in here.
955 /* If DecimalPoint...
958 if( bDecimalPointProcessed
||
959 bSecondDigitsProcessed
||
960 bExponentProcessed
||
961 bSecondSignProcessed
||
962 bThirdDigitsProcessed
)
964 bValidRealString
= FALSE
;
966 bFirstSignProcessed
= TRUE
;
967 bWhiteSpaceProcessed
= TRUE
;
968 bFirstDigitsProcessed
= TRUE
;
969 bDecimalPointProcessed
= TRUE
;
977 if( bExponentProcessed
||
978 bSecondSignProcessed
||
979 bThirdDigitsProcessed
||
982 bValidRealString
= FALSE
;
984 bFirstSignProcessed
= TRUE
;
985 bWhiteSpaceProcessed
= TRUE
;
986 bFirstDigitsProcessed
= TRUE
;
987 bDecimalPointProcessed
= TRUE
;
988 bSecondDigitsProcessed
= TRUE
;
989 bExponentProcessed
= TRUE
;
992 bValidRealString
= FALSE
;
995 /* Process next character.
1000 /* If the required digits were not present we have an invalid
1001 * string representation of a real number.
1003 if( bDigitsRequired
== TRUE
)
1005 bValidRealString
= FALSE
;
1008 return bValidRealString
;
1012 /******************************************************************************
1015 * This function dispatches execution to the proper conversion API
1016 * to do the necessary coercion.
1018 * FIXME: Passing down dwFlags to the conversion functions is wrong, this
1019 * is a different flagmask. Check MSDN.
1021 static HRESULT
Coerce( VARIANTARG
* pd
, LCID lcid
, ULONG dwFlags
, VARIANTARG
* ps
, VARTYPE vt
)
1024 unsigned short vtFrom
= 0;
1025 vtFrom
= V_VT(ps
) & VT_TYPEMASK
;
1028 /* Note: Since "long" and "int" values both have 4 bytes and are
1029 * both signed integers "int" will be treated as "long" in the
1031 * The same goes for their unsigned versions.
1034 /* Trivial Case: If the coercion is from two types that are
1035 * identical then we can blindly copy from one argument to another.*/
1037 return VariantCopy(pd
,ps
);
1039 /* Cases requiring thought*/
1044 res
= VariantClear( pd
);
1047 res
= VariantClear( pd
);
1057 res
= VarI1FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,cVal
) );
1061 res
= VarI1FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,cVal
) );
1064 res
= VarI1FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,cVal
) );
1067 res
= VarI1FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,cVal
) );
1071 res
= VarI1FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,cVal
) );
1074 res
= VarI1FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,cVal
) );
1077 res
= VarI1FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,cVal
) );
1080 res
= VarI1FromDate( V_UNION(ps
,date
), &V_UNION(pd
,cVal
) );
1083 res
= VarI1FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,cVal
) );
1086 res
= VarI1FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,cVal
) );
1089 res
= VarI1FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,cVal
) );
1091 case( VT_DISPATCH
):
1092 /*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
1094 /*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
1097 res
= DISP_E_TYPEMISMATCH
;
1098 FIXME("Coercion from %d to VT_I1\n", vtFrom
);
1107 res
= VarI2FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,iVal
) );
1111 res
= VarI2FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,iVal
) );
1114 res
= VarI2FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,iVal
) );
1117 res
= VarI2FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,iVal
) );
1121 res
= VarI2FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,iVal
) );
1124 res
= VarI2FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,iVal
) );
1127 res
= VarI2FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,iVal
) );
1130 res
= VarI2FromDate( V_UNION(ps
,date
), &V_UNION(pd
,iVal
) );
1133 res
= VarI2FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,iVal
) );
1136 res
= VarI2FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,iVal
) );
1139 res
= VarI2FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,iVal
) );
1141 case( VT_DISPATCH
):
1142 /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
1144 /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
1147 res
= DISP_E_TYPEMISMATCH
;
1148 FIXME("Coercion from %d to VT_I2\n", vtFrom
);
1158 V_UNION(pd
,lVal
) = 0;
1162 res
= VarI4FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,lVal
) );
1165 res
= VarI4FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,lVal
) );
1169 V_UNION(pd
,lVal
) = V_UNION(pd
,scode
);
1174 res
= VariantCopy( pd
, ps
);
1177 res
= VarI4FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,lVal
) );
1180 res
= VarI4FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,lVal
) );
1184 res
= VarI4FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,lVal
) );
1187 res
= VarI4FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,lVal
) );
1190 res
= VarI4FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,lVal
) );
1193 res
= VarI4FromDate( V_UNION(ps
,date
), &V_UNION(pd
,lVal
) );
1196 res
= VarI4FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,lVal
) );
1199 res
= VarI4FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,lVal
) );
1202 res
= VarI4FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,lVal
) );
1204 case( VT_DISPATCH
):
1205 /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1207 /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1210 res
= DISP_E_TYPEMISMATCH
;
1211 FIXME("Coercion from %d to VT_INT/VT_I4\n", vtFrom
);
1220 res
= VarUI1FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,bVal
) );
1223 res
= VarUI1FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,bVal
) );
1227 res
= VarUI1FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,bVal
) );
1230 res
= VariantCopy( pd
, ps
);
1233 res
= VarUI1FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,bVal
) );
1237 res
= VarUI1FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,bVal
) );
1240 res
= VarUI1FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,bVal
) );
1243 res
= VarUI1FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,bVal
) );
1246 res
= VarUI1FromDate( V_UNION(ps
,date
), &V_UNION(pd
,bVal
) );
1249 res
= VarUI1FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,bVal
) );
1252 res
= VarUI1FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,bVal
) );
1255 res
= VarUI1FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,bVal
) );
1257 case( VT_DISPATCH
):
1258 /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1260 /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1263 res
= DISP_E_TYPEMISMATCH
;
1264 FIXME("Coercion from %d to VT_UI1\n", vtFrom
);
1273 res
= VarUI2FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,uiVal
) );
1276 res
= VarUI2FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,uiVal
) );
1280 res
= VarUI2FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,uiVal
) );
1283 res
= VarUI2FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,uiVal
) );
1286 res
= VariantCopy( pd
, ps
);
1290 res
= VarUI2FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,uiVal
) );
1293 res
= VarUI2FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,uiVal
) );
1296 res
= VarUI2FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,uiVal
) );
1299 res
= VarUI2FromDate( V_UNION(ps
,date
), &V_UNION(pd
,uiVal
) );
1302 res
= VarUI2FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,uiVal
) );
1305 res
= VarUI2FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,uiVal
) );
1308 res
= VarUI2FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,uiVal
) );
1310 case( VT_DISPATCH
):
1311 /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1313 /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1316 res
= DISP_E_TYPEMISMATCH
;
1317 FIXME("Coercion from %d to VT_UI2\n", vtFrom
);
1327 res
= VarUI4FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,ulVal
) );
1330 res
= VarUI4FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,ulVal
) );
1334 res
= VarUI4FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,ulVal
) );
1337 res
= VarUI4FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,ulVal
) );
1340 res
= VarUI4FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,ulVal
) );
1343 res
= VariantCopy( pd
, ps
);
1346 res
= VarUI4FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,ulVal
) );
1349 res
= VarUI4FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,ulVal
) );
1352 res
= VarUI4FromDate( V_UNION(ps
,date
), &V_UNION(pd
,ulVal
) );
1355 res
= VarUI4FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,ulVal
) );
1358 res
= VarUI4FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,ulVal
) );
1361 res
= VarUI4FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,ulVal
) );
1363 case( VT_DISPATCH
):
1364 /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1366 /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1369 res
= DISP_E_TYPEMISMATCH
;
1370 FIXME("Coercion from %d to VT_UINT/VT_UI4\n", vtFrom
);
1379 res
= VarR4FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,fltVal
) );
1382 res
= VarR4FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,fltVal
) );
1386 res
= VarR4FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,fltVal
) );
1389 res
= VarR4FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,fltVal
) );
1392 res
= VarR4FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,fltVal
) );
1396 res
= VarR4FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,fltVal
) );
1399 res
= VariantCopy( pd
, ps
);
1402 res
= VarR4FromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,fltVal
) );
1405 res
= VarR4FromDate( V_UNION(ps
,date
), &V_UNION(pd
,fltVal
) );
1408 res
= VarR4FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,fltVal
) );
1411 res
= VarR4FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,fltVal
) );
1414 res
= VarR4FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,fltVal
) );
1417 V_UNION(pd
,fltVal
) = V_UNION(ps
,scode
);
1420 case( VT_DISPATCH
):
1421 /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1423 /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1426 res
= DISP_E_TYPEMISMATCH
;
1427 FIXME("Coercion from %d to VT_R4\n", vtFrom
);
1436 res
= VarR8FromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,dblVal
) );
1439 res
= VarR8FromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,dblVal
) );
1443 res
= VarR8FromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,dblVal
) );
1446 res
= VarR8FromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,dblVal
) );
1449 res
= VarR8FromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,dblVal
) );
1453 res
= VarR8FromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,dblVal
) );
1456 res
= VarR8FromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,dblVal
) );
1459 res
= VariantCopy( pd
, ps
);
1462 res
= VarR8FromDate( V_UNION(ps
,date
), &V_UNION(pd
,dblVal
) );
1465 res
= VarR8FromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,dblVal
) );
1468 res
= VarR8FromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,dblVal
) );
1471 res
= VarR8FromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,dblVal
) );
1473 case( VT_DISPATCH
):
1474 /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1476 /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1479 res
= DISP_E_TYPEMISMATCH
;
1480 FIXME("Coercion from %d to VT_R8\n", vtFrom
);
1489 res
= VarDateFromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,date
) );
1492 res
= VarDateFromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,date
) );
1495 res
= VarDateFromInt( V_UNION(ps
,intVal
), &V_UNION(pd
,date
) );
1498 res
= VarDateFromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,date
) );
1501 res
= VarDateFromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,date
) );
1504 res
= VarDateFromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,date
) );
1507 res
= VarDateFromUint( V_UNION(ps
,uintVal
), &V_UNION(pd
,date
) );
1510 res
= VarDateFromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,date
) );
1513 res
= VarDateFromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,date
) );
1516 res
= VarDateFromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,date
) );
1519 res
= VarDateFromBool( V_UNION(ps
,boolVal
), &V_UNION(pd
,date
) );
1522 res
= VarDateFromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,date
) );
1525 res
= VarDateFromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,date
) );
1527 case( VT_DISPATCH
):
1528 /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1530 /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1533 res
= DISP_E_TYPEMISMATCH
;
1534 FIXME("Coercion from %d to VT_DATE\n", vtFrom
);
1544 V_UNION(pd
,boolVal
) = VARIANT_FALSE
;
1547 res
= VarBoolFromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,boolVal
) );
1550 res
= VarBoolFromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,boolVal
) );
1553 res
= VarBoolFromInt( V_UNION(ps
,intVal
), &V_UNION(pd
,boolVal
) );
1556 res
= VarBoolFromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,boolVal
) );
1559 res
= VarBoolFromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,boolVal
) );
1562 res
= VarBoolFromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,boolVal
) );
1565 res
= VarBoolFromUint( V_UNION(ps
,uintVal
), &V_UNION(pd
,boolVal
) );
1568 res
= VarBoolFromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,boolVal
) );
1571 res
= VarBoolFromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,boolVal
) );
1574 res
= VarBoolFromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,boolVal
) );
1577 res
= VarBoolFromDate( V_UNION(ps
,date
), &V_UNION(pd
,boolVal
) );
1580 res
= VarBoolFromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,boolVal
) );
1583 res
= VarBoolFromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,boolVal
) );
1585 case( VT_DISPATCH
):
1586 /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1588 /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1591 res
= DISP_E_TYPEMISMATCH
;
1592 FIXME("Coercion from %d to VT_BOOL\n", vtFrom
);
1601 if ((V_UNION(pd
,bstrVal
) = SysAllocStringLen(NULL
, 0)))
1604 res
= E_OUTOFMEMORY
;
1607 res
= VarBstrFromI1( V_UNION(ps
,cVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1610 res
= VarBstrFromI2( V_UNION(ps
,iVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1613 res
= VarBstrFromInt( V_UNION(ps
,intVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1616 res
= VarBstrFromI4( V_UNION(ps
,lVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1619 res
= VarBstrFromUI1( V_UNION(ps
,bVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1622 res
= VarBstrFromUI2( V_UNION(ps
,uiVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1625 res
= VarBstrFromUint( V_UNION(ps
,uintVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1628 res
= VarBstrFromUI4( V_UNION(ps
,ulVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1631 res
= VarBstrFromR4( V_UNION(ps
,fltVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1634 res
= VarBstrFromR8( V_UNION(ps
,dblVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1637 res
= VarBstrFromDate( V_UNION(ps
,date
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1640 res
= VarBstrFromBool( V_UNION(ps
,boolVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1643 res
= VariantCopy( pd
, ps
);
1646 res
= VarBstrFromCy( V_UNION(ps
,cyVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1648 case( VT_DISPATCH
):
1649 /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1651 /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1654 res
= DISP_E_TYPEMISMATCH
;
1655 FIXME("Coercion from %d to VT_BSTR\n", vtFrom
);
1664 res
= VarCyFromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,cyVal
) );
1667 res
= VarCyFromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,cyVal
) );
1670 res
= VarCyFromInt( V_UNION(ps
,intVal
), &V_UNION(pd
,cyVal
) );
1673 res
= VarCyFromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,cyVal
) );
1676 res
= VarCyFromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,cyVal
) );
1679 res
= VarCyFromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,cyVal
) );
1682 res
= VarCyFromUint( V_UNION(ps
,uintVal
), &V_UNION(pd
,cyVal
) );
1685 res
= VarCyFromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,cyVal
) );
1688 res
= VarCyFromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,cyVal
) );
1691 res
= VarCyFromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,cyVal
) );
1694 res
= VarCyFromDate( V_UNION(ps
,date
), &V_UNION(pd
,cyVal
) );
1697 res
= VarCyFromBool( V_UNION(ps
,date
), &V_UNION(pd
,cyVal
) );
1700 res
= VariantCopy( pd
, ps
);
1703 res
= VarCyFromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,cyVal
) );
1705 case( VT_DISPATCH
):
1706 /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1708 /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1712 res
= DISP_E_TYPEMISMATCH
;
1713 FIXME("Coercion from %d to VT_CY\n", vtFrom
);
1721 if (V_DISPATCH(ps
) == NULL
) {
1722 V_UNKNOWN(pd
) = NULL
;
1724 res
= IDispatch_QueryInterface(V_DISPATCH(ps
), &IID_IUnknown
, (LPVOID
*)&V_UNKNOWN(pd
));
1727 case VT_EMPTY
: case VT_NULL
: case VT_I2
: case VT_I4
:
1728 case VT_R4
: case VT_R8
: case VT_CY
: case VT_DATE
:
1729 case VT_BSTR
: case VT_ERROR
: case VT_BOOL
:
1730 case VT_VARIANT
: case VT_DECIMAL
: case VT_I1
: case VT_UI1
:
1731 case VT_UI2
: case VT_UI4
: case VT_I8
: case VT_UI8
: case VT_INT
:
1732 case VT_UINT
: case VT_VOID
: case VT_HRESULT
: case VT_PTR
:
1733 case VT_SAFEARRAY
: case VT_CARRAY
: case VT_USERDEFINED
:
1734 case VT_LPSTR
: case VT_LPWSTR
: case VT_RECORD
: case VT_FILETIME
:
1735 case VT_BLOB
: case VT_STREAM
: case VT_STORAGE
:
1736 case VT_STREAMED_OBJECT
: case VT_STORED_OBJECT
: case VT_BLOB_OBJECT
:
1737 case VT_CF
: case VT_CLSID
:
1738 res
= DISP_E_TYPEMISMATCH
;
1741 FIXME("Coercion from %d to VT_UNKNOWN unhandled.\n", vtFrom
);
1742 res
= DISP_E_BADVARTYPE
;
1747 case( VT_DISPATCH
):
1750 if (V_UNION(ps
,punkVal
) == NULL
) {
1751 V_UNION(pd
,pdispVal
) = NULL
;
1753 res
= IUnknown_QueryInterface(V_UNION(ps
,punkVal
), &IID_IDispatch
, (LPVOID
*)&V_UNION(pd
,pdispVal
));
1756 case VT_EMPTY
: case VT_NULL
: case VT_I2
: case VT_I4
:
1757 case VT_R4
: case VT_R8
: case VT_CY
: case VT_DATE
:
1758 case VT_BSTR
: case VT_ERROR
: case VT_BOOL
:
1759 case VT_VARIANT
: case VT_DECIMAL
: case VT_I1
: case VT_UI1
:
1760 case VT_UI2
: case VT_UI4
: case VT_I8
: case VT_UI8
: case VT_INT
:
1761 case VT_UINT
: case VT_VOID
: case VT_HRESULT
:
1762 case VT_SAFEARRAY
: case VT_CARRAY
: case VT_USERDEFINED
:
1763 case VT_LPSTR
: case VT_LPWSTR
: case VT_RECORD
: case VT_FILETIME
:
1764 case VT_BLOB
: case VT_STREAM
: case VT_STORAGE
:
1765 case VT_STREAMED_OBJECT
: case VT_STORED_OBJECT
: case VT_BLOB_OBJECT
:
1766 case VT_CF
: case VT_CLSID
:
1767 res
= DISP_E_TYPEMISMATCH
;
1770 V_UNION(pd
,pdispVal
) = V_UNION(ps
,pdispVal
);
1773 FIXME("Coercion from %d to VT_DISPATCH unhandled.\n", vtFrom
);
1774 res
= DISP_E_BADVARTYPE
;
1780 res
= DISP_E_TYPEMISMATCH
;
1781 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1788 /******************************************************************************
1789 * ValidateVtRange [INTERNAL]
1791 * Used internally by the hi-level Variant API to determine
1792 * if the vartypes are valid.
1794 static HRESULT WINAPI
ValidateVtRange( VARTYPE vt
)
1796 /* if by value we must make sure it is in the
1797 * range of the valid types.
1799 if( ( vt
& VT_TYPEMASK
) > VT_MAXVALIDTYPE
)
1801 return DISP_E_BADVARTYPE
;
1807 /******************************************************************************
1808 * ValidateVartype [INTERNAL]
1810 * Used internally by the hi-level Variant API to determine
1811 * if the vartypes are valid.
1813 static HRESULT WINAPI
ValidateVariantType( VARTYPE vt
)
1817 /* check if we have a valid argument.
1821 /* if by reference check that the type is in
1822 * the valid range and that it is not of empty or null type
1824 if( ( vt
& VT_TYPEMASK
) == VT_EMPTY
||
1825 ( vt
& VT_TYPEMASK
) == VT_NULL
||
1826 ( vt
& VT_TYPEMASK
) > VT_MAXVALIDTYPE
)
1828 res
= DISP_E_BADVARTYPE
;
1834 res
= ValidateVtRange( vt
);
1840 /******************************************************************************
1841 * ValidateVt [INTERNAL]
1843 * Used internally by the hi-level Variant API to determine
1844 * if the vartypes are valid.
1846 static HRESULT WINAPI
ValidateVt( VARTYPE vt
)
1850 /* check if we have a valid argument.
1854 /* if by reference check that the type is in
1855 * the valid range and that it is not of empty or null type
1857 if( ( vt
& VT_TYPEMASK
) == VT_EMPTY
||
1858 ( vt
& VT_TYPEMASK
) == VT_NULL
||
1859 ( vt
& VT_TYPEMASK
) > VT_MAXVALIDTYPE
)
1861 res
= DISP_E_BADVARTYPE
;
1867 res
= ValidateVtRange( vt
);
1877 /******************************************************************************
1878 * VariantInit [OLEAUT32.8]
1880 * Initializes the Variant. Unlike VariantClear it does not interpret
1881 * the current contents of the Variant.
1883 void WINAPI
VariantInit(VARIANTARG
* pvarg
)
1885 TRACE("(%p)\n",pvarg
);
1887 memset(pvarg
, 0, sizeof (VARIANTARG
));
1888 V_VT(pvarg
) = VT_EMPTY
;
1893 /******************************************************************************
1894 * VariantClear [OLEAUT32.9]
1896 * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1897 * sets the wReservedX field to 0. The current contents of the VARIANT are
1898 * freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1899 * released. If VT_ARRAY the array is freed.
1901 HRESULT WINAPI
VariantClear(VARIANTARG
* pvarg
)
1904 TRACE("(%p)\n",pvarg
);
1906 res
= ValidateVariantType( V_VT(pvarg
) );
1909 if( !( V_VT(pvarg
) & VT_BYREF
) )
1912 * The VT_ARRAY flag is a special case of a safe array.
1914 if ( (V_VT(pvarg
) & VT_ARRAY
) != 0)
1916 SafeArrayDestroy(V_UNION(pvarg
,parray
));
1920 switch( V_VT(pvarg
) & VT_TYPEMASK
)
1923 SysFreeString( V_UNION(pvarg
,bstrVal
) );
1925 case( VT_DISPATCH
):
1926 if(V_UNION(pvarg
,pdispVal
)!=NULL
)
1927 IDispatch_Release(V_UNION(pvarg
,pdispVal
));
1930 VariantClear(V_UNION(pvarg
,pvarVal
));
1933 if(V_UNION(pvarg
,punkVal
)!=NULL
)
1934 IUnknown_Release(V_UNION(pvarg
,punkVal
));
1936 case( VT_SAFEARRAY
):
1937 SafeArrayDestroy(V_UNION(pvarg
,parray
));
1946 * Empty all the fields and mark the type as empty.
1948 memset(pvarg
, 0, sizeof (VARIANTARG
));
1949 V_VT(pvarg
) = VT_EMPTY
;
1955 /******************************************************************************
1956 * VariantCopy [OLEAUT32.10]
1958 * Frees up the designation variant and makes a copy of the source.
1960 HRESULT WINAPI
VariantCopy(VARIANTARG
* pvargDest
, VARIANTARG
* pvargSrc
)
1964 TRACE("(%p, %p), vt=%d\n", pvargDest
, pvargSrc
, V_VT(pvargSrc
));
1966 res
= ValidateVariantType( V_VT(pvargSrc
) );
1968 /* If the pointer are to the same variant we don't need
1971 if( pvargDest
!= pvargSrc
&& res
== S_OK
)
1973 VariantClear( pvargDest
); /* result is not checked */
1975 if( V_VT(pvargSrc
) & VT_BYREF
)
1977 /* In the case of byreference we only need
1978 * to copy the pointer.
1980 pvargDest
->n1
.n2
.n3
= pvargSrc
->n1
.n2
.n3
;
1981 V_VT(pvargDest
) = V_VT(pvargSrc
);
1986 * The VT_ARRAY flag is another way to designate a safe array.
1988 if (V_VT(pvargSrc
) & VT_ARRAY
)
1990 SafeArrayCopy(V_UNION(pvargSrc
,parray
), &V_UNION(pvargDest
,parray
));
1994 /* In the case of by value we need to
1995 * copy the actual value. In the case of
1996 * VT_BSTR a copy of the string is made,
1997 * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1998 * called to increment the object's reference count.
2000 switch( V_VT(pvargSrc
) & VT_TYPEMASK
)
2003 V_UNION(pvargDest
,bstrVal
) = SYSDUPSTRING( V_UNION(pvargSrc
,bstrVal
) );
2005 case( VT_DISPATCH
):
2006 V_UNION(pvargDest
,pdispVal
) = V_UNION(pvargSrc
,pdispVal
);
2007 if (V_UNION(pvargDest
,pdispVal
)!=NULL
)
2008 IDispatch_AddRef(V_UNION(pvargDest
,pdispVal
));
2011 VariantCopy(V_UNION(pvargDest
,pvarVal
),V_UNION(pvargSrc
,pvarVal
));
2014 V_UNION(pvargDest
,punkVal
) = V_UNION(pvargSrc
,punkVal
);
2015 if (V_UNION(pvargDest
,pdispVal
)!=NULL
)
2016 IUnknown_AddRef(V_UNION(pvargDest
,punkVal
));
2018 case( VT_SAFEARRAY
):
2019 SafeArrayCopy(V_UNION(pvargSrc
,parray
), &V_UNION(pvargDest
,parray
));
2022 pvargDest
->n1
.n2
.n3
= pvargSrc
->n1
.n2
.n3
;
2026 V_VT(pvargDest
) = V_VT(pvargSrc
);
2027 dump_Variant(pvargDest
);
2035 /******************************************************************************
2036 * VariantCopyInd [OLEAUT32.11]
2038 * Frees up the destination variant and makes a copy of the source. If
2039 * the source is of type VT_BYREF it performs the necessary indirections.
2041 HRESULT WINAPI
VariantCopyInd(VARIANT
* pvargDest
, VARIANTARG
* pvargSrc
)
2045 TRACE("(%p, %p)\n", pvargDest
, pvargSrc
);
2047 res
= ValidateVariantType( V_VT(pvargSrc
) );
2052 if( V_VT(pvargSrc
) & VT_BYREF
)
2055 VariantInit( &varg
);
2057 /* handle the in place copy.
2059 if( pvargDest
== pvargSrc
)
2061 /* we will use a copy of the source instead.
2063 res
= VariantCopy( &varg
, pvargSrc
);
2069 res
= VariantClear( pvargDest
);
2074 * The VT_ARRAY flag is another way to designate a safearray variant.
2076 if ( V_VT(pvargSrc
) & VT_ARRAY
)
2078 SafeArrayCopy(*V_UNION(pvargSrc
,pparray
), &V_UNION(pvargDest
,parray
));
2082 /* In the case of by reference we need
2083 * to copy the date pointed to by the variant.
2086 /* Get the variant type.
2088 switch( V_VT(pvargSrc
) & VT_TYPEMASK
)
2091 V_UNION(pvargDest
,bstrVal
) = SYSDUPSTRING( *(V_UNION(pvargSrc
,pbstrVal
)) );
2093 case( VT_DISPATCH
):
2094 V_UNION(pvargDest
,pdispVal
) = *V_UNION(pvargSrc
,ppdispVal
);
2095 if (V_UNION(pvargDest
,pdispVal
)!=NULL
)
2096 IDispatch_AddRef(V_UNION(pvargDest
,pdispVal
));
2100 /* Prevent from cycling. According to tests on
2101 * VariantCopyInd in Windows and the documentation
2102 * this API dereferences the inner Variants to only one depth.
2103 * If the inner Variant itself contains an
2104 * other inner variant the E_INVALIDARG error is
2107 if( pvargSrc
->n1
.n2
.wReserved1
& PROCESSING_INNER_VARIANT
)
2109 /* If we get here we are attempting to deference
2110 * an inner variant that that is itself contained
2111 * in an inner variant so report E_INVALIDARG error.
2117 /* Set the processing inner variant flag.
2118 * We will set this flag in the inner variant
2119 * that will be passed to the VariantCopyInd function.
2121 (V_UNION(pvargSrc
,pvarVal
))->n1
.n2
.wReserved1
|= PROCESSING_INNER_VARIANT
;
2123 /* Dereference the inner variant.
2125 res
= VariantCopyInd( pvargDest
, V_UNION(pvargSrc
,pvarVal
) );
2126 /* We must also copy its type, I think.
2128 V_VT(pvargSrc
) = V_VT(V_UNION(pvargSrc
,pvarVal
));
2133 V_UNION(pvargDest
,punkVal
) = *V_UNION(pvargSrc
,ppunkVal
);
2134 if (V_UNION(pvargDest
,pdispVal
)!=NULL
)
2135 IUnknown_AddRef(V_UNION(pvargDest
,punkVal
));
2137 case( VT_SAFEARRAY
):
2138 SafeArrayCopy(*V_UNION(pvargSrc
,pparray
), &V_UNION(pvargDest
,parray
));
2141 /* This is a by reference Variant which means that the union
2142 * part of the Variant contains a pointer to some data of
2143 * type "V_VT(pvargSrc) & VT_TYPEMASK".
2144 * We will deference this data in a generic fashion using
2145 * the void pointer "Variant.u.byref".
2146 * We will copy this data into the union of the destination
2149 memcpy( &pvargDest
->n1
.n2
.n3
, V_UNION(pvargSrc
,byref
), SizeOfVariantData( pvargSrc
) );
2154 if (res
== S_OK
) V_VT(pvargDest
) = V_VT(pvargSrc
) & VT_TYPEMASK
;
2158 /* this should not fail.
2160 VariantClear( &varg
);
2164 res
= VariantCopy( pvargDest
, pvargSrc
);
2170 /******************************************************************************
2171 * Coerces a full safearray. Not optimal code.
2175 VARIANTARG
* src
, VARIANTARG
*dst
, LCID lcid
, USHORT wFlags
, VARTYPE vt
2177 SAFEARRAY
*sarr
= V_ARRAY(src
);
2182 SafeArrayGetVartype(sarr
,&vartype
);
2185 if (sarr
->cDims
!= 1) {
2186 FIXME("Can not coerce array with dim %d into BSTR\n", sarr
->cDims
);
2189 switch (V_VT(src
) & VT_TYPEMASK
) {
2191 hres
= SafeArrayAccessData(sarr
, &data
);
2192 if (FAILED(hres
)) return hres
;
2194 /* Yes, just memcpied apparently. */
2195 V_BSTR(dst
) = SysAllocStringByteLen(data
, sarr
->rgsabound
[0].cElements
);
2196 hres
= SafeArrayUnaccessData(sarr
);
2197 if (FAILED(hres
)) return hres
;
2200 FIXME("Cannot coerce array of %d into BSTR yet. Please report!\n", V_VT(src
) & VT_TYPEMASK
);
2205 V_VT(dst
) = VT_SAFEARRAY
;
2206 return SafeArrayCopy(sarr
, &V_ARRAY(dst
));
2208 FIXME("Cannot coerce array of vt 0x%x/0x%x into vt 0x%x yet. Please report/implement!\n", vartype
, V_VT(src
), vt
);
2214 /******************************************************************************
2215 * VariantChangeType [OLEAUT32.12]
2217 HRESULT WINAPI
VariantChangeType(VARIANTARG
* pvargDest
, VARIANTARG
* pvargSrc
,
2218 USHORT wFlags
, VARTYPE vt
)
2220 return VariantChangeTypeEx( pvargDest
, pvargSrc
, 0, wFlags
, vt
);
2223 /******************************************************************************
2224 * VariantChangeTypeEx [OLEAUT32.147]
2226 HRESULT WINAPI
VariantChangeTypeEx(VARIANTARG
* pvargDest
, VARIANTARG
* pvargSrc
,
2227 LCID lcid
, USHORT wFlags
, VARTYPE vt
)
2231 VariantInit( &varg
);
2233 TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest
, pvargSrc
, lcid
, wFlags
, vt
, V_VT(pvargSrc
));
2234 TRACE("Src Var:\n");
2235 dump_Variant(pvargSrc
);
2237 /* validate our source argument.
2239 res
= ValidateVariantType( V_VT(pvargSrc
) );
2241 /* validate the vartype.
2245 res
= ValidateVt( vt
);
2248 /* if we are doing an in-place conversion make a copy of the source.
2250 if( res
== S_OK
&& pvargDest
== pvargSrc
)
2252 res
= VariantCopy( &varg
, pvargSrc
);
2258 /* free up the destination variant.
2260 res
= VariantClear( pvargDest
);
2265 if( V_VT(pvargSrc
) & VT_BYREF
)
2267 /* Convert the source variant to a "byvalue" variant.
2271 if ((V_VT(pvargSrc
) & 0xf000) != VT_BYREF
) {
2272 FIXME("VT_TYPEMASK %x is unhandled.\n",V_VT(pvargSrc
) & VT_TYPEMASK
);
2276 VariantInit( &Variant
);
2277 res
= VariantCopyInd( &Variant
, pvargSrc
);
2280 res
= Coerce( pvargDest
, lcid
, wFlags
, &Variant
, vt
);
2281 /* this should not fail.
2283 VariantClear( &Variant
);
2286 if (V_VT(pvargSrc
) & VT_ARRAY
) {
2287 if ((V_VT(pvargSrc
) & 0xf000) != VT_ARRAY
) {
2288 FIXME("VT_TYPEMASK %x is unhandled in VT_ARRAY.\n",V_VT(pvargSrc
) & VT_TYPEMASK
);
2291 V_VT(pvargDest
) = VT_ARRAY
| vt
;
2292 res
= coerce_array(pvargSrc
, pvargDest
, lcid
, wFlags
, vt
);
2294 if ((V_VT(pvargSrc
) & 0xf000)) {
2295 FIXME("VT_TYPEMASK %x is unhandled in normal case.\n",V_VT(pvargSrc
) & VT_TYPEMASK
);
2298 /* Use the current "byvalue" source variant.
2300 res
= Coerce( pvargDest
, lcid
, wFlags
, pvargSrc
, vt
);
2304 /* this should not fail.
2306 VariantClear( &varg
);
2308 /* set the type of the destination
2311 V_VT(pvargDest
) = vt
;
2313 TRACE("Dest Var:\n");
2314 dump_Variant(pvargDest
);
2322 /******************************************************************************
2323 * VarUI1FromI2 [OLEAUT32.130]
2325 HRESULT WINAPI
VarUI1FromI2(short sIn
, BYTE
* pbOut
)
2327 TRACE("( %d, %p ), stub\n", sIn
, pbOut
);
2329 /* Check range of value.
2331 if( sIn
< UI1_MIN
|| sIn
> UI1_MAX
)
2333 return DISP_E_OVERFLOW
;
2336 *pbOut
= (BYTE
) sIn
;
2341 /******************************************************************************
2342 * VarUI1FromI4 [OLEAUT32.131]
2344 HRESULT WINAPI
VarUI1FromI4(LONG lIn
, BYTE
* pbOut
)
2346 TRACE("( %ld, %p ), stub\n", lIn
, pbOut
);
2348 /* Check range of value.
2350 if( lIn
< UI1_MIN
|| lIn
> UI1_MAX
)
2352 return DISP_E_OVERFLOW
;
2355 *pbOut
= (BYTE
) lIn
;
2361 /******************************************************************************
2362 * VarUI1FromR4 [OLEAUT32.132]
2364 HRESULT WINAPI
VarUI1FromR4(FLOAT fltIn
, BYTE
* pbOut
)
2366 TRACE("( %f, %p ), stub\n", fltIn
, pbOut
);
2368 /* Check range of value.
2370 fltIn
= round( fltIn
);
2371 if( fltIn
< UI1_MIN
|| fltIn
> UI1_MAX
)
2373 return DISP_E_OVERFLOW
;
2376 *pbOut
= (BYTE
) fltIn
;
2381 /******************************************************************************
2382 * VarUI1FromR8 [OLEAUT32.133]
2384 HRESULT WINAPI
VarUI1FromR8(double dblIn
, BYTE
* pbOut
)
2386 TRACE("( %f, %p ), stub\n", dblIn
, pbOut
);
2388 /* Check range of value.
2390 dblIn
= round( dblIn
);
2391 if( dblIn
< UI1_MIN
|| dblIn
> UI1_MAX
)
2393 return DISP_E_OVERFLOW
;
2396 *pbOut
= (BYTE
) dblIn
;
2401 /******************************************************************************
2402 * VarUI1FromDate [OLEAUT32.135]
2404 HRESULT WINAPI
VarUI1FromDate(DATE dateIn
, BYTE
* pbOut
)
2406 TRACE("( %f, %p ), stub\n", dateIn
, pbOut
);
2408 /* Check range of value.
2410 dateIn
= round( dateIn
);
2411 if( dateIn
< UI1_MIN
|| dateIn
> UI1_MAX
)
2413 return DISP_E_OVERFLOW
;
2416 *pbOut
= (BYTE
) dateIn
;
2421 /******************************************************************************
2422 * VarUI1FromBool [OLEAUT32.138]
2424 HRESULT WINAPI
VarUI1FromBool(VARIANT_BOOL boolIn
, BYTE
* pbOut
)
2426 TRACE("( %d, %p ), stub\n", boolIn
, pbOut
);
2428 *pbOut
= (BYTE
) boolIn
;
2433 /******************************************************************************
2434 * VarUI1FromI1 [OLEAUT32.237]
2436 HRESULT WINAPI
VarUI1FromI1(CHAR cIn
, BYTE
* pbOut
)
2438 TRACE("( %c, %p ), stub\n", cIn
, pbOut
);
2445 /******************************************************************************
2446 * VarUI1FromUI2 [OLEAUT32.238]
2448 HRESULT WINAPI
VarUI1FromUI2(USHORT uiIn
, BYTE
* pbOut
)
2450 TRACE("( %d, %p ), stub\n", uiIn
, pbOut
);
2452 /* Check range of value.
2454 if( uiIn
> UI1_MAX
)
2456 return DISP_E_OVERFLOW
;
2459 *pbOut
= (BYTE
) uiIn
;
2464 /******************************************************************************
2465 * VarUI1FromUI4 [OLEAUT32.239]
2467 HRESULT WINAPI
VarUI1FromUI4(ULONG ulIn
, BYTE
* pbOut
)
2469 TRACE("( %ld, %p ), stub\n", ulIn
, pbOut
);
2471 /* Check range of value.
2473 if( ulIn
> UI1_MAX
)
2475 return DISP_E_OVERFLOW
;
2478 *pbOut
= (BYTE
) ulIn
;
2484 /******************************************************************************
2485 * VarUI1FromStr [OLEAUT32.136]
2487 HRESULT WINAPI
VarUI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, BYTE
* pbOut
)
2489 double dValue
= 0.0;
2490 LPSTR pNewString
= NULL
;
2492 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn
, lcid
, dwFlags
, pbOut
);
2494 /* Check if we have a valid argument
2496 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
2497 RemoveCharacterFromString( pNewString
, "," );
2498 if( IsValidRealString( pNewString
) == FALSE
)
2500 return DISP_E_TYPEMISMATCH
;
2503 /* Convert the valid string to a floating point number.
2505 dValue
= atof( pNewString
);
2507 /* We don't need the string anymore so free it.
2509 HeapFree( GetProcessHeap(), 0 , pNewString
);
2511 /* Check range of value.
2513 dValue
= round( dValue
);
2514 if( dValue
< UI1_MIN
|| dValue
> UI1_MAX
)
2516 return DISP_E_OVERFLOW
;
2519 *pbOut
= (BYTE
) dValue
;
2524 /**********************************************************************
2525 * VarUI1FromCy [OLEAUT32.134]
2526 * Convert currency to unsigned char
2528 HRESULT WINAPI
VarUI1FromCy(CY cyIn
, BYTE
* pbOut
) {
2529 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
2531 if (t
> UI1_MAX
|| t
< UI1_MIN
) return DISP_E_OVERFLOW
;
2537 /******************************************************************************
2538 * VarI2FromUI1 [OLEAUT32.48]
2540 HRESULT WINAPI
VarI2FromUI1(BYTE bIn
, short* psOut
)
2542 TRACE("( 0x%08x, %p ), stub\n", bIn
, psOut
);
2544 *psOut
= (short) bIn
;
2549 /******************************************************************************
2550 * VarI2FromI4 [OLEAUT32.49]
2552 HRESULT WINAPI
VarI2FromI4(LONG lIn
, short* psOut
)
2554 TRACE("( %lx, %p ), stub\n", lIn
, psOut
);
2556 /* Check range of value.
2558 if( lIn
< I2_MIN
|| lIn
> I2_MAX
)
2560 return DISP_E_OVERFLOW
;
2563 *psOut
= (short) lIn
;
2568 /******************************************************************************
2569 * VarI2FromR4 [OLEAUT32.50]
2571 HRESULT WINAPI
VarI2FromR4(FLOAT fltIn
, short* psOut
)
2573 TRACE("( %f, %p ), stub\n", fltIn
, psOut
);
2575 /* Check range of value.
2577 fltIn
= round( fltIn
);
2578 if( fltIn
< I2_MIN
|| fltIn
> I2_MAX
)
2580 return DISP_E_OVERFLOW
;
2583 *psOut
= (short) fltIn
;
2588 /******************************************************************************
2589 * VarI2FromR8 [OLEAUT32.51]
2591 HRESULT WINAPI
VarI2FromR8(double dblIn
, short* psOut
)
2593 TRACE("( %f, %p ), stub\n", dblIn
, psOut
);
2595 /* Check range of value.
2597 dblIn
= round( dblIn
);
2598 if( dblIn
< I2_MIN
|| dblIn
> I2_MAX
)
2600 return DISP_E_OVERFLOW
;
2603 *psOut
= (short) dblIn
;
2608 /******************************************************************************
2609 * VarI2FromDate [OLEAUT32.53]
2611 HRESULT WINAPI
VarI2FromDate(DATE dateIn
, short* psOut
)
2613 TRACE("( %f, %p ), stub\n", dateIn
, psOut
);
2615 /* Check range of value.
2617 dateIn
= round( dateIn
);
2618 if( dateIn
< I2_MIN
|| dateIn
> I2_MAX
)
2620 return DISP_E_OVERFLOW
;
2623 *psOut
= (short) dateIn
;
2628 /******************************************************************************
2629 * VarI2FromBool [OLEAUT32.56]
2631 HRESULT WINAPI
VarI2FromBool(VARIANT_BOOL boolIn
, short* psOut
)
2633 TRACE("( %d, %p ), stub\n", boolIn
, psOut
);
2635 *psOut
= (short) boolIn
;
2640 /******************************************************************************
2641 * VarI2FromI1 [OLEAUT32.205]
2643 HRESULT WINAPI
VarI2FromI1(CHAR cIn
, short* psOut
)
2645 TRACE("( %c, %p ), stub\n", cIn
, psOut
);
2647 *psOut
= (short) cIn
;
2652 /******************************************************************************
2653 * VarI2FromUI2 [OLEAUT32.206]
2655 HRESULT WINAPI
VarI2FromUI2(USHORT uiIn
, short* psOut
)
2657 TRACE("( %d, %p ), stub\n", uiIn
, psOut
);
2659 /* Check range of value.
2663 return DISP_E_OVERFLOW
;
2666 *psOut
= (short) uiIn
;
2671 /******************************************************************************
2672 * VarI2FromUI4 [OLEAUT32.207]
2674 HRESULT WINAPI
VarI2FromUI4(ULONG ulIn
, short* psOut
)
2676 TRACE("( %lx, %p ), stub\n", ulIn
, psOut
);
2678 /* Check range of value.
2680 if( ulIn
< I2_MIN
|| ulIn
> I2_MAX
)
2682 return DISP_E_OVERFLOW
;
2685 *psOut
= (short) ulIn
;
2690 /******************************************************************************
2691 * VarI2FromStr [OLEAUT32.54]
2693 HRESULT WINAPI
VarI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, short* psOut
)
2695 double dValue
= 0.0;
2696 LPSTR pNewString
= NULL
;
2698 TRACE("( %s, 0x%08lx, 0x%08lx, %p ), stub\n", debugstr_w(strIn
), lcid
, dwFlags
, psOut
);
2700 /* Check if we have a valid argument
2702 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
2703 RemoveCharacterFromString( pNewString
, "," );
2704 if( IsValidRealString( pNewString
) == FALSE
)
2706 return DISP_E_TYPEMISMATCH
;
2709 /* Convert the valid string to a floating point number.
2711 dValue
= atof( pNewString
);
2713 /* We don't need the string anymore so free it.
2715 HeapFree( GetProcessHeap(), 0, pNewString
);
2717 /* Check range of value.
2719 dValue
= round( dValue
);
2720 if( dValue
< I2_MIN
|| dValue
> I2_MAX
)
2722 return DISP_E_OVERFLOW
;
2725 *psOut
= (short) dValue
;
2730 /**********************************************************************
2731 * VarI2FromCy [OLEAUT32.52]
2732 * Convert currency to signed short
2734 HRESULT WINAPI
VarI2FromCy(CY cyIn
, short* psOut
) {
2735 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
2737 if (t
> I2_MAX
|| t
< I2_MIN
) return DISP_E_OVERFLOW
;
2743 /******************************************************************************
2744 * VarI4FromUI1 [OLEAUT32.58]
2746 HRESULT WINAPI
VarI4FromUI1(BYTE bIn
, LONG
* plOut
)
2748 TRACE("( %X, %p ), stub\n", bIn
, plOut
);
2750 *plOut
= (LONG
) bIn
;
2756 /******************************************************************************
2757 * VarI4FromR4 [OLEAUT32.60]
2759 HRESULT WINAPI
VarI4FromR4(FLOAT fltIn
, LONG
* plOut
)
2761 TRACE("( %f, %p ), stub\n", fltIn
, plOut
);
2763 /* Check range of value.
2765 fltIn
= round( fltIn
);
2766 if( fltIn
< I4_MIN
|| fltIn
> I4_MAX
)
2768 return DISP_E_OVERFLOW
;
2771 *plOut
= (LONG
) fltIn
;
2776 /******************************************************************************
2777 * VarI4FromR8 [OLEAUT32.61]
2779 HRESULT WINAPI
VarI4FromR8(double dblIn
, LONG
* plOut
)
2781 TRACE("( %f, %p ), stub\n", dblIn
, plOut
);
2783 /* Check range of value.
2785 dblIn
= round( dblIn
);
2786 if( dblIn
< I4_MIN
|| dblIn
> I4_MAX
)
2788 return DISP_E_OVERFLOW
;
2791 *plOut
= (LONG
) dblIn
;
2796 /******************************************************************************
2797 * VarI4FromDate [OLEAUT32.63]
2799 HRESULT WINAPI
VarI4FromDate(DATE dateIn
, LONG
* plOut
)
2801 TRACE("( %f, %p ), stub\n", dateIn
, plOut
);
2803 /* Check range of value.
2805 dateIn
= round( dateIn
);
2806 if( dateIn
< I4_MIN
|| dateIn
> I4_MAX
)
2808 return DISP_E_OVERFLOW
;
2811 *plOut
= (LONG
) dateIn
;
2816 /******************************************************************************
2817 * VarI4FromBool [OLEAUT32.66]
2819 HRESULT WINAPI
VarI4FromBool(VARIANT_BOOL boolIn
, LONG
* plOut
)
2821 TRACE("( %d, %p ), stub\n", boolIn
, plOut
);
2823 *plOut
= (LONG
) boolIn
;
2828 /******************************************************************************
2829 * VarI4FromI1 [OLEAUT32.209]
2831 HRESULT WINAPI
VarI4FromI1(CHAR cIn
, LONG
* plOut
)
2833 TRACE("( %c, %p ), stub\n", cIn
, plOut
);
2835 *plOut
= (LONG
) cIn
;
2840 /******************************************************************************
2841 * VarI4FromUI2 [OLEAUT32.210]
2843 HRESULT WINAPI
VarI4FromUI2(USHORT uiIn
, LONG
* plOut
)
2845 TRACE("( %d, %p ), stub\n", uiIn
, plOut
);
2847 *plOut
= (LONG
) uiIn
;
2852 /******************************************************************************
2853 * VarI4FromUI4 [OLEAUT32.211]
2855 HRESULT WINAPI
VarI4FromUI4(ULONG ulIn
, LONG
* plOut
)
2857 TRACE("( %lx, %p ), stub\n", ulIn
, plOut
);
2859 /* Check range of value.
2861 if( ulIn
< I4_MIN
|| ulIn
> I4_MAX
)
2863 return DISP_E_OVERFLOW
;
2866 *plOut
= (LONG
) ulIn
;
2871 /******************************************************************************
2872 * VarI4FromI2 [OLEAUT32.59]
2874 HRESULT WINAPI
VarI4FromI2(short sIn
, LONG
* plOut
)
2876 TRACE("( %d, %p ), stub\n", sIn
, plOut
);
2878 *plOut
= (LONG
) sIn
;
2883 /******************************************************************************
2884 * VarI4FromStr [OLEAUT32.64]
2886 HRESULT WINAPI
VarI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG
* plOut
)
2888 double dValue
= 0.0;
2889 LPSTR pNewString
= NULL
;
2891 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn
, lcid
, dwFlags
, plOut
);
2893 /* Check if we have a valid argument
2895 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
2896 RemoveCharacterFromString( pNewString
, "," );
2897 if( IsValidRealString( pNewString
) == FALSE
)
2899 return DISP_E_TYPEMISMATCH
;
2902 /* Convert the valid string to a floating point number.
2904 dValue
= atof( pNewString
);
2906 /* We don't need the string anymore so free it.
2908 HeapFree( GetProcessHeap(), 0, pNewString
);
2910 /* Check range of value.
2912 dValue
= round( dValue
);
2913 if( dValue
< I4_MIN
|| dValue
> I4_MAX
)
2915 return DISP_E_OVERFLOW
;
2918 *plOut
= (LONG
) dValue
;
2923 /**********************************************************************
2924 * VarI4FromCy [OLEAUT32.62]
2925 * Convert currency to signed long
2927 HRESULT WINAPI
VarI4FromCy(CY cyIn
, LONG
* plOut
) {
2928 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
2930 if (t
> I4_MAX
|| t
< I4_MIN
) return DISP_E_OVERFLOW
;
2936 /******************************************************************************
2937 * VarR4FromUI1 [OLEAUT32.68]
2939 HRESULT WINAPI
VarR4FromUI1(BYTE bIn
, FLOAT
* pfltOut
)
2941 TRACE("( %X, %p ), stub\n", bIn
, pfltOut
);
2943 *pfltOut
= (FLOAT
) bIn
;
2948 /******************************************************************************
2949 * VarR4FromI2 [OLEAUT32.69]
2951 HRESULT WINAPI
VarR4FromI2(short sIn
, FLOAT
* pfltOut
)
2953 TRACE("( %d, %p ), stub\n", sIn
, pfltOut
);
2955 *pfltOut
= (FLOAT
) sIn
;
2960 /******************************************************************************
2961 * VarR4FromI4 [OLEAUT32.70]
2963 HRESULT WINAPI
VarR4FromI4(LONG lIn
, FLOAT
* pfltOut
)
2965 TRACE("( %lx, %p ), stub\n", lIn
, pfltOut
);
2967 *pfltOut
= (FLOAT
) lIn
;
2972 /******************************************************************************
2973 * VarR4FromR8 [OLEAUT32.71]
2975 HRESULT WINAPI
VarR4FromR8(double dblIn
, FLOAT
* pfltOut
)
2977 TRACE("( %f, %p ), stub\n", dblIn
, pfltOut
);
2979 /* Check range of value.
2981 if( dblIn
< -(FLT_MAX
) || dblIn
> FLT_MAX
)
2983 return DISP_E_OVERFLOW
;
2986 *pfltOut
= (FLOAT
) dblIn
;
2991 /******************************************************************************
2992 * VarR4FromDate [OLEAUT32.73]
2994 HRESULT WINAPI
VarR4FromDate(DATE dateIn
, FLOAT
* pfltOut
)
2996 TRACE("( %f, %p ), stub\n", dateIn
, pfltOut
);
2998 /* Check range of value.
3000 if( dateIn
< -(FLT_MAX
) || dateIn
> FLT_MAX
)
3002 return DISP_E_OVERFLOW
;
3005 *pfltOut
= (FLOAT
) dateIn
;
3010 /******************************************************************************
3011 * VarR4FromBool [OLEAUT32.76]
3013 HRESULT WINAPI
VarR4FromBool(VARIANT_BOOL boolIn
, FLOAT
* pfltOut
)
3015 TRACE("( %d, %p ), stub\n", boolIn
, pfltOut
);
3017 *pfltOut
= (FLOAT
) boolIn
;
3022 /******************************************************************************
3023 * VarR4FromI1 [OLEAUT32.213]
3025 HRESULT WINAPI
VarR4FromI1(CHAR cIn
, FLOAT
* pfltOut
)
3027 TRACE("( %c, %p ), stub\n", cIn
, pfltOut
);
3029 *pfltOut
= (FLOAT
) cIn
;
3034 /******************************************************************************
3035 * VarR4FromUI2 [OLEAUT32.214]
3037 HRESULT WINAPI
VarR4FromUI2(USHORT uiIn
, FLOAT
* pfltOut
)
3039 TRACE("( %d, %p ), stub\n", uiIn
, pfltOut
);
3041 *pfltOut
= (FLOAT
) uiIn
;
3046 /******************************************************************************
3047 * VarR4FromUI4 [OLEAUT32.215]
3049 HRESULT WINAPI
VarR4FromUI4(ULONG ulIn
, FLOAT
* pfltOut
)
3051 TRACE("( %ld, %p ), stub\n", ulIn
, pfltOut
);
3053 *pfltOut
= (FLOAT
) ulIn
;
3058 /******************************************************************************
3059 * VarR4FromStr [OLEAUT32.74]
3061 HRESULT WINAPI
VarR4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, FLOAT
* pfltOut
)
3063 double dValue
= 0.0;
3064 LPSTR pNewString
= NULL
;
3066 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, pfltOut
);
3068 /* Check if we have a valid argument
3070 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
3071 RemoveCharacterFromString( pNewString
, "," );
3072 if( IsValidRealString( pNewString
) == FALSE
)
3074 return DISP_E_TYPEMISMATCH
;
3077 /* Convert the valid string to a floating point number.
3079 dValue
= atof( pNewString
);
3081 /* We don't need the string anymore so free it.
3083 HeapFree( GetProcessHeap(), 0, pNewString
);
3085 /* Check range of value.
3087 if( dValue
< -(FLT_MAX
) || dValue
> FLT_MAX
)
3089 return DISP_E_OVERFLOW
;
3092 *pfltOut
= (FLOAT
) dValue
;
3097 /**********************************************************************
3098 * VarR4FromCy [OLEAUT32.72]
3099 * Convert currency to float
3101 HRESULT WINAPI
VarR4FromCy(CY cyIn
, FLOAT
* pfltOut
) {
3102 *pfltOut
= (FLOAT
)((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
3107 /******************************************************************************
3108 * VarR8FromUI1 [OLEAUT32.78]
3110 HRESULT WINAPI
VarR8FromUI1(BYTE bIn
, double* pdblOut
)
3112 TRACE("( %d, %p ), stub\n", bIn
, pdblOut
);
3114 *pdblOut
= (double) bIn
;
3119 /******************************************************************************
3120 * VarR8FromI2 [OLEAUT32.79]
3122 HRESULT WINAPI
VarR8FromI2(short sIn
, double* pdblOut
)
3124 TRACE("( %d, %p ), stub\n", sIn
, pdblOut
);
3126 *pdblOut
= (double) sIn
;
3131 /******************************************************************************
3132 * VarR8FromI4 [OLEAUT32.80]
3134 HRESULT WINAPI
VarR8FromI4(LONG lIn
, double* pdblOut
)
3136 TRACE("( %ld, %p ), stub\n", lIn
, pdblOut
);
3138 *pdblOut
= (double) lIn
;
3143 /******************************************************************************
3144 * VarR8FromR4 [OLEAUT32.81]
3146 HRESULT WINAPI
VarR8FromR4(FLOAT fltIn
, double* pdblOut
)
3148 TRACE("( %f, %p ), stub\n", fltIn
, pdblOut
);
3150 *pdblOut
= (double) fltIn
;
3155 /******************************************************************************
3156 * VarR8FromDate [OLEAUT32.83]
3158 HRESULT WINAPI
VarR8FromDate(DATE dateIn
, double* pdblOut
)
3160 TRACE("( %f, %p ), stub\n", dateIn
, pdblOut
);
3162 *pdblOut
= (double) dateIn
;
3167 /******************************************************************************
3168 * VarR8FromBool [OLEAUT32.86]
3170 HRESULT WINAPI
VarR8FromBool(VARIANT_BOOL boolIn
, double* pdblOut
)
3172 TRACE("( %d, %p ), stub\n", boolIn
, pdblOut
);
3174 *pdblOut
= (double) boolIn
;
3179 /******************************************************************************
3180 * VarR8FromI1 [OLEAUT32.217]
3182 HRESULT WINAPI
VarR8FromI1(CHAR cIn
, double* pdblOut
)
3184 TRACE("( %c, %p ), stub\n", cIn
, pdblOut
);
3186 *pdblOut
= (double) cIn
;
3191 /******************************************************************************
3192 * VarR8FromUI2 [OLEAUT32.218]
3194 HRESULT WINAPI
VarR8FromUI2(USHORT uiIn
, double* pdblOut
)
3196 TRACE("( %d, %p ), stub\n", uiIn
, pdblOut
);
3198 *pdblOut
= (double) uiIn
;
3203 /******************************************************************************
3204 * VarR8FromUI4 [OLEAUT32.219]
3206 HRESULT WINAPI
VarR8FromUI4(ULONG ulIn
, double* pdblOut
)
3208 TRACE("( %ld, %p ), stub\n", ulIn
, pdblOut
);
3210 *pdblOut
= (double) ulIn
;
3215 /******************************************************************************
3216 * VarR8FromStr [OLEAUT32.84]
3218 HRESULT WINAPI
VarR8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, double* pdblOut
)
3220 double dValue
= 0.0;
3221 LPSTR pNewString
= NULL
;
3223 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
3224 TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString
, lcid
, dwFlags
, pdblOut
);
3226 /* Check if we have a valid argument
3228 RemoveCharacterFromString( pNewString
, "," );
3229 if( IsValidRealString( pNewString
) == FALSE
)
3231 return DISP_E_TYPEMISMATCH
;
3234 /* Convert the valid string to a floating point number.
3236 dValue
= atof( pNewString
);
3238 /* We don't need the string anymore so free it.
3240 HeapFree( GetProcessHeap(), 0, pNewString
);
3247 /**********************************************************************
3248 * VarR8FromCy [OLEAUT32.82]
3249 * Convert currency to double
3251 HRESULT WINAPI
VarR8FromCy(CY cyIn
, double* pdblOut
) {
3252 *pdblOut
= (double)((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
3253 TRACE("%lu %ld -> %f\n", cyIn
.s
.Hi
, cyIn
.s
.Lo
, *pdblOut
);
3257 /******************************************************************************
3258 * VarDateFromUI1 [OLEAUT32.88]
3260 HRESULT WINAPI
VarDateFromUI1(BYTE bIn
, DATE
* pdateOut
)
3262 TRACE("( %d, %p ), stub\n", bIn
, pdateOut
);
3264 *pdateOut
= (DATE
) bIn
;
3269 /******************************************************************************
3270 * VarDateFromI2 [OLEAUT32.89]
3272 HRESULT WINAPI
VarDateFromI2(short sIn
, DATE
* pdateOut
)
3274 TRACE("( %d, %p ), stub\n", sIn
, pdateOut
);
3276 *pdateOut
= (DATE
) sIn
;
3281 /******************************************************************************
3282 * VarDateFromI4 [OLEAUT32.90]
3284 HRESULT WINAPI
VarDateFromI4(LONG lIn
, DATE
* pdateOut
)
3286 TRACE("( %ld, %p ), stub\n", lIn
, pdateOut
);
3288 if( lIn
< DATE_MIN
|| lIn
> DATE_MAX
)
3290 return DISP_E_OVERFLOW
;
3293 *pdateOut
= (DATE
) lIn
;
3298 /******************************************************************************
3299 * VarDateFromR4 [OLEAUT32.91]
3301 HRESULT WINAPI
VarDateFromR4(FLOAT fltIn
, DATE
* pdateOut
)
3303 TRACE("( %f, %p ), stub\n", fltIn
, pdateOut
);
3305 if( ceil(fltIn
) < DATE_MIN
|| floor(fltIn
) > DATE_MAX
)
3307 return DISP_E_OVERFLOW
;
3310 *pdateOut
= (DATE
) fltIn
;
3315 /******************************************************************************
3316 * VarDateFromR8 [OLEAUT32.92]
3318 HRESULT WINAPI
VarDateFromR8(double dblIn
, DATE
* pdateOut
)
3320 TRACE("( %f, %p ), stub\n", dblIn
, pdateOut
);
3322 if( ceil(dblIn
) < DATE_MIN
|| floor(dblIn
) > DATE_MAX
)
3324 return DISP_E_OVERFLOW
;
3327 *pdateOut
= (DATE
) dblIn
;
3332 /******************************************************************************
3333 * VarDateFromStr [OLEAUT32.94]
3334 * The string representing the date is composed of two parts, a date and time.
3336 * The format of the time is has follows:
3337 * hh[:mm][:ss][AM|PM]
3338 * Whitespace can be inserted anywhere between these tokens. A whitespace consists
3339 * of space and/or tab characters, which are ignored.
3341 * The formats for the date part are has follows:
3345 * January dd[,] [yy]yy
3348 * Whitespace can be inserted anywhere between these tokens.
3350 * The formats for the date and time string are has follows.
3351 * date[whitespace][time]
3352 * [time][whitespace]date
3354 * These are the only characters allowed in a string representing a date and time:
3355 * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3357 HRESULT WINAPI
VarDateFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DATE
* pdateOut
)
3362 memset( &TM
, 0, sizeof(TM
) );
3364 TRACE("( %p, %lx, %lx, %p ), stub\n", strIn
, lcid
, dwFlags
, pdateOut
);
3366 if( DateTimeStringToTm( strIn
, dwFlags
, &TM
) )
3368 if( TmToDATE( &TM
, pdateOut
) == FALSE
)
3375 ret
= DISP_E_TYPEMISMATCH
;
3377 TRACE("Return value %f\n", *pdateOut
);
3381 /******************************************************************************
3382 * VarDateFromI1 [OLEAUT32.221]
3384 HRESULT WINAPI
VarDateFromI1(CHAR cIn
, DATE
* pdateOut
)
3386 TRACE("( %c, %p ), stub\n", cIn
, pdateOut
);
3388 *pdateOut
= (DATE
) cIn
;
3393 /******************************************************************************
3394 * VarDateFromUI2 [OLEAUT32.222]
3396 HRESULT WINAPI
VarDateFromUI2(USHORT uiIn
, DATE
* pdateOut
)
3398 TRACE("( %d, %p ), stub\n", uiIn
, pdateOut
);
3400 if( uiIn
> DATE_MAX
)
3402 return DISP_E_OVERFLOW
;
3405 *pdateOut
= (DATE
) uiIn
;
3410 /******************************************************************************
3411 * VarDateFromUI4 [OLEAUT32.223]
3413 HRESULT WINAPI
VarDateFromUI4(ULONG ulIn
, DATE
* pdateOut
)
3415 TRACE("( %ld, %p ), stub\n", ulIn
, pdateOut
);
3417 if( ulIn
< DATE_MIN
|| ulIn
> DATE_MAX
)
3419 return DISP_E_OVERFLOW
;
3422 *pdateOut
= (DATE
) ulIn
;
3427 /******************************************************************************
3428 * VarDateFromBool [OLEAUT32.96]
3430 HRESULT WINAPI
VarDateFromBool(VARIANT_BOOL boolIn
, DATE
* pdateOut
)
3432 TRACE("( %d, %p ), stub\n", boolIn
, pdateOut
);
3434 *pdateOut
= (DATE
) boolIn
;
3439 /**********************************************************************
3440 * VarDateFromCy [OLEAUT32.93]
3441 * Convert currency to date
3443 HRESULT WINAPI
VarDateFromCy(CY cyIn
, DATE
* pdateOut
) {
3444 *pdateOut
= (DATE
)((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
3446 if (*pdateOut
> DATE_MAX
|| *pdateOut
< DATE_MIN
) return DISP_E_TYPEMISMATCH
;
3450 /******************************************************************************
3451 * VarBstrFromUI1 [OLEAUT32.108]
3453 HRESULT WINAPI
VarBstrFromUI1(BYTE bVal
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3455 TRACE("( %d, %ld, %ld, %p ), stub\n", bVal
, lcid
, dwFlags
, pbstrOut
);
3456 sprintf( pBuffer
, "%d", bVal
);
3458 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3463 /******************************************************************************
3464 * VarBstrFromI2 [OLEAUT32.109]
3466 HRESULT WINAPI
VarBstrFromI2(short iVal
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3468 TRACE("( %d, %ld, %ld, %p ), stub\n", iVal
, lcid
, dwFlags
, pbstrOut
);
3469 sprintf( pBuffer
, "%d", iVal
);
3470 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3475 /******************************************************************************
3476 * VarBstrFromI4 [OLEAUT32.110]
3478 HRESULT WINAPI
VarBstrFromI4(LONG lIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3480 TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn
, lcid
, dwFlags
, pbstrOut
);
3482 sprintf( pBuffer
, "%ld", lIn
);
3483 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3488 /******************************************************************************
3489 * VarBstrFromR4 [OLEAUT32.111]
3491 HRESULT WINAPI
VarBstrFromR4(FLOAT fltIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3493 TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn
, lcid
, dwFlags
, pbstrOut
);
3495 sprintf( pBuffer
, "%.7G", fltIn
);
3496 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3501 /******************************************************************************
3502 * VarBstrFromR8 [OLEAUT32.112]
3504 HRESULT WINAPI
VarBstrFromR8(double dblIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3506 TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn
, lcid
, dwFlags
, pbstrOut
);
3508 sprintf( pBuffer
, "%.15G", dblIn
);
3509 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3514 /******************************************************************************
3515 * VarBstrFromCy [OLEAUT32.113]
3517 HRESULT WINAPI
VarBstrFromCy(CY cyIn
, LCID lcid
, ULONG dwFlags
, BSTR
*pbstrOut
) {
3519 double curVal
= 0.0;
3521 TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid
, dwFlags
, pbstrOut
);
3523 /* Firstly get the currency in a double, then put it in a buffer */
3524 rc
= VarR8FromCy(cyIn
, &curVal
);
3526 sprintf(pBuffer
, "%G", curVal
);
3527 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3533 /******************************************************************************
3534 * VarBstrFromDate [OLEAUT32.114]
3536 * The date is implemented using an 8 byte floating-point number.
3537 * Days are represented by whole numbers increments starting with 0.00 as
3538 * being December 30 1899, midnight.
3539 * The hours are expressed as the fractional part of the number.
3540 * December 30 1899 at midnight = 0.00
3541 * January 1 1900 at midnight = 2.00
3542 * January 4 1900 at 6 AM = 5.25
3543 * January 4 1900 at noon = 5.50
3544 * December 29 1899 at midnight = -1.00
3545 * December 18 1899 at midnight = -12.00
3546 * December 18 1899 at 6AM = -12.25
3547 * December 18 1899 at 6PM = -12.75
3548 * December 19 1899 at midnight = -11.00
3549 * The tm structure is as follows:
3551 * int tm_sec; seconds after the minute - [0,59]
3552 * int tm_min; minutes after the hour - [0,59]
3553 * int tm_hour; hours since midnight - [0,23]
3554 * int tm_mday; day of the month - [1,31]
3555 * int tm_mon; months since January - [0,11]
3556 * int tm_year; years
3557 * int tm_wday; days since Sunday - [0,6]
3558 * int tm_yday; days since January 1 - [0,365]
3559 * int tm_isdst; daylight savings time flag
3562 HRESULT WINAPI
VarBstrFromDate(DATE dateIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3565 memset( &TM
, 0, sizeof(TM
) );
3567 TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn
, lcid
, dwFlags
, pbstrOut
);
3569 if( DateToTm( dateIn
, dwFlags
, &TM
) == FALSE
)
3571 return E_INVALIDARG
;
3574 if( dwFlags
& VAR_DATEVALUEONLY
)
3575 strftime( pBuffer
, BUFFER_MAX
, "%x", &TM
);
3576 else if( dwFlags
& VAR_TIMEVALUEONLY
)
3577 strftime( pBuffer
, BUFFER_MAX
, "%X", &TM
);
3579 strftime( pBuffer
, BUFFER_MAX
, "%x %X", &TM
);
3581 TRACE("result: %s\n", pBuffer
);
3582 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3586 /******************************************************************************
3587 * VarBstrFromBool [OLEAUT32.116]
3589 HRESULT WINAPI
VarBstrFromBool(VARIANT_BOOL boolIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3591 TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn
, lcid
, dwFlags
, pbstrOut
);
3593 sprintf( pBuffer
, (boolIn
== VARIANT_FALSE
) ? "False" : "True" );
3595 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3600 /******************************************************************************
3601 * VarBstrFromI1 [OLEAUT32.229]
3603 HRESULT WINAPI
VarBstrFromI1(CHAR cIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3605 TRACE("( %c, %ld, %ld, %p ), stub\n", cIn
, lcid
, dwFlags
, pbstrOut
);
3606 sprintf( pBuffer
, "%d", cIn
);
3607 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3612 /******************************************************************************
3613 * VarBstrFromUI2 [OLEAUT32.230]
3615 HRESULT WINAPI
VarBstrFromUI2(USHORT uiIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3617 TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn
, lcid
, dwFlags
, pbstrOut
);
3618 sprintf( pBuffer
, "%d", uiIn
);
3619 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3624 /******************************************************************************
3625 * VarBstrFromUI4 [OLEAUT32.231]
3627 HRESULT WINAPI
VarBstrFromUI4(ULONG ulIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3629 TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn
, lcid
, dwFlags
, pbstrOut
);
3630 sprintf( pBuffer
, "%ld", ulIn
);
3631 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3636 /******************************************************************************
3637 * VarBoolFromUI1 [OLEAUT32.118]
3639 HRESULT WINAPI
VarBoolFromUI1(BYTE bIn
, VARIANT_BOOL
* pboolOut
)
3641 TRACE("( %d, %p ), stub\n", bIn
, pboolOut
);
3645 *pboolOut
= VARIANT_FALSE
;
3649 *pboolOut
= VARIANT_TRUE
;
3655 /******************************************************************************
3656 * VarBoolFromI2 [OLEAUT32.119]
3658 HRESULT WINAPI
VarBoolFromI2(short sIn
, VARIANT_BOOL
* pboolOut
)
3660 TRACE("( %d, %p ), stub\n", sIn
, pboolOut
);
3662 *pboolOut
= (sIn
) ? VARIANT_TRUE
: VARIANT_FALSE
;
3667 /******************************************************************************
3668 * VarBoolFromI4 [OLEAUT32.120]
3670 HRESULT WINAPI
VarBoolFromI4(LONG lIn
, VARIANT_BOOL
* pboolOut
)
3672 TRACE("( %ld, %p ), stub\n", lIn
, pboolOut
);
3674 *pboolOut
= (lIn
) ? VARIANT_TRUE
: VARIANT_FALSE
;
3679 /******************************************************************************
3680 * VarBoolFromR4 [OLEAUT32.121]
3682 HRESULT WINAPI
VarBoolFromR4(FLOAT fltIn
, VARIANT_BOOL
* pboolOut
)
3684 TRACE("( %f, %p ), stub\n", fltIn
, pboolOut
);
3686 *pboolOut
= (fltIn
== 0.0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3691 /******************************************************************************
3692 * VarBoolFromR8 [OLEAUT32.122]
3694 HRESULT WINAPI
VarBoolFromR8(double dblIn
, VARIANT_BOOL
* pboolOut
)
3696 TRACE("( %f, %p ), stub\n", dblIn
, pboolOut
);
3698 *pboolOut
= (dblIn
== 0.0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3703 /******************************************************************************
3704 * VarBoolFromDate [OLEAUT32.123]
3706 HRESULT WINAPI
VarBoolFromDate(DATE dateIn
, VARIANT_BOOL
* pboolOut
)
3708 TRACE("( %f, %p ), stub\n", dateIn
, pboolOut
);
3710 *pboolOut
= (dateIn
== 0.0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3715 /******************************************************************************
3716 * VarBoolFromStr [OLEAUT32.125]
3718 HRESULT WINAPI
VarBoolFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, VARIANT_BOOL
* pboolOut
)
3721 char* pNewString
= NULL
;
3723 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, pboolOut
);
3725 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
3727 if( pNewString
== NULL
|| strlen( pNewString
) == 0 )
3729 ret
= DISP_E_TYPEMISMATCH
;
3734 if( strncasecmp( pNewString
, "True", strlen( pNewString
) ) == 0 )
3736 *pboolOut
= VARIANT_TRUE
;
3738 else if( strncasecmp( pNewString
, "False", strlen( pNewString
) ) == 0 )
3740 *pboolOut
= VARIANT_FALSE
;
3744 /* Try converting the string to a floating point number.
3746 double dValue
= 0.0;
3747 HRESULT res
= VarR8FromStr( strIn
, lcid
, dwFlags
, &dValue
);
3750 ret
= DISP_E_TYPEMISMATCH
;
3753 *pboolOut
= (dValue
== 0.0) ?
3754 VARIANT_FALSE
: VARIANT_TRUE
;
3758 HeapFree( GetProcessHeap(), 0, pNewString
);
3763 /******************************************************************************
3764 * VarBoolFromI1 [OLEAUT32.233]
3766 HRESULT WINAPI
VarBoolFromI1(CHAR cIn
, VARIANT_BOOL
* pboolOut
)
3768 TRACE("( %c, %p ), stub\n", cIn
, pboolOut
);
3770 *pboolOut
= (cIn
== 0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3775 /******************************************************************************
3776 * VarBoolFromUI2 [OLEAUT32.234]
3778 HRESULT WINAPI
VarBoolFromUI2(USHORT uiIn
, VARIANT_BOOL
* pboolOut
)
3780 TRACE("( %d, %p ), stub\n", uiIn
, pboolOut
);
3782 *pboolOut
= (uiIn
== 0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3787 /******************************************************************************
3788 * VarBoolFromUI4 [OLEAUT32.235]
3790 HRESULT WINAPI
VarBoolFromUI4(ULONG ulIn
, VARIANT_BOOL
* pboolOut
)
3792 TRACE("( %ld, %p ), stub\n", ulIn
, pboolOut
);
3794 *pboolOut
= (ulIn
== 0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3799 /**********************************************************************
3800 * VarBoolFromCy [OLEAUT32.124]
3801 * Convert currency to boolean
3803 HRESULT WINAPI
VarBoolFromCy(CY cyIn
, VARIANT_BOOL
* pboolOut
) {
3804 if (cyIn
.s
.Hi
|| cyIn
.s
.Lo
) *pboolOut
= -1;
3810 /******************************************************************************
3811 * VarI1FromUI1 [OLEAUT32.244]
3813 HRESULT WINAPI
VarI1FromUI1(BYTE bIn
, CHAR
* pcOut
)
3815 TRACE("( %d, %p ), stub\n", bIn
, pcOut
);
3817 /* Check range of value.
3819 if( bIn
> CHAR_MAX
)
3821 return DISP_E_OVERFLOW
;
3824 *pcOut
= (CHAR
) bIn
;
3829 /******************************************************************************
3830 * VarI1FromI2 [OLEAUT32.245]
3832 HRESULT WINAPI
VarI1FromI2(short uiIn
, CHAR
* pcOut
)
3834 TRACE("( %d, %p ), stub\n", uiIn
, pcOut
);
3836 if( uiIn
> CHAR_MAX
)
3838 return DISP_E_OVERFLOW
;
3841 *pcOut
= (CHAR
) uiIn
;
3846 /******************************************************************************
3847 * VarI1FromI4 [OLEAUT32.246]
3849 HRESULT WINAPI
VarI1FromI4(LONG lIn
, CHAR
* pcOut
)
3851 TRACE("( %ld, %p ), stub\n", lIn
, pcOut
);
3853 if( lIn
< CHAR_MIN
|| lIn
> CHAR_MAX
)
3855 return DISP_E_OVERFLOW
;
3858 *pcOut
= (CHAR
) lIn
;
3863 /******************************************************************************
3864 * VarI1FromR4 [OLEAUT32.247]
3866 HRESULT WINAPI
VarI1FromR4(FLOAT fltIn
, CHAR
* pcOut
)
3868 TRACE("( %f, %p ), stub\n", fltIn
, pcOut
);
3870 fltIn
= round( fltIn
);
3871 if( fltIn
< CHAR_MIN
|| fltIn
> CHAR_MAX
)
3873 return DISP_E_OVERFLOW
;
3876 *pcOut
= (CHAR
) fltIn
;
3881 /******************************************************************************
3882 * VarI1FromR8 [OLEAUT32.248]
3884 HRESULT WINAPI
VarI1FromR8(double dblIn
, CHAR
* pcOut
)
3886 TRACE("( %f, %p ), stub\n", dblIn
, pcOut
);
3888 dblIn
= round( dblIn
);
3889 if( dblIn
< CHAR_MIN
|| dblIn
> CHAR_MAX
)
3891 return DISP_E_OVERFLOW
;
3894 *pcOut
= (CHAR
) dblIn
;
3899 /******************************************************************************
3900 * VarI1FromDate [OLEAUT32.249]
3902 HRESULT WINAPI
VarI1FromDate(DATE dateIn
, CHAR
* pcOut
)
3904 TRACE("( %f, %p ), stub\n", dateIn
, pcOut
);
3906 dateIn
= round( dateIn
);
3907 if( dateIn
< CHAR_MIN
|| dateIn
> CHAR_MAX
)
3909 return DISP_E_OVERFLOW
;
3912 *pcOut
= (CHAR
) dateIn
;
3917 /******************************************************************************
3918 * VarI1FromStr [OLEAUT32.251]
3920 HRESULT WINAPI
VarI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, CHAR
* pcOut
)
3922 double dValue
= 0.0;
3923 LPSTR pNewString
= NULL
;
3925 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, pcOut
);
3927 /* Check if we have a valid argument
3929 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
3930 RemoveCharacterFromString( pNewString
, "," );
3931 if( IsValidRealString( pNewString
) == FALSE
)
3933 return DISP_E_TYPEMISMATCH
;
3936 /* Convert the valid string to a floating point number.
3938 dValue
= atof( pNewString
);
3940 /* We don't need the string anymore so free it.
3942 HeapFree( GetProcessHeap(), 0, pNewString
);
3944 /* Check range of value.
3946 dValue
= round( dValue
);
3947 if( dValue
< CHAR_MIN
|| dValue
> CHAR_MAX
)
3949 return DISP_E_OVERFLOW
;
3952 *pcOut
= (CHAR
) dValue
;
3957 /******************************************************************************
3958 * VarI1FromBool [OLEAUT32.253]
3960 HRESULT WINAPI
VarI1FromBool(VARIANT_BOOL boolIn
, CHAR
* pcOut
)
3962 TRACE("( %d, %p ), stub\n", boolIn
, pcOut
);
3964 *pcOut
= (CHAR
) boolIn
;
3969 /******************************************************************************
3970 * VarI1FromUI2 [OLEAUT32.254]
3972 HRESULT WINAPI
VarI1FromUI2(USHORT uiIn
, CHAR
* pcOut
)
3974 TRACE("( %d, %p ), stub\n", uiIn
, pcOut
);
3976 if( uiIn
> CHAR_MAX
)
3978 return DISP_E_OVERFLOW
;
3981 *pcOut
= (CHAR
) uiIn
;
3986 /******************************************************************************
3987 * VarI1FromUI4 [OLEAUT32.255]
3989 HRESULT WINAPI
VarI1FromUI4(ULONG ulIn
, CHAR
* pcOut
)
3991 TRACE("( %ld, %p ), stub\n", ulIn
, pcOut
);
3993 if( ulIn
> CHAR_MAX
)
3995 return DISP_E_OVERFLOW
;
3998 *pcOut
= (CHAR
) ulIn
;
4003 /**********************************************************************
4004 * VarI1FromCy [OLEAUT32.250]
4005 * Convert currency to signed char
4007 HRESULT WINAPI
VarI1FromCy(CY cyIn
, CHAR
* pcOut
) {
4008 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
4010 if (t
> CHAR_MAX
|| t
< CHAR_MIN
) return DISP_E_OVERFLOW
;
4016 /******************************************************************************
4017 * VarUI2FromUI1 [OLEAUT32.257]
4019 HRESULT WINAPI
VarUI2FromUI1(BYTE bIn
, USHORT
* puiOut
)
4021 TRACE("( %d, %p ), stub\n", bIn
, puiOut
);
4023 *puiOut
= (USHORT
) bIn
;
4028 /******************************************************************************
4029 * VarUI2FromI2 [OLEAUT32.258]
4031 HRESULT WINAPI
VarUI2FromI2(short uiIn
, USHORT
* puiOut
)
4033 TRACE("( %d, %p ), stub\n", uiIn
, puiOut
);
4035 if( uiIn
< UI2_MIN
)
4037 return DISP_E_OVERFLOW
;
4040 *puiOut
= (USHORT
) uiIn
;
4045 /******************************************************************************
4046 * VarUI2FromI4 [OLEAUT32.259]
4048 HRESULT WINAPI
VarUI2FromI4(LONG lIn
, USHORT
* puiOut
)
4050 TRACE("( %ld, %p ), stub\n", lIn
, puiOut
);
4052 if( lIn
< UI2_MIN
|| lIn
> UI2_MAX
)
4054 return DISP_E_OVERFLOW
;
4057 *puiOut
= (USHORT
) lIn
;
4062 /******************************************************************************
4063 * VarUI2FromR4 [OLEAUT32.260]
4065 HRESULT WINAPI
VarUI2FromR4(FLOAT fltIn
, USHORT
* puiOut
)
4067 TRACE("( %f, %p ), stub\n", fltIn
, puiOut
);
4069 fltIn
= round( fltIn
);
4070 if( fltIn
< UI2_MIN
|| fltIn
> UI2_MAX
)
4072 return DISP_E_OVERFLOW
;
4075 *puiOut
= (USHORT
) fltIn
;
4080 /******************************************************************************
4081 * VarUI2FromR8 [OLEAUT32.261]
4083 HRESULT WINAPI
VarUI2FromR8(double dblIn
, USHORT
* puiOut
)
4085 TRACE("( %f, %p ), stub\n", dblIn
, puiOut
);
4087 dblIn
= round( dblIn
);
4088 if( dblIn
< UI2_MIN
|| dblIn
> UI2_MAX
)
4090 return DISP_E_OVERFLOW
;
4093 *puiOut
= (USHORT
) dblIn
;
4098 /******************************************************************************
4099 * VarUI2FromDate [OLEAUT32.262]
4101 HRESULT WINAPI
VarUI2FromDate(DATE dateIn
, USHORT
* puiOut
)
4103 TRACE("( %f, %p ), stub\n", dateIn
, puiOut
);
4105 dateIn
= round( dateIn
);
4106 if( dateIn
< UI2_MIN
|| dateIn
> UI2_MAX
)
4108 return DISP_E_OVERFLOW
;
4111 *puiOut
= (USHORT
) dateIn
;
4116 /******************************************************************************
4117 * VarUI2FromStr [OLEAUT32.264]
4119 HRESULT WINAPI
VarUI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, USHORT
* puiOut
)
4121 double dValue
= 0.0;
4122 LPSTR pNewString
= NULL
;
4124 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, puiOut
);
4126 /* Check if we have a valid argument
4128 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
4129 RemoveCharacterFromString( pNewString
, "," );
4130 if( IsValidRealString( pNewString
) == FALSE
)
4132 return DISP_E_TYPEMISMATCH
;
4135 /* Convert the valid string to a floating point number.
4137 dValue
= atof( pNewString
);
4139 /* We don't need the string anymore so free it.
4141 HeapFree( GetProcessHeap(), 0, pNewString
);
4143 /* Check range of value.
4145 dValue
= round( dValue
);
4146 if( dValue
< UI2_MIN
|| dValue
> UI2_MAX
)
4148 return DISP_E_OVERFLOW
;
4151 *puiOut
= (USHORT
) dValue
;
4156 /******************************************************************************
4157 * VarUI2FromBool [OLEAUT32.266]
4159 HRESULT WINAPI
VarUI2FromBool(VARIANT_BOOL boolIn
, USHORT
* puiOut
)
4161 TRACE("( %d, %p ), stub\n", boolIn
, puiOut
);
4163 *puiOut
= (USHORT
) boolIn
;
4168 /******************************************************************************
4169 * VarUI2FromI1 [OLEAUT32.267]
4171 HRESULT WINAPI
VarUI2FromI1(CHAR cIn
, USHORT
* puiOut
)
4173 TRACE("( %c, %p ), stub\n", cIn
, puiOut
);
4175 *puiOut
= (USHORT
) cIn
;
4180 /******************************************************************************
4181 * VarUI2FromUI4 [OLEAUT32.268]
4183 HRESULT WINAPI
VarUI2FromUI4(ULONG ulIn
, USHORT
* puiOut
)
4185 TRACE("( %ld, %p ), stub\n", ulIn
, puiOut
);
4187 if( ulIn
> UI2_MAX
)
4189 return DISP_E_OVERFLOW
;
4192 *puiOut
= (USHORT
) ulIn
;
4197 /******************************************************************************
4198 * VarUI4FromStr [OLEAUT32.277]
4200 HRESULT WINAPI
VarUI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG
* pulOut
)
4202 double dValue
= 0.0;
4203 LPSTR pNewString
= NULL
;
4205 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, pulOut
);
4207 /* Check if we have a valid argument
4209 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
4210 RemoveCharacterFromString( pNewString
, "," );
4211 if( IsValidRealString( pNewString
) == FALSE
)
4213 return DISP_E_TYPEMISMATCH
;
4216 /* Convert the valid string to a floating point number.
4218 dValue
= atof( pNewString
);
4220 /* We don't need the string anymore so free it.
4222 HeapFree( GetProcessHeap(), 0, pNewString
);
4224 /* Check range of value.
4226 dValue
= round( dValue
);
4227 if( dValue
< UI4_MIN
|| dValue
> UI4_MAX
)
4229 return DISP_E_OVERFLOW
;
4232 *pulOut
= (ULONG
) dValue
;
4237 /**********************************************************************
4238 * VarUI2FromCy [OLEAUT32.263]
4239 * Convert currency to unsigned short
4241 HRESULT WINAPI
VarUI2FromCy(CY cyIn
, USHORT
* pusOut
) {
4242 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
4244 if (t
> UI2_MAX
|| t
< UI2_MIN
) return DISP_E_OVERFLOW
;
4246 *pusOut
= (USHORT
)t
;
4251 /******************************************************************************
4252 * VarUI4FromUI1 [OLEAUT32.270]
4254 HRESULT WINAPI
VarUI4FromUI1(BYTE bIn
, ULONG
* pulOut
)
4256 TRACE("( %d, %p ), stub\n", bIn
, pulOut
);
4258 *pulOut
= (USHORT
) bIn
;
4263 /******************************************************************************
4264 * VarUI4FromI2 [OLEAUT32.271]
4266 HRESULT WINAPI
VarUI4FromI2(short uiIn
, ULONG
* pulOut
)
4268 TRACE("( %d, %p ), stub\n", uiIn
, pulOut
);
4270 if( uiIn
< UI4_MIN
)
4272 return DISP_E_OVERFLOW
;
4275 *pulOut
= (ULONG
) uiIn
;
4280 /******************************************************************************
4281 * VarUI4FromI4 [OLEAUT32.272]
4283 HRESULT WINAPI
VarUI4FromI4(LONG lIn
, ULONG
* pulOut
)
4285 TRACE("( %ld, %p ), stub\n", lIn
, pulOut
);
4289 return DISP_E_OVERFLOW
;
4292 *pulOut
= (ULONG
) lIn
;
4297 /******************************************************************************
4298 * VarUI4FromR4 [OLEAUT32.273]
4300 HRESULT WINAPI
VarUI4FromR4(FLOAT fltIn
, ULONG
* pulOut
)
4302 fltIn
= round( fltIn
);
4303 if( fltIn
< UI4_MIN
|| fltIn
> UI4_MAX
)
4305 return DISP_E_OVERFLOW
;
4308 *pulOut
= (ULONG
) fltIn
;
4313 /******************************************************************************
4314 * VarUI4FromR8 [OLEAUT32.274]
4316 HRESULT WINAPI
VarUI4FromR8(double dblIn
, ULONG
* pulOut
)
4318 TRACE("( %f, %p ), stub\n", dblIn
, pulOut
);
4320 dblIn
= round( dblIn
);
4321 if( dblIn
< UI4_MIN
|| dblIn
> UI4_MAX
)
4323 return DISP_E_OVERFLOW
;
4326 *pulOut
= (ULONG
) dblIn
;
4331 /******************************************************************************
4332 * VarUI4FromDate [OLEAUT32.275]
4334 HRESULT WINAPI
VarUI4FromDate(DATE dateIn
, ULONG
* pulOut
)
4336 TRACE("( %f, %p ), stub\n", dateIn
, pulOut
);
4338 dateIn
= round( dateIn
);
4339 if( dateIn
< UI4_MIN
|| dateIn
> UI4_MAX
)
4341 return DISP_E_OVERFLOW
;
4344 *pulOut
= (ULONG
) dateIn
;
4349 /******************************************************************************
4350 * VarUI4FromBool [OLEAUT32.279]
4352 HRESULT WINAPI
VarUI4FromBool(VARIANT_BOOL boolIn
, ULONG
* pulOut
)
4354 TRACE("( %d, %p ), stub\n", boolIn
, pulOut
);
4356 *pulOut
= (ULONG
) boolIn
;
4361 /******************************************************************************
4362 * VarUI4FromI1 [OLEAUT32.280]
4364 HRESULT WINAPI
VarUI4FromI1(CHAR cIn
, ULONG
* pulOut
)
4366 TRACE("( %c, %p ), stub\n", cIn
, pulOut
);
4368 *pulOut
= (ULONG
) cIn
;
4373 /******************************************************************************
4374 * VarUI4FromUI2 [OLEAUT32.281]
4376 HRESULT WINAPI
VarUI4FromUI2(USHORT uiIn
, ULONG
* pulOut
)
4378 TRACE("( %d, %p ), stub\n", uiIn
, pulOut
);
4380 *pulOut
= (ULONG
) uiIn
;
4385 /**********************************************************************
4386 * VarUI4FromCy [OLEAUT32.276]
4387 * Convert currency to unsigned long
4389 HRESULT WINAPI
VarUI4FromCy(CY cyIn
, ULONG
* pulOut
) {
4390 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
4392 if (t
> UI4_MAX
|| t
< UI4_MIN
) return DISP_E_OVERFLOW
;
4399 /**********************************************************************
4400 * VarCyFromUI1 [OLEAUT32.98]
4401 * Convert unsigned char to currency
4403 HRESULT WINAPI
VarCyFromUI1(BYTE bIn
, CY
* pcyOut
) {
4405 pcyOut
->s
.Lo
= ((ULONG
)bIn
) * 10000;
4410 /**********************************************************************
4411 * VarCyFromI2 [OLEAUT32.99]
4412 * Convert signed short to currency
4414 HRESULT WINAPI
VarCyFromI2(short sIn
, CY
* pcyOut
) {
4415 if (sIn
< 0) pcyOut
->s
.Hi
= -1;
4416 else pcyOut
->s
.Hi
= 0;
4417 pcyOut
->s
.Lo
= ((ULONG
)sIn
) * 10000;
4422 /**********************************************************************
4423 * VarCyFromI4 [OLEAUT32.100]
4424 * Convert signed long to currency
4426 HRESULT WINAPI
VarCyFromI4(LONG lIn
, CY
* pcyOut
) {
4427 double t
= (double)lIn
* (double)10000;
4428 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4429 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4430 if (lIn
< 0) pcyOut
->s
.Hi
--;
4435 /**********************************************************************
4436 * VarCyFromR4 [OLEAUT32.101]
4437 * Convert float to currency
4439 HRESULT WINAPI
VarCyFromR4(FLOAT fltIn
, CY
* pcyOut
) {
4440 double t
= round((double)fltIn
* (double)10000);
4441 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4442 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4443 if (fltIn
< 0) pcyOut
->s
.Hi
--;
4448 /**********************************************************************
4449 * VarCyFromR8 [OLEAUT32.102]
4450 * Convert double to currency
4452 HRESULT WINAPI
VarCyFromR8(double dblIn
, CY
* pcyOut
) {
4453 double t
= round(dblIn
* (double)10000);
4454 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4455 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4456 if (dblIn
< 0) pcyOut
->s
.Hi
--;
4461 /**********************************************************************
4462 * VarCyFromDate [OLEAUT32.103]
4463 * Convert date to currency
4465 HRESULT WINAPI
VarCyFromDate(DATE dateIn
, CY
* pcyOut
) {
4466 double t
= round((double)dateIn
* (double)10000);
4467 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4468 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4469 if (dateIn
< 0) pcyOut
->s
.Hi
--;
4474 /**********************************************************************
4475 * VarCyFromStr [OLEAUT32.104]
4476 * FIXME: Never tested with decimal seperator other than '.'
4478 HRESULT WINAPI
VarCyFromStr(OLECHAR
*strIn
, LCID lcid
, ULONG dwFlags
, CY
*pcyOut
) {
4480 LPSTR pNewString
= NULL
;
4481 char *decSep
= NULL
;
4482 char *strPtr
,*curPtr
= NULL
;
4484 double currencyVal
= 0.0;
4487 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
4488 TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString
, lcid
, dwFlags
, pcyOut
);
4490 /* Get locale information - Decimal Seperator (size includes 0x00) */
4491 size
= GetLocaleInfoA(lcid
, LOCALE_SDECIMAL
, NULL
, 0);
4492 decSep
= (char *) malloc(size
);
4493 rc
= GetLocaleInfoA(lcid
, LOCALE_SDECIMAL
, decSep
, size
);
4494 TRACE("Decimal Seperator is '%s'\n", decSep
);
4496 /* Now copy to temporary buffer, skipping any character except 0-9 and
4497 the decimal seperator */
4498 curPtr
= pBuffer
; /* Current position in string being built */
4499 strPtr
= pNewString
; /* Current position in supplied currenct string */
4502 /* If decimal seperator, skip it and put '.' in string */
4503 if (strncmp(strPtr
, decSep
, (size
-1)) == 0) {
4504 strPtr
= strPtr
+ (size
-1);
4507 } else if ((*strPtr
== '+' || *strPtr
== '-') ||
4508 (*strPtr
>= '0' && *strPtr
<= '9')) {
4516 /* Try to get currency into a double */
4517 currencyVal
= atof(pBuffer
);
4518 TRACE("Converted string '%s' to %f\n", pBuffer
, currencyVal
);
4520 /* Free allocated storage */
4521 HeapFree( GetProcessHeap(), 0, pNewString
);
4524 /* Convert double -> currency using internal routine */
4525 return VarCyFromR8(currencyVal
, pcyOut
);
4529 /**********************************************************************
4530 * VarCyFromBool [OLEAUT32.106]
4531 * Convert boolean to currency
4533 HRESULT WINAPI
VarCyFromBool(VARIANT_BOOL boolIn
, CY
* pcyOut
) {
4534 if (boolIn
< 0) pcyOut
->s
.Hi
= -1;
4535 else pcyOut
->s
.Hi
= 0;
4536 pcyOut
->s
.Lo
= (ULONG
)boolIn
* (ULONG
)10000;
4541 /**********************************************************************
4542 * VarCyFromI1 [OLEAUT32.225]
4543 * Convert signed char to currency
4545 HRESULT WINAPI
VarCyFromI1(signed char cIn
, CY
* pcyOut
) {
4546 if (cIn
< 0) pcyOut
->s
.Hi
= -1;
4547 else pcyOut
->s
.Hi
= 0;
4548 pcyOut
->s
.Lo
= (ULONG
)cIn
* (ULONG
)10000;
4553 /**********************************************************************
4554 * VarCyFromUI2 [OLEAUT32.226]
4555 * Convert unsigned short to currency
4557 HRESULT WINAPI
VarCyFromUI2(USHORT usIn
, CY
* pcyOut
) {
4559 pcyOut
->s
.Lo
= (ULONG
)usIn
* (ULONG
)10000;
4564 /**********************************************************************
4565 * VarCyFromUI4 [OLEAUT32.227]
4566 * Convert unsigned long to currency
4568 HRESULT WINAPI
VarCyFromUI4(ULONG ulIn
, CY
* pcyOut
) {
4569 double t
= (double)ulIn
* (double)10000;
4570 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4571 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4577 /**********************************************************************
4578 * DosDateTimeToVariantTime [OLEAUT32.14]
4579 * Convert dos representation of time to the date and time representation
4580 * stored in a variant.
4582 INT WINAPI
DosDateTimeToVariantTime(USHORT wDosDate
, USHORT wDosTime
,
4587 TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate
, wDosTime
, pvtime
);
4589 t
.tm_sec
= (wDosTime
& 0x001f) * 2;
4590 t
.tm_min
= (wDosTime
& 0x07e0) >> 5;
4591 t
.tm_hour
= (wDosTime
& 0xf800) >> 11;
4593 t
.tm_mday
= (wDosDate
& 0x001f);
4594 t
.tm_mon
= (wDosDate
& 0x01e0) >> 5;
4595 t
.tm_year
= ((wDosDate
& 0xfe00) >> 9) + 1980;
4597 return TmToDATE( &t
, pvtime
);
4601 /**********************************************************************
4602 * VarParseNumFromStr [OLEAUT32.46]
4604 HRESULT WINAPI
VarParseNumFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
,
4605 NUMPARSE
* pnumprs
, BYTE
* rgbDig
)
4609 BOOL foundNum
=FALSE
;
4611 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn
),dwFlags
);
4612 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs
->cDig
,pnumprs
->dwInFlags
);
4614 /* The other struct components are to be set by us */
4615 memset(rgbDig
,0,pnumprs
->cDig
);
4617 /* FIXME: Just patching some values in */
4618 pnumprs
->nPwr10
= 0;
4619 pnumprs
->nBaseShift
= 0;
4620 pnumprs
->cchUsed
= lastent
;
4621 pnumprs
->dwOutFlags
= NUMPRS_DECIMAL
;
4624 for (i
=0; strIn
[i
] ;i
++) {
4625 if ((strIn
[i
]>='0') && (strIn
[i
]<='9')) {
4627 if (pnumprs
->cDig
> cDig
) {
4628 *(rgbDig
++)=strIn
[i
]-'0';
4632 } else if ((strIn
[i
]=='-') && (foundNum
==FALSE
)) {
4633 pnumprs
->dwOutFlags
|= NUMPRS_NEG
;
4636 pnumprs
->cDig
= cDig
;
4637 TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs
->cDig
,pnumprs
->dwOutFlags
);
4642 /**********************************************************************
4643 * VarNumFromParseNum [OLEAUT32.47]
4645 HRESULT WINAPI
VarNumFromParseNum(NUMPARSE
* pnumprs
, BYTE
* rgbDig
,
4646 ULONG dwVtBits
, VARIANT
* pvar
)
4650 FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits
);
4653 for (i
=0;i
<pnumprs
->cDig
;i
++)
4654 xint
= xint
*10 + rgbDig
[i
];
4656 if (pnumprs
->dwOutFlags
& NUMPRS_NEG
) {
4661 if (dwVtBits
& VTBIT_I4
) {
4663 V_UNION(pvar
,intVal
) = xint
;
4666 if (dwVtBits
& VTBIT_R8
) {
4668 V_UNION(pvar
,dblVal
) = xint
;
4671 if (dwVtBits
& VTBIT_R4
) {
4673 V_UNION(pvar
,fltVal
) = xint
;
4676 if (dwVtBits
& VTBIT_I2
) {
4678 V_UNION(pvar
,iVal
) = xint
;
4681 /* FIXME: Currency should be from a double */
4682 if (dwVtBits
& VTBIT_CY
) {
4684 TRACE("Calculated currency is xint=%ld\n", xint
);
4685 VarCyFromInt( (int) xint
, &V_UNION(pvar
,cyVal
) );
4686 TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar
,cyVal
).s
.Hi
, V_UNION(pvar
,cyVal
).s
.Lo
);
4687 return VarCyFromInt( (int) xint
, &V_UNION(pvar
,cyVal
) );
4690 FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits
, (int) xint
);
4695 /**********************************************************************
4696 * VarFormatDateTime [OLEAUT32.97]
4698 HRESULT WINAPI
VarFormatDateTime(LPVARIANT var
, INT format
, ULONG dwFlags
, BSTR
*out
)
4700 FIXME("%p %d %lx %p\n", var
, format
, dwFlags
, out
);
4704 /**********************************************************************
4705 * VarFormatCurrency [OLEAUT32.127]
4707 HRESULT WINAPI
VarFormatCurrency(LPVARIANT var
, INT digits
, INT lead
, INT paren
, INT group
, ULONG dwFlags
, BSTR
*out
)
4709 FIXME("%p %d %d %d %d %lx %p\n", var
, digits
, lead
, paren
, group
, dwFlags
, out
);
4713 /**********************************************************************
4714 * VariantTimeToDosDateTime [OLEAUT32.13]
4715 * Convert variant representation of time to the date and time representation
4718 INT WINAPI
VariantTimeToDosDateTime(DATE pvtime
, USHORT
*wDosDate
, USHORT
*wDosTime
)
4724 TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate
, *wDosTime
, &pvtime
);
4726 if (DateToTm(pvtime
, 0, &t
) < 0) return 0;
4728 *wDosTime
= *wDosTime
| (t
.tm_sec
/ 2);
4729 *wDosTime
= *wDosTime
| (t
.tm_min
<< 5);
4730 *wDosTime
= *wDosTime
| (t
.tm_hour
<< 11);
4732 *wDosDate
= *wDosDate
| t
.tm_mday
;
4733 *wDosDate
= *wDosDate
| t
.tm_mon
<< 5;
4734 *wDosDate
= *wDosDate
| ((t
.tm_year
- 1980) << 9) ;
4740 /***********************************************************************
4741 * SystemTimeToVariantTime [OLEAUT32.184]
4743 HRESULT WINAPI
SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime
, double *pvtime
)
4747 TRACE(" %d/%d/%d %d:%d:%d\n",
4748 lpSystemTime
->wMonth
, lpSystemTime
->wDay
,
4749 lpSystemTime
->wYear
, lpSystemTime
->wHour
,
4750 lpSystemTime
->wMinute
, lpSystemTime
->wSecond
);
4752 if (lpSystemTime
->wYear
>= 1900)
4754 t
.tm_sec
= lpSystemTime
->wSecond
;
4755 t
.tm_min
= lpSystemTime
->wMinute
;
4756 t
.tm_hour
= lpSystemTime
->wHour
;
4758 t
.tm_mday
= lpSystemTime
->wDay
;
4759 t
.tm_mon
= lpSystemTime
->wMonth
- 1; /* tm_mon is 0..11, wMonth is 1..12 */
4760 t
.tm_year
= lpSystemTime
->wYear
;
4762 return TmToDATE( &t
, pvtime
);
4767 long firstDayOfNextYear
;
4772 double decimalPart
= 0.0;
4774 t
.tm_sec
= lpSystemTime
->wSecond
;
4775 t
.tm_min
= lpSystemTime
->wMinute
;
4776 t
.tm_hour
= lpSystemTime
->wHour
;
4778 /* Step year forward the same number of years before 1900 */
4779 t
.tm_year
= 1900 + 1899 - lpSystemTime
->wYear
;
4780 t
.tm_mon
= lpSystemTime
->wMonth
- 1;
4781 t
.tm_mday
= lpSystemTime
->wDay
;
4783 /* Calculate date */
4784 TmToDATE( &t
, pvtime
);
4786 thisDay
= (double) floor( *pvtime
);
4787 decimalPart
= fmod( *pvtime
, thisDay
);
4789 /* Now, calculate the same time for the first of Jan that year */
4795 t
.tm_year
= t
.tm_year
+1;
4796 TmToDATE( &t
, &tmpDate
);
4797 firstDayOfNextYear
= (long) floor(tmpDate
);
4799 /* Finally since we know the size of the year, subtract the two to get
4800 remaining time in the year */
4801 leftInYear
= firstDayOfNextYear
- thisDay
;
4803 /* Now we want full years up to the year in question, and remainder of year
4804 of the year in question */
4805 if (isleap(lpSystemTime
->wYear
) ) {
4806 TRACE("Extra day due to leap year\n");
4807 result
= 2.0 - ((firstDayOfNextYear
- 366) + leftInYear
- 2.0);
4809 result
= 2.0 - ((firstDayOfNextYear
- 365) + leftInYear
- 2.0);
4811 *pvtime
= (double) result
+ decimalPart
;
4812 TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime
, firstDayOfNextYear
, thisDay
, leftInYear
);
4820 /***********************************************************************
4821 * VariantTimeToSystemTime [OLEAUT32.185]
4823 HRESULT WINAPI
VariantTimeToSystemTime( double vtime
, LPSYSTEMTIME lpSystemTime
)
4825 double t
= 0, timeofday
= 0;
4827 static const BYTE Days_Per_Month
[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4828 static const BYTE Days_Per_Month_LY
[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4830 /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4831 static const BYTE Month_Code
[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4832 static const BYTE Month_Code_LY
[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4834 /* The Century_Code is used to find the Day of the Week */
4835 static const BYTE Century_Code
[] = {0, 6, 4, 2};
4839 TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime
, lpSystemTime
);
4844 if (DateToTm(vtime
, 0, &r
) <= 0) return 0;
4846 lpSystemTime
->wSecond
= r
.tm_sec
;
4847 lpSystemTime
->wMinute
= r
.tm_min
;
4848 lpSystemTime
->wHour
= r
.tm_hour
;
4849 lpSystemTime
->wDay
= r
.tm_mday
;
4850 lpSystemTime
->wMonth
= r
.tm_mon
;
4852 if (lpSystemTime
->wMonth
== 12)
4853 lpSystemTime
->wMonth
= 1;
4855 lpSystemTime
->wMonth
++;
4857 lpSystemTime
->wYear
= r
.tm_year
;
4863 if (DateToTm(vtime
, 0, &r
) <= 0) return 0;
4865 lpSystemTime
->wSecond
= r
.tm_sec
;
4866 lpSystemTime
->wMinute
= r
.tm_min
;
4867 lpSystemTime
->wHour
= r
.tm_hour
;
4869 lpSystemTime
->wMonth
= 13 - r
.tm_mon
;
4871 if (lpSystemTime
->wMonth
== 1)
4872 lpSystemTime
->wMonth
= 12;
4874 lpSystemTime
->wMonth
--;
4876 lpSystemTime
->wYear
= 1899 - (r
.tm_year
- 1900);
4878 if (!isleap(lpSystemTime
->wYear
) )
4879 lpSystemTime
->wDay
= Days_Per_Month
[13 - lpSystemTime
->wMonth
] - r
.tm_mday
;
4881 lpSystemTime
->wDay
= Days_Per_Month_LY
[13 - lpSystemTime
->wMonth
] - r
.tm_mday
;
4886 if (!isleap(lpSystemTime
->wYear
))
4889 (Century_Code+Month_Code+Year_Code+Day) % 7
4891 The century code repeats every 400 years , so the array
4892 works out like this,
4894 Century_Code[0] is for 16th/20th Centry
4895 Century_Code[1] is for 17th/21th Centry
4896 Century_Code[2] is for 18th/22th Centry
4897 Century_Code[3] is for 19th/23th Centry
4899 The year code is found with the formula (year + (year / 4))
4900 the "year" must be between 0 and 99 .
4902 The Month Code (Month_Code[1]) starts with January and
4906 lpSystemTime
->wDayOfWeek
= (
4907 Century_Code
[(( (lpSystemTime
->wYear
+100) - lpSystemTime
->wYear
%100) /100) %4]+
4908 ((lpSystemTime
->wYear
%100)+(lpSystemTime
->wYear
%100)/4)+
4909 Month_Code
[lpSystemTime
->wMonth
]+
4910 lpSystemTime
->wDay
) % 7;
4912 if (lpSystemTime
->wDayOfWeek
== 0) lpSystemTime
->wDayOfWeek
= 7;
4913 else lpSystemTime
->wDayOfWeek
-= 1;
4917 lpSystemTime
->wDayOfWeek
= (
4918 Century_Code
[(((lpSystemTime
->wYear
+100) - lpSystemTime
->wYear
%100)/100)%4]+
4919 ((lpSystemTime
->wYear
%100)+(lpSystemTime
->wYear
%100)/4)+
4920 Month_Code_LY
[lpSystemTime
->wMonth
]+
4921 lpSystemTime
->wDay
) % 7;
4923 if (lpSystemTime
->wDayOfWeek
== 0) lpSystemTime
->wDayOfWeek
= 7;
4924 else lpSystemTime
->wDayOfWeek
-= 1;
4928 timeofday
= vtime
- t
;
4930 lpSystemTime
->wMilliseconds
= (timeofday
4931 - lpSystemTime
->wHour
*(1/24)
4932 - lpSystemTime
->wMinute
*(1/1440)
4933 - lpSystemTime
->wSecond
*(1/86400) )*(1/5184000);
4938 /***********************************************************************
4939 * VarUdateFromDate [OLEAUT32.331]
4941 HRESULT WINAPI
VarUdateFromDate( DATE datein
, ULONG dwFlags
, UDATE
*pudateout
)
4944 static const BYTE Days_Per_Month
[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4945 static const BYTE Days_Per_Month_LY
[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4947 TRACE("DATE = %f\n", (double)datein
);
4948 i
= VariantTimeToSystemTime(datein
, &(pudateout
->st
) );
4952 pudateout
->wDayOfYear
= 0;
4954 if (isleap(pudateout
->st
.wYear
))
4956 for (i
=1; i
<pudateout
->st
.wMonth
; i
++)
4957 pudateout
->wDayOfYear
+= Days_Per_Month
[i
];
4961 for (i
=1; i
<pudateout
->st
.wMonth
; i
++)
4962 pudateout
->wDayOfYear
+= Days_Per_Month_LY
[i
];
4965 pudateout
->wDayOfYear
+= pudateout
->st
.wDay
;
4966 dwFlags
= 0; /*VAR_VALIDDATE*/
4973 /***********************************************************************
4974 * VarDateFromUdate [OLEAUT32.330]
4976 HRESULT WINAPI
VarDateFromUdate(UDATE
*pudateout
,
4977 ULONG dwFlags
, DATE
*datein
)
4981 TRACE(" %d/%d/%d %d:%d:%d\n",
4982 pudateout
->st
.wMonth
, pudateout
->st
.wDay
,
4983 pudateout
->st
.wYear
, pudateout
->st
.wHour
,
4984 pudateout
->st
.wMinute
, pudateout
->st
.wSecond
);
4987 i
= SystemTimeToVariantTime(&(pudateout
->st
), &t
);
4991 else return E_INVALIDARG
;
4995 /**********************************************************************
4996 * VarBstrCmp [OLEAUT32.314]
4999 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
5000 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
5003 HRESULT WINAPI
VarBstrCmp(BSTR left
, BSTR right
, LCID lcid
, DWORD flags
)
5007 TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left
), debugstr_w(right
), lcid
, flags
);
5009 /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
5010 if((!left
) || (!right
)) {
5012 if (!left
&& (!right
|| *right
==0)) return VARCMP_EQ
;
5013 else if (!right
&& (!left
|| *left
==0)) return VARCMP_EQ
;
5014 else return VARCMP_NULL
;
5017 if(flags
&NORM_IGNORECASE
)
5018 r
= lstrcmpiW(left
,right
);
5020 r
= lstrcmpW(left
,right
);
5030 /**********************************************************************
5031 * VarBstrCat [OLEAUT32.313]
5033 HRESULT WINAPI
VarBstrCat(BSTR left
, BSTR right
, BSTR
*out
)
5038 TRACE("( %s %s %p )\n", debugstr_w(left
), debugstr_w(right
), out
);
5040 /* On Windows, NULL parms are still handled (as empty strings) */
5041 if (left
) size
=size
+ lstrlenW(left
);
5042 if (right
) size
=size
+ lstrlenW(right
);
5045 result
= SysAllocStringLen(NULL
, size
);
5047 if (left
) lstrcatW(result
,left
);
5048 if (right
) lstrcatW(result
,right
);
5049 TRACE("result = %s, [%p]\n", debugstr_w(result
), result
);
5054 /**********************************************************************
5055 * VarCat [OLEAUT32.318]
5057 HRESULT WINAPI
VarCat(LPVARIANT left
, LPVARIANT right
, LPVARIANT out
)
5059 /* Should we VariantClear out? */
5060 /* Can we handle array, vector, by ref etc. */
5061 if ((V_VT(left
)&VT_TYPEMASK
) == VT_NULL
&&
5062 (V_VT(right
)&VT_TYPEMASK
) == VT_NULL
)
5064 V_VT(out
) = VT_NULL
;
5068 if (V_VT(left
) == VT_BSTR
&& V_VT(right
) == VT_BSTR
)
5070 V_VT(out
) = VT_BSTR
;
5071 VarBstrCat (V_BSTR(left
), V_BSTR(right
), &V_BSTR(out
));
5074 if (V_VT(left
) == VT_BSTR
) {
5078 V_VT(out
) = VT_BSTR
;
5079 hres
= VariantChangeTypeEx(&bstrvar
,right
,0,0,VT_BSTR
);
5081 FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right
));
5084 VarBstrCat (V_BSTR(left
), V_BSTR(&bstrvar
), &V_BSTR(out
));
5087 if (V_VT(right
) == VT_BSTR
) {
5091 V_VT(out
) = VT_BSTR
;
5092 hres
= VariantChangeTypeEx(&bstrvar
,left
,0,0,VT_BSTR
);
5094 FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right
));
5097 VarBstrCat (V_BSTR(&bstrvar
), V_BSTR(right
), &V_BSTR(out
));
5100 FIXME ("types %d / %d not supported\n",V_VT(left
)&VT_TYPEMASK
, V_VT(right
)&VT_TYPEMASK
);
5104 /**********************************************************************
5105 * VarCmp [OLEAUT32.176]
5108 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
5109 * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
5112 HRESULT WINAPI
VarCmp(LPVARIANT left
, LPVARIANT right
, LCID lcid
, DWORD flags
)
5124 VariantInit(&lv
);VariantInit(&rv
);
5125 V_VT(right
) &= ~0x8000; /* hack since we sometime get this flag. */
5126 V_VT(left
) &= ~0x8000; /* hack since we sometime get this flag. */
5128 TRACE("Left Var:\n");
5130 TRACE("Right Var:\n");
5131 dump_Variant(right
);
5133 /* If either are null, then return VARCMP_NULL */
5134 if ((V_VT(left
)&VT_TYPEMASK
) == VT_NULL
||
5135 (V_VT(right
)&VT_TYPEMASK
) == VT_NULL
)
5138 /* Strings - use VarBstrCmp */
5139 if ((V_VT(left
)&VT_TYPEMASK
) == VT_BSTR
&&
5140 (V_VT(right
)&VT_TYPEMASK
) == VT_BSTR
) {
5141 return VarBstrCmp(V_BSTR(left
), V_BSTR(right
), lcid
, flags
);
5144 xmask
= (1<<(V_VT(left
)&VT_TYPEMASK
))|(1<<(V_VT(right
)&VT_TYPEMASK
));
5145 if (xmask
& (1<<VT_R8
)) {
5146 rc
= VariantChangeType(&lv
,left
,0,VT_R8
);
5147 if (FAILED(rc
)) return rc
;
5148 rc
= VariantChangeType(&rv
,right
,0,VT_R8
);
5149 if (FAILED(rc
)) return rc
;
5151 if (V_R8(&lv
) == V_R8(&rv
)) return VARCMP_EQ
;
5152 if (V_R8(&lv
) < V_R8(&rv
)) return VARCMP_LT
;
5153 if (V_R8(&lv
) > V_R8(&rv
)) return VARCMP_GT
;
5154 return E_FAIL
; /* can't get here */
5156 if (xmask
& (1<<VT_R4
)) {
5157 rc
= VariantChangeType(&lv
,left
,0,VT_R4
);
5158 if (FAILED(rc
)) return rc
;
5159 rc
= VariantChangeType(&rv
,right
,0,VT_R4
);
5160 if (FAILED(rc
)) return rc
;
5162 if (V_R4(&lv
) == V_R4(&rv
)) return VARCMP_EQ
;
5163 if (V_R4(&lv
) < V_R4(&rv
)) return VARCMP_LT
;
5164 if (V_R4(&lv
) > V_R4(&rv
)) return VARCMP_GT
;
5165 return E_FAIL
; /* can't get here */
5168 /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
5169 Use LONGLONG to maximize ranges */
5171 switch (V_VT(left
)&VT_TYPEMASK
) {
5172 case VT_I1
: lVal
= V_UNION(left
,cVal
); break;
5173 case VT_I2
: lVal
= V_UNION(left
,iVal
); break;
5174 case VT_I4
: lVal
= V_UNION(left
,lVal
); break;
5175 case VT_INT
: lVal
= V_UNION(left
,lVal
); break;
5176 case VT_UI1
: lVal
= V_UNION(left
,bVal
); break;
5177 case VT_UI2
: lVal
= V_UNION(left
,uiVal
); break;
5178 case VT_UI4
: lVal
= V_UNION(left
,ulVal
); break;
5179 case VT_UINT
: lVal
= V_UNION(left
,ulVal
); break;
5180 case VT_BOOL
: lVal
= V_UNION(left
,boolVal
); break;
5181 default: lOk
= FALSE
;
5185 switch (V_VT(right
)&VT_TYPEMASK
) {
5186 case VT_I1
: rVal
= V_UNION(right
,cVal
); break;
5187 case VT_I2
: rVal
= V_UNION(right
,iVal
); break;
5188 case VT_I4
: rVal
= V_UNION(right
,lVal
); break;
5189 case VT_INT
: rVal
= V_UNION(right
,lVal
); break;
5190 case VT_UI1
: rVal
= V_UNION(right
,bVal
); break;
5191 case VT_UI2
: rVal
= V_UNION(right
,uiVal
); break;
5192 case VT_UI4
: rVal
= V_UNION(right
,ulVal
); break;
5193 case VT_UINT
: rVal
= V_UNION(right
,ulVal
); break;
5194 case VT_BOOL
: rVal
= V_UNION(right
,boolVal
); break;
5195 default: rOk
= FALSE
;
5201 } else if (lVal
> rVal
) {
5208 /* Strings - use VarBstrCmp */
5209 if ((V_VT(left
)&VT_TYPEMASK
) == VT_DATE
&&
5210 (V_VT(right
)&VT_TYPEMASK
) == VT_DATE
) {
5212 if (floor(V_UNION(left
,date
)) == floor(V_UNION(right
,date
))) {
5213 /* Due to floating point rounding errors, calculate varDate in whole numbers) */
5214 double wholePart
= 0.0;
5218 /* Get the fraction * 24*60*60 to make it into whole seconds */
5219 wholePart
= (double) floor( V_UNION(left
,date
) );
5220 if (wholePart
== 0) wholePart
= 1;
5221 leftR
= floor(fmod( V_UNION(left
,date
), wholePart
) * (24*60*60));
5223 wholePart
= (double) floor( V_UNION(right
,date
) );
5224 if (wholePart
== 0) wholePart
= 1;
5225 rightR
= floor(fmod( V_UNION(right
,date
), wholePart
) * (24*60*60));
5227 if (leftR
< rightR
) {
5229 } else if (leftR
> rightR
) {
5235 } else if (V_UNION(left
,date
) < V_UNION(right
,date
)) {
5237 } else if (V_UNION(left
,date
) > V_UNION(right
,date
)) {
5241 FIXME("VarCmp partial implementation, doesnt support vt 0x%x / 0x%x\n",V_VT(left
), V_VT(right
));
5245 /**********************************************************************
5246 * VarAnd [OLEAUT32.142]
5249 HRESULT WINAPI
VarAnd(LPVARIANT left
, LPVARIANT right
, LPVARIANT result
)
5251 HRESULT rc
= E_FAIL
;
5253 TRACE("Left Var:\n");
5255 TRACE("Right Var:\n");
5256 dump_Variant(right
);
5258 if ((V_VT(left
)&VT_TYPEMASK
) == VT_BOOL
&&
5259 (V_VT(right
)&VT_TYPEMASK
) == VT_BOOL
) {
5261 V_VT(result
) = VT_BOOL
;
5262 if (V_BOOL(left
) && V_BOOL(right
)) {
5263 V_BOOL(result
) = VARIANT_TRUE
;
5265 V_BOOL(result
) = VARIANT_FALSE
;
5276 int resT
= 0; /* Testing has shown I2 & I2 == I2, all else
5277 becomes I4, even unsigned ints (incl. UI2) */
5280 switch (V_VT(left
)&VT_TYPEMASK
) {
5281 case VT_I1
: lVal
= V_UNION(left
,cVal
); resT
=VT_I4
; break;
5282 case VT_I2
: lVal
= V_UNION(left
,iVal
); resT
=VT_I2
; break;
5283 case VT_I4
: lVal
= V_UNION(left
,lVal
); resT
=VT_I4
; break;
5284 case VT_INT
: lVal
= V_UNION(left
,lVal
); resT
=VT_I4
; break;
5285 case VT_UI1
: lVal
= V_UNION(left
,bVal
); resT
=VT_I4
; break;
5286 case VT_UI2
: lVal
= V_UNION(left
,uiVal
); resT
=VT_I4
; break;
5287 case VT_UI4
: lVal
= V_UNION(left
,ulVal
); resT
=VT_I4
; break;
5288 case VT_UINT
: lVal
= V_UNION(left
,ulVal
); resT
=VT_I4
; break;
5289 default: lOk
= FALSE
;
5293 switch (V_VT(right
)&VT_TYPEMASK
) {
5294 case VT_I1
: rVal
= V_UNION(right
,cVal
); resT
=VT_I4
; break;
5295 case VT_I2
: rVal
= V_UNION(right
,iVal
); resT
=max(VT_I2
, resT
); break;
5296 case VT_I4
: rVal
= V_UNION(right
,lVal
); resT
=VT_I4
; break;
5297 case VT_INT
: rVal
= V_UNION(right
,lVal
); resT
=VT_I4
; break;
5298 case VT_UI1
: rVal
= V_UNION(right
,bVal
); resT
=VT_I4
; break;
5299 case VT_UI2
: rVal
= V_UNION(right
,uiVal
); resT
=VT_I4
; break;
5300 case VT_UI4
: rVal
= V_UNION(right
,ulVal
); resT
=VT_I4
; break;
5301 case VT_UINT
: rVal
= V_UNION(right
,ulVal
); resT
=VT_I4
; break;
5302 default: rOk
= FALSE
;
5306 res
= (lVal
& rVal
);
5307 V_VT(result
) = resT
;
5309 case VT_I2
: V_UNION(result
,iVal
) = res
; break;
5310 case VT_I4
: V_UNION(result
,lVal
) = res
; break;
5312 FIXME("Unexpected result variant type %x\n", resT
);
5313 V_UNION(result
,lVal
) = res
;
5318 FIXME("VarAnd stub\n");
5322 TRACE("rc=%d, Result:\n", (int) rc
);
5323 dump_Variant(result
);
5327 /**********************************************************************
5328 * VarAdd [OLEAUT32.141]
5329 * FIXME: From MSDN: If ... Then
5330 * Both expressions are of the string type Concatenated.
5331 * One expression is a string type and the other a character Addition.
5332 * One expression is numeric and the other is a string Addition.
5333 * Both expressions are numeric Addition.
5334 * Either expression is NULL NULL is returned.
5335 * Both expressions are empty Integer subtype is returned.
5338 HRESULT WINAPI
VarAdd(LPVARIANT left
, LPVARIANT right
, LPVARIANT result
)
5340 HRESULT rc
= E_FAIL
;
5342 TRACE("Left Var:\n");
5344 TRACE("Right Var:\n");
5345 dump_Variant(right
);
5347 /* Handle strings as concat */
5348 if ((V_VT(left
)&VT_TYPEMASK
) == VT_BSTR
&&
5349 (V_VT(right
)&VT_TYPEMASK
) == VT_BSTR
) {
5350 V_VT(result
) = VT_BSTR
;
5351 rc
= VarBstrCat(V_BSTR(left
), V_BSTR(right
), &V_BSTR(result
));
5360 int resT
= 0; /* Testing has shown I2 + I2 == I2, all else
5364 switch (V_VT(left
)&VT_TYPEMASK
) {
5365 case VT_I1
: lVal
= V_UNION(left
,cVal
); resT
=VT_I4
; break;
5366 case VT_I2
: lVal
= V_UNION(left
,iVal
); resT
=VT_I2
; break;
5367 case VT_I4
: lVal
= V_UNION(left
,lVal
); resT
=VT_I4
; break;
5368 case VT_INT
: lVal
= V_UNION(left
,lVal
); resT
=VT_I4
; break;
5369 case VT_UI1
: lVal
= V_UNION(left
,bVal
); resT
=VT_I4
; break;
5370 case VT_UI2
: lVal
= V_UNION(left
,uiVal
); resT
=VT_I4
; break;
5371 case VT_UI4
: lVal
= V_UNION(left
,ulVal
); resT
=VT_I4
; break;
5372 case VT_UINT
: lVal
= V_UNION(left
,ulVal
); resT
=VT_I4
; break;
5373 default: lOk
= FALSE
;
5377 switch (V_VT(right
)&VT_TYPEMASK
) {
5378 case VT_I1
: rVal
= V_UNION(right
,cVal
); resT
=VT_I4
; break;
5379 case VT_I2
: rVal
= V_UNION(right
,iVal
); resT
=max(VT_I2
, resT
); break;
5380 case VT_I4
: rVal
= V_UNION(right
,lVal
); resT
=VT_I4
; break;
5381 case VT_INT
: rVal
= V_UNION(right
,lVal
); resT
=VT_I4
; break;
5382 case VT_UI1
: rVal
= V_UNION(right
,bVal
); resT
=VT_I4
; break;
5383 case VT_UI2
: rVal
= V_UNION(right
,uiVal
); resT
=VT_I4
; break;
5384 case VT_UI4
: rVal
= V_UNION(right
,ulVal
); resT
=VT_I4
; break;
5385 case VT_UINT
: rVal
= V_UNION(right
,ulVal
); resT
=VT_I4
; break;
5386 default: rOk
= FALSE
;
5390 res
= (lVal
+ rVal
);
5391 V_VT(result
) = resT
;
5393 case VT_I2
: V_UNION(result
,iVal
) = res
; break;
5394 case VT_I4
: V_UNION(result
,lVal
) = res
; break;
5396 FIXME("Unexpected result variant type %x\n", resT
);
5397 V_UNION(result
,lVal
) = res
;
5402 FIXME("unimplemented part\n");
5406 TRACE("rc=%d, Result:\n", (int) rc
);
5407 dump_Variant(result
);
5411 /**********************************************************************
5412 * VarMul [OLEAUT32.156]
5415 HRESULT WINAPI
VarMul(LPVARIANT left
, LPVARIANT right
, LPVARIANT result
)
5417 HRESULT rc
= E_FAIL
;
5418 VARTYPE lvt
,rvt
,resvt
;
5422 TRACE("left: ");dump_Variant(left
);
5423 TRACE("right: ");dump_Variant(right
);
5425 VariantInit(&lv
);VariantInit(&rv
);
5426 lvt
= V_VT(left
)&VT_TYPEMASK
;
5427 rvt
= V_VT(right
)&VT_TYPEMASK
;
5428 found
= FALSE
;resvt
=VT_VOID
;
5429 if (((1<<lvt
) | (1<<rvt
)) & ((1<<VT_R4
)|(1<<VT_R8
))) {
5433 if (!found
&& (((1<<lvt
) | (1<<rvt
)) & ((1<<VT_I1
)|(1<<VT_I2
)|(1<<VT_UI1
)|(1<<VT_UI2
)|(1<<VT_I4
)|(1<<VT_UI4
)|(1<<VT_INT
)|(1<<VT_UINT
)))) {
5438 FIXME("can't expand vt %d vs %d to a target type.\n",lvt
,rvt
);
5441 rc
= VariantChangeType(&lv
, left
, 0, resvt
);
5443 FIXME("Could not convert 0x%x to %d?\n",V_VT(left
),resvt
);
5446 rc
= VariantChangeType(&rv
, right
, 0, resvt
);
5448 FIXME("Could not convert 0x%x to %d?\n",V_VT(right
),resvt
);
5453 V_VT(result
) = resvt
;
5454 V_R8(result
) = V_R8(&lv
) * V_R8(&rv
);
5458 V_VT(result
) = resvt
;
5459 V_I4(result
) = V_I4(&lv
) * V_I4(&rv
);
5463 TRACE("rc=%d, Result:\n", (int) rc
);
5464 dump_Variant(result
);
5468 /**********************************************************************
5469 * VarDiv [OLEAUT32.143]
5472 HRESULT WINAPI
VarDiv(LPVARIANT left
, LPVARIANT right
, LPVARIANT result
)
5474 HRESULT rc
= E_FAIL
;
5475 VARTYPE lvt
,rvt
,resvt
;
5479 TRACE("left: ");dump_Variant(left
);
5480 TRACE("right: ");dump_Variant(right
);
5482 VariantInit(&lv
);VariantInit(&rv
);
5483 lvt
= V_VT(left
)&VT_TYPEMASK
;
5484 rvt
= V_VT(right
)&VT_TYPEMASK
;
5485 found
= FALSE
;resvt
= VT_VOID
;
5486 if (((1<<lvt
) | (1<<rvt
)) & ((1<<VT_R4
)|(1<<VT_R8
))) {
5490 if (!found
&& (((1<<lvt
) | (1<<rvt
)) & ((1<<VT_I1
)|(1<<VT_I2
)|(1<<VT_UI1
)|(1<<VT_UI2
)|(1<<VT_I4
)|(1<<VT_UI4
)|(1<<VT_INT
)|(1<<VT_UINT
)))) {
5495 FIXME("can't expand vt %d vs %d to a target type.\n",lvt
,rvt
);
5498 rc
= VariantChangeType(&lv
, left
, 0, resvt
);
5500 FIXME("Could not convert 0x%x to %d?\n",V_VT(left
),resvt
);
5503 rc
= VariantChangeType(&rv
, right
, 0, resvt
);
5505 FIXME("Could not convert 0x%x to %d?\n",V_VT(right
),resvt
);
5510 V_VT(result
) = resvt
;
5511 V_R8(result
) = V_R8(&lv
) / V_R8(&rv
);
5515 V_VT(result
) = resvt
;
5516 V_I4(result
) = V_I4(&lv
) / V_I4(&rv
);
5520 TRACE("rc=%d, Result:\n", (int) rc
);
5521 dump_Variant(result
);
5525 /**********************************************************************
5526 * VarSub [OLEAUT32.159]
5529 HRESULT WINAPI
VarSub(LPVARIANT left
, LPVARIANT right
, LPVARIANT result
)
5531 HRESULT rc
= E_FAIL
;
5532 VARTYPE lvt
,rvt
,resvt
;
5536 TRACE("left: ");dump_Variant(left
);
5537 TRACE("right: ");dump_Variant(right
);
5539 VariantInit(&lv
);VariantInit(&rv
);
5540 lvt
= V_VT(left
)&VT_TYPEMASK
;
5541 rvt
= V_VT(right
)&VT_TYPEMASK
;
5542 found
= FALSE
;resvt
= VT_VOID
;
5543 if (((1<<lvt
) | (1<<rvt
)) & ((1<<VT_R4
)|(1<<VT_R8
))) {
5547 if (!found
&& (((1<<lvt
) | (1<<rvt
)) & ((1<<VT_I1
)|(1<<VT_I2
)|(1<<VT_UI1
)|(1<<VT_UI2
)|(1<<VT_I4
)|(1<<VT_UI4
)|(1<<VT_INT
)|(1<<VT_UINT
)))) {
5552 FIXME("can't expand vt %d vs %d to a target type.\n",lvt
,rvt
);
5555 rc
= VariantChangeType(&lv
, left
, 0, resvt
);
5557 FIXME("Could not convert 0x%x to %d?\n",V_VT(left
),resvt
);
5560 rc
= VariantChangeType(&rv
, right
, 0, resvt
);
5562 FIXME("Could not convert 0x%x to %d?\n",V_VT(right
),resvt
);
5567 V_VT(result
) = resvt
;
5568 V_R8(result
) = V_R8(&lv
) - V_R8(&rv
);
5572 V_VT(result
) = resvt
;
5573 V_I4(result
) = V_I4(&lv
) - V_I4(&rv
);
5577 TRACE("rc=%d, Result:\n", (int) rc
);
5578 dump_Variant(result
);
5582 /**********************************************************************
5583 * VarOr [OLEAUT32.157]
5586 HRESULT WINAPI
VarOr(LPVARIANT left
, LPVARIANT right
, LPVARIANT result
)
5588 HRESULT rc
= E_FAIL
;
5590 TRACE("Left Var:\n");
5592 TRACE("Right Var:\n");
5593 dump_Variant(right
);
5595 if ((V_VT(left
)&VT_TYPEMASK
) == VT_BOOL
&&
5596 (V_VT(right
)&VT_TYPEMASK
) == VT_BOOL
) {
5598 V_VT(result
) = VT_BOOL
;
5599 if (V_BOOL(left
) || V_BOOL(right
)) {
5600 V_BOOL(result
) = VARIANT_TRUE
;
5602 V_BOOL(result
) = VARIANT_FALSE
;
5613 int resT
= 0; /* Testing has shown I2 & I2 == I2, all else
5614 becomes I4, even unsigned ints (incl. UI2) */
5617 switch (V_VT(left
)&VT_TYPEMASK
) {
5618 case VT_I1
: lVal
= V_UNION(left
,cVal
); resT
=VT_I4
; break;
5619 case VT_I2
: lVal
= V_UNION(left
,iVal
); resT
=VT_I2
; break;
5620 case VT_I4
: lVal
= V_UNION(left
,lVal
); resT
=VT_I4
; break;
5621 case VT_INT
: lVal
= V_UNION(left
,lVal
); resT
=VT_I4
; break;
5622 case VT_UI1
: lVal
= V_UNION(left
,bVal
); resT
=VT_I4
; break;
5623 case VT_UI2
: lVal
= V_UNION(left
,uiVal
); resT
=VT_I4
; break;
5624 case VT_UI4
: lVal
= V_UNION(left
,ulVal
); resT
=VT_I4
; break;
5625 case VT_UINT
: lVal
= V_UNION(left
,ulVal
); resT
=VT_I4
; break;
5626 default: lOk
= FALSE
;
5630 switch (V_VT(right
)&VT_TYPEMASK
) {
5631 case VT_I1
: rVal
= V_UNION(right
,cVal
); resT
=VT_I4
; break;
5632 case VT_I2
: rVal
= V_UNION(right
,iVal
); resT
=max(VT_I2
, resT
); break;
5633 case VT_I4
: rVal
= V_UNION(right
,lVal
); resT
=VT_I4
; break;
5634 case VT_INT
: rVal
= V_UNION(right
,lVal
); resT
=VT_I4
; break;
5635 case VT_UI1
: rVal
= V_UNION(right
,bVal
); resT
=VT_I4
; break;
5636 case VT_UI2
: rVal
= V_UNION(right
,uiVal
); resT
=VT_I4
; break;
5637 case VT_UI4
: rVal
= V_UNION(right
,ulVal
); resT
=VT_I4
; break;
5638 case VT_UINT
: rVal
= V_UNION(right
,ulVal
); resT
=VT_I4
; break;
5639 default: rOk
= FALSE
;
5643 res
= (lVal
| rVal
);
5644 V_VT(result
) = resT
;
5646 case VT_I2
: V_UNION(result
,iVal
) = res
; break;
5647 case VT_I4
: V_UNION(result
,lVal
) = res
; break;
5649 FIXME("Unexpected result variant type %x\n", resT
);
5650 V_UNION(result
,lVal
) = res
;
5655 FIXME("unimplemented part\n");
5659 TRACE("rc=%d, Result:\n", (int) rc
);
5660 dump_Variant(result
);
5664 /**********************************************************************
5665 * VarNot [OLEAUT32.174]
5668 HRESULT WINAPI
VarNot(LPVARIANT in
, LPVARIANT result
)
5670 HRESULT rc
= E_FAIL
;
5675 if ((V_VT(in
)&VT_TYPEMASK
) == VT_BOOL
) {
5677 V_VT(result
) = VT_BOOL
;
5679 V_BOOL(result
) = VARIANT_FALSE
;
5681 V_BOOL(result
) = VARIANT_TRUE
;
5686 FIXME("VarNot stub\n");
5689 TRACE("rc=%d, Result:\n", (int) rc
);
5690 dump_Variant(result
);
5694 /**********************************************************************
5695 * VarTokenizeFormatString [OLEAUT32.140]
5697 * From investigation on W2K, a list is built up which is:
5699 * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
5700 * <token> - Insert appropriate token
5703 HRESULT WINAPI
VarTokenizeFormatString(LPOLESTR format
, LPBYTE rgbTok
,
5704 int cbTok
, int iFirstDay
, int iFirstWeek
,
5705 LCID lcid
, int *pcbActual
) {
5708 int realLen
, formatLeft
;
5710 LPSTR pFormatA
, pStart
;
5712 BOOL insertCopy
= FALSE
;
5713 LPSTR copyFrom
= NULL
;
5715 TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format
), rgbTok
, cbTok
,
5716 iFirstDay
, iFirstWeek
);
5718 /* Big enough for header? */
5719 if (cbTok
< sizeof(FORMATHDR
)) {
5720 return TYPE_E_BUFFERTOOSMALL
;
5724 hdr
= (FORMATHDR
*) rgbTok
;
5725 memset(hdr
, 0x00, sizeof(FORMATHDR
));
5726 hdr
->hex3
= 0x03; /* No idea what these are */
5729 /* Start parsing string */
5730 realLen
= sizeof(FORMATHDR
);
5731 pData
= rgbTok
+ realLen
;
5732 pFormatA
= HEAP_strdupWtoA( GetProcessHeap(), 0, format
);
5734 formatLeft
= strlen(pFormatA
);
5736 /* Work through the format */
5737 while (*pFormatA
!= 0x00) {
5740 while (checkStr
>=0 && (formatTokens
[checkStr
].tokenSize
!= 0x00)) {
5741 if (formatLeft
>= formatTokens
[checkStr
].tokenSize
&&
5742 strncmp(formatTokens
[checkStr
].str
, pFormatA
,
5743 formatTokens
[checkStr
].tokenSize
) == 0) {
5744 TRACE("match on '%s'\n", formatTokens
[checkStr
].str
);
5748 /* If we have skipped chars, insert the copy */
5749 if (insertCopy
== TRUE
) {
5751 if ((realLen
+ 3) > cbTok
) {
5752 HeapFree( GetProcessHeap(), 0, pFormatA
);
5753 return TYPE_E_BUFFERTOOSMALL
;
5758 *pData
= (BYTE
)(copyFrom
- pStart
);
5760 *pData
= (BYTE
)(pFormatA
- copyFrom
);
5762 realLen
= realLen
+ 3;
5766 /* Now insert the token itself */
5767 if ((realLen
+ 1) > cbTok
) {
5768 HeapFree( GetProcessHeap(), 0, pFormatA
);
5769 return TYPE_E_BUFFERTOOSMALL
;
5771 *pData
= formatTokens
[checkStr
].tokenId
;
5773 realLen
= realLen
+ 1;
5775 pFormatA
= pFormatA
+ formatTokens
[checkStr
].tokenSize
;
5776 formatLeft
= formatLeft
- formatTokens
[checkStr
].tokenSize
;
5777 checkStr
= -1; /* Flag as found and break out of while loop */
5783 /* Did we ever match a token? */
5784 if (checkStr
!= -1 && insertCopy
== FALSE
) {
5785 TRACE("No match - need to insert copy from %p [%p]\n", pFormatA
, pStart
);
5787 copyFrom
= pFormatA
;
5788 } else if (checkStr
!= -1) {
5789 pFormatA
= pFormatA
+ 1;
5794 /* Finally, if we have skipped chars, insert the copy */
5795 if (insertCopy
== TRUE
) {
5797 TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom
, pStart
, pFormatA
);
5798 if ((realLen
+ 3) > cbTok
) {
5799 HeapFree( GetProcessHeap(), 0, pFormatA
);
5800 return TYPE_E_BUFFERTOOSMALL
;
5805 *pData
= (BYTE
)(copyFrom
- pStart
);
5807 *pData
= (BYTE
)(pFormatA
- copyFrom
);
5809 realLen
= realLen
+ 3;
5812 /* Finally insert the terminator */
5813 if ((realLen
+ 1) > cbTok
) {
5814 HeapFree( GetProcessHeap(), 0, pFormatA
);
5815 return TYPE_E_BUFFERTOOSMALL
;
5818 realLen
= realLen
+ 1;
5820 /* Finally fill in the length */
5822 *pcbActual
= realLen
;
5826 for (i
=0; i
<realLen
; i
=i
+0x10) {
5827 printf(" %4.4x : ", i
);
5828 for (j
=0; j
<0x10 && (i
+j
< realLen
); j
++) {
5829 printf("%2.2x ", rgbTok
[i
+j
]);
5835 HeapFree( GetProcessHeap(), 0, pFormatA
);
5840 /**********************************************************************
5841 * VarFormatFromTokens [OLEAUT32.139]
5842 * FIXME: No account of flags or iFirstDay etc
5844 HRESULT WINAPI
VarFormatFromTokens(LPVARIANT varIn
, LPOLESTR format
,
5845 LPBYTE pbTokCur
, ULONG dwFlags
, BSTR
*pbstrOut
,
5848 FORMATHDR
*hdr
= (FORMATHDR
*)pbTokCur
;
5849 BYTE
*pData
= pbTokCur
+ sizeof (FORMATHDR
);
5850 LPSTR pFormatA
= HEAP_strdupWtoA( GetProcessHeap(), 0, format
);
5851 char output
[BUFFER_MAX
];
5853 int size
, whichToken
;
5859 TRACE("'%s', %p %lx %p only date support\n", pFormatA
, pbTokCur
, dwFlags
, pbstrOut
);
5861 dump_Variant(varIn
);
5863 memset(output
, 0x00, BUFFER_MAX
);
5866 while (*pData
!= TOK_END
&& ((pData
- pbTokCur
) <= (hdr
->len
))) {
5868 TRACE("Output looks like : '%s'\n", output
);
5870 /* Convert varient to appropriate data type */
5872 while ((formatTokens
[whichToken
].tokenSize
!= 0x00) &&
5873 (formatTokens
[whichToken
].tokenId
!= *pData
)) {
5877 /* Use Variant local from here downwards as always correct type */
5878 if (formatTokens
[whichToken
].tokenSize
> 0 &&
5879 formatTokens
[whichToken
].varTypeRequired
!= 0) {
5880 VariantInit( &Variant
);
5881 if (Coerce( &Variant
, lcid
, dwFlags
, varIn
,
5882 formatTokens
[whichToken
].varTypeRequired
) != S_OK
) {
5883 HeapFree( GetProcessHeap(), 0, pFormatA
);
5884 return DISP_E_TYPEMISMATCH
;
5885 } else if (formatTokens
[whichToken
].varTypeRequired
== VT_DATE
) {
5886 if( DateToTm( V_UNION(&Variant
,date
), dwFlags
, &TM
) == FALSE
) {
5887 HeapFree( GetProcessHeap(), 0, pFormatA
);
5888 return E_INVALIDARG
;
5893 TRACE("Looking for match on token '%x'\n", *pData
);
5896 TRACE("Copy from %d for %d bytes\n", *(pData
+1), *(pData
+2));
5897 memcpy(pNextPos
, &pFormatA
[*(pData
+1)], *(pData
+2));
5898 pNextPos
= pNextPos
+ *(pData
+2);
5903 /* Get locale information - Time Seperator */
5904 size
= GetLocaleInfoA(lcid
, LOCALE_STIME
, NULL
, 0);
5905 GetLocaleInfoA(lcid
, LOCALE_STIME
, pNextPos
, size
);
5906 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos
);
5907 pNextPos
= pNextPos
+ size
;
5912 /* Get locale information - Date Seperator */
5913 size
= GetLocaleInfoA(lcid
, LOCALE_SDATE
, NULL
, 0);
5914 GetLocaleInfoA(lcid
, LOCALE_SDATE
, pNextPos
, size
);
5915 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos
);
5916 pNextPos
= pNextPos
+ size
;
5921 sprintf(pNextPos
, "%d", TM
.tm_mday
);
5922 pNextPos
= pNextPos
+ strlen(pNextPos
);
5927 sprintf(pNextPos
, "%2.2d", TM
.tm_mday
);
5928 pNextPos
= pNextPos
+ strlen(pNextPos
);
5933 sprintf(pNextPos
, "%d", TM
.tm_wday
+1);
5934 pNextPos
= pNextPos
+ strlen(pNextPos
);
5939 sprintf(pNextPos
, "%d", TM
.tm_mon
+1);
5940 pNextPos
= pNextPos
+ strlen(pNextPos
);
5945 sprintf(pNextPos
, "%2.2d", TM
.tm_mon
+1);
5946 pNextPos
= pNextPos
+ strlen(pNextPos
);
5951 sprintf(pNextPos
, "%d", ((TM
.tm_mon
+1)/4)+1);
5952 pNextPos
= pNextPos
+ strlen(pNextPos
);
5957 sprintf(pNextPos
, "%2.2d", TM
.tm_yday
+1);
5958 pNextPos
= pNextPos
+ strlen(pNextPos
);
5963 sprintf(pNextPos
, "%2.2d", TM
.tm_year
);
5964 pNextPos
= pNextPos
+ strlen(pNextPos
);
5969 sprintf(pNextPos
, "%4.4d", TM
.tm_year
);
5970 pNextPos
= pNextPos
+ strlen(pNextPos
);
5975 sprintf(pNextPos
, "%d", TM
.tm_hour
);
5976 pNextPos
= pNextPos
+ strlen(pNextPos
);
5981 sprintf(pNextPos
, "%2.2d", TM
.tm_hour
);
5982 pNextPos
= pNextPos
+ strlen(pNextPos
);
5987 sprintf(pNextPos
, "%d", TM
.tm_min
);
5988 pNextPos
= pNextPos
+ strlen(pNextPos
);
5993 sprintf(pNextPos
, "%2.2d", TM
.tm_min
);
5994 pNextPos
= pNextPos
+ strlen(pNextPos
);
5999 sprintf(pNextPos
, "%d", TM
.tm_sec
);
6000 pNextPos
= pNextPos
+ strlen(pNextPos
);
6005 sprintf(pNextPos
, "%2.2d", TM
.tm_sec
);
6006 pNextPos
= pNextPos
+ strlen(pNextPos
);
6026 FIXME("Unhandled token for VarFormat %d\n", *pData
);
6027 HeapFree( GetProcessHeap(), 0, pFormatA
);
6028 return E_INVALIDARG
;
6033 *pbstrOut
= StringDupAtoBstr( output
);
6034 HeapFree( GetProcessHeap(), 0, pFormatA
);
6038 /**********************************************************************
6039 * VarFormat [OLEAUT32.87]
6042 HRESULT WINAPI
VarFormat(LPVARIANT varIn
, LPOLESTR format
,
6043 int firstDay
, int firstWeek
, ULONG dwFlags
,
6046 LPSTR pNewString
= NULL
;
6049 TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
6050 debugstr_w(format
), firstDay
, firstWeek
, dwFlags
);
6052 dump_Variant(varIn
);
6054 /* Note: Must Handle references type Variants (contain ptrs
6055 to values rather than values */
6057 /* Get format string */
6058 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, format
);
6060 /* FIXME: Handle some simple pre-definted format strings : */
6061 if (((V_VT(varIn
)&VT_TYPEMASK
) == VT_CY
) && (lstrcmpiA(pNewString
, "Currency") == 0)) {
6063 /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
6067 /* Handle references type Variants (contain ptrs to values rather than values */
6068 if (V_VT(varIn
)&VT_BYREF
) {
6069 rc
= VarR8FromCy(*(CY
*)V_UNION(varIn
,byref
), &curVal
);
6071 rc
= VarR8FromCy(V_UNION(varIn
,cyVal
), &curVal
);
6075 char tmpStr
[BUFFER_MAX
];
6076 sprintf(tmpStr
, "%f", curVal
);
6077 if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags
, tmpStr
, NULL
, pBuffer
, BUFFER_MAX
) == 0) {
6080 *pbstrOut
= StringDupAtoBstr( pBuffer
);
6084 } else if ((V_VT(varIn
)&VT_TYPEMASK
) == VT_DATE
) {
6086 /* Attempt to do proper formatting! */
6087 int firstToken
= -1;
6089 rc
= VarTokenizeFormatString(format
, pBuffer
, sizeof(pBuffer
), firstDay
,
6090 firstWeek
, GetUserDefaultLCID(), &firstToken
);
6092 rc
= VarFormatFromTokens(varIn
, format
, pBuffer
, dwFlags
, pbstrOut
, GetUserDefaultLCID());
6095 } else if ((V_VT(varIn
)&VT_TYPEMASK
) == VT_R8
) {
6096 if (V_VT(varIn
)&VT_BYREF
) {
6097 sprintf(pBuffer
, "%f", *V_UNION(varIn
,pdblVal
));
6099 sprintf(pBuffer
, "%f", V_UNION(varIn
,dblVal
));
6101 *pbstrOut
= StringDupAtoBstr( pBuffer
);
6102 } else if ((V_VT(varIn
)&VT_TYPEMASK
) == VT_I2
) {
6103 if (V_VT(varIn
)&VT_BYREF
) {
6104 sprintf(pBuffer
, "%d", *V_UNION(varIn
,piVal
));
6106 sprintf(pBuffer
, "%d", V_UNION(varIn
,iVal
));
6108 *pbstrOut
= StringDupAtoBstr( pBuffer
);
6109 } else if ((V_VT(varIn
)&VT_TYPEMASK
) == VT_BSTR
) {
6110 if (V_VT(varIn
)&VT_BYREF
)
6111 *pbstrOut
= SysAllocString( *V_UNION(varIn
,pbstrVal
) );
6113 *pbstrOut
= SysAllocString( V_UNION(varIn
,bstrVal
) );
6115 FIXME("VarFormat: Unsupported format %d!\n", V_VT(varIn
)&VT_TYPEMASK
);
6116 *pbstrOut
= StringDupAtoBstr( "??" );
6119 /* Free allocated storage */
6120 HeapFree( GetProcessHeap(), 0, pNewString
);
6121 TRACE("result: '%s'\n", debugstr_w(*pbstrOut
));
6125 /**********************************************************************
6126 * VarCyMulI4 [OLEAUT32.304]
6127 * Multiply currency value by integer
6129 HRESULT WINAPI
VarCyMulI4(CY cyIn
, LONG mulBy
, CY
*pcyOut
) {
6134 rc
= VarR8FromCy(cyIn
, &cyVal
);
6136 rc
= VarCyFromR8((cyVal
* (double) mulBy
), pcyOut
);
6137 TRACE("Multiply %f by %ld = %f [%ld,%lu]\n", cyVal
, mulBy
, (cyVal
* (double) mulBy
),
6138 pcyOut
->s
.Hi
, pcyOut
->s
.Lo
);