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 fractional 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
);
1545 V_UNION(pd
,boolVal
) = VARIANT_FALSE
;
1548 res
= VarBoolFromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,boolVal
) );
1551 res
= VarBoolFromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,boolVal
) );
1554 res
= VarBoolFromInt( V_UNION(ps
,intVal
), &V_UNION(pd
,boolVal
) );
1557 res
= VarBoolFromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,boolVal
) );
1560 res
= VarBoolFromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,boolVal
) );
1563 res
= VarBoolFromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,boolVal
) );
1566 res
= VarBoolFromUint( V_UNION(ps
,uintVal
), &V_UNION(pd
,boolVal
) );
1569 res
= VarBoolFromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,boolVal
) );
1572 res
= VarBoolFromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,boolVal
) );
1575 res
= VarBoolFromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,boolVal
) );
1578 res
= VarBoolFromDate( V_UNION(ps
,date
), &V_UNION(pd
,boolVal
) );
1581 res
= VarBoolFromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,boolVal
) );
1584 res
= VarBoolFromCy( V_UNION(ps
,cyVal
), &V_UNION(pd
,boolVal
) );
1586 case( VT_DISPATCH
):
1587 /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1589 /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1592 res
= DISP_E_TYPEMISMATCH
;
1593 FIXME("Coercion from %d to VT_BOOL\n", vtFrom
);
1602 if ((V_UNION(pd
,bstrVal
) = SysAllocStringLen(NULL
, 0)))
1605 res
= E_OUTOFMEMORY
;
1608 res
= VarBstrFromI1( V_UNION(ps
,cVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1611 res
= VarBstrFromI2( V_UNION(ps
,iVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1614 res
= VarBstrFromInt( V_UNION(ps
,intVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1617 res
= VarBstrFromI4( V_UNION(ps
,lVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1620 res
= VarBstrFromUI1( V_UNION(ps
,bVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1623 res
= VarBstrFromUI2( V_UNION(ps
,uiVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1626 res
= VarBstrFromUint( V_UNION(ps
,uintVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1629 res
= VarBstrFromUI4( V_UNION(ps
,ulVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1632 res
= VarBstrFromR4( V_UNION(ps
,fltVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1635 res
= VarBstrFromR8( V_UNION(ps
,dblVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1638 res
= VarBstrFromDate( V_UNION(ps
,date
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1641 res
= VarBstrFromBool( V_UNION(ps
,boolVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1644 res
= VariantCopy( pd
, ps
);
1647 res
= VarBstrFromCy( V_UNION(ps
,cyVal
), lcid
, 0, &V_UNION(pd
,bstrVal
) );
1649 case( VT_DISPATCH
):
1650 /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1652 /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1655 res
= DISP_E_TYPEMISMATCH
;
1656 FIXME("Coercion from %d to VT_BSTR\n", vtFrom
);
1665 res
= VarCyFromI1( V_UNION(ps
,cVal
), &V_UNION(pd
,cyVal
) );
1668 res
= VarCyFromI2( V_UNION(ps
,iVal
), &V_UNION(pd
,cyVal
) );
1671 res
= VarCyFromInt( V_UNION(ps
,intVal
), &V_UNION(pd
,cyVal
) );
1674 res
= VarCyFromI4( V_UNION(ps
,lVal
), &V_UNION(pd
,cyVal
) );
1677 res
= VarCyFromUI1( V_UNION(ps
,bVal
), &V_UNION(pd
,cyVal
) );
1680 res
= VarCyFromUI2( V_UNION(ps
,uiVal
), &V_UNION(pd
,cyVal
) );
1683 res
= VarCyFromUint( V_UNION(ps
,uintVal
), &V_UNION(pd
,cyVal
) );
1686 res
= VarCyFromUI4( V_UNION(ps
,ulVal
), &V_UNION(pd
,cyVal
) );
1689 res
= VarCyFromR4( V_UNION(ps
,fltVal
), &V_UNION(pd
,cyVal
) );
1692 res
= VarCyFromR8( V_UNION(ps
,dblVal
), &V_UNION(pd
,cyVal
) );
1695 res
= VarCyFromDate( V_UNION(ps
,date
), &V_UNION(pd
,cyVal
) );
1698 res
= VarCyFromBool( V_UNION(ps
,date
), &V_UNION(pd
,cyVal
) );
1701 res
= VariantCopy( pd
, ps
);
1704 res
= VarCyFromStr( V_UNION(ps
,bstrVal
), lcid
, 0, &V_UNION(pd
,cyVal
) );
1706 case( VT_DISPATCH
):
1707 /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1709 /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1713 res
= DISP_E_TYPEMISMATCH
;
1714 FIXME("Coercion from %d to VT_CY\n", vtFrom
);
1722 if (V_DISPATCH(ps
) == NULL
) {
1723 V_UNKNOWN(pd
) = NULL
;
1725 res
= IDispatch_QueryInterface(V_DISPATCH(ps
), &IID_IUnknown
, (LPVOID
*)&V_UNKNOWN(pd
));
1728 case VT_EMPTY
: case VT_NULL
: case VT_I2
: case VT_I4
:
1729 case VT_R4
: case VT_R8
: case VT_CY
: case VT_DATE
:
1730 case VT_BSTR
: case VT_ERROR
: case VT_BOOL
:
1731 case VT_VARIANT
: case VT_DECIMAL
: case VT_I1
: case VT_UI1
:
1732 case VT_UI2
: case VT_UI4
: case VT_I8
: case VT_UI8
: case VT_INT
:
1733 case VT_UINT
: case VT_VOID
: case VT_HRESULT
: case VT_PTR
:
1734 case VT_SAFEARRAY
: case VT_CARRAY
: case VT_USERDEFINED
:
1735 case VT_LPSTR
: case VT_LPWSTR
: case VT_RECORD
: case VT_FILETIME
:
1736 case VT_BLOB
: case VT_STREAM
: case VT_STORAGE
:
1737 case VT_STREAMED_OBJECT
: case VT_STORED_OBJECT
: case VT_BLOB_OBJECT
:
1738 case VT_CF
: case VT_CLSID
:
1739 res
= DISP_E_TYPEMISMATCH
;
1742 FIXME("Coercion from %d to VT_UNKNOWN unhandled.\n", vtFrom
);
1743 res
= DISP_E_BADVARTYPE
;
1748 case( VT_DISPATCH
):
1751 if (V_UNION(ps
,punkVal
) == NULL
) {
1752 V_UNION(pd
,pdispVal
) = NULL
;
1754 res
= IUnknown_QueryInterface(V_UNION(ps
,punkVal
), &IID_IDispatch
, (LPVOID
*)&V_UNION(pd
,pdispVal
));
1757 case VT_EMPTY
: case VT_NULL
: case VT_I2
: case VT_I4
:
1758 case VT_R4
: case VT_R8
: case VT_CY
: case VT_DATE
:
1759 case VT_BSTR
: case VT_ERROR
: case VT_BOOL
:
1760 case VT_VARIANT
: case VT_DECIMAL
: case VT_I1
: case VT_UI1
:
1761 case VT_UI2
: case VT_UI4
: case VT_I8
: case VT_UI8
: case VT_INT
:
1762 case VT_UINT
: case VT_VOID
: case VT_HRESULT
:
1763 case VT_SAFEARRAY
: case VT_CARRAY
: case VT_USERDEFINED
:
1764 case VT_LPSTR
: case VT_LPWSTR
: case VT_RECORD
: case VT_FILETIME
:
1765 case VT_BLOB
: case VT_STREAM
: case VT_STORAGE
:
1766 case VT_STREAMED_OBJECT
: case VT_STORED_OBJECT
: case VT_BLOB_OBJECT
:
1767 case VT_CF
: case VT_CLSID
:
1768 res
= DISP_E_TYPEMISMATCH
;
1771 V_UNION(pd
,pdispVal
) = V_UNION(ps
,pdispVal
);
1774 FIXME("Coercion from %d to VT_DISPATCH unhandled.\n", vtFrom
);
1775 res
= DISP_E_BADVARTYPE
;
1781 res
= DISP_E_TYPEMISMATCH
;
1782 FIXME("Coercion from %d to %d\n", vtFrom
, vt
);
1789 /******************************************************************************
1790 * ValidateVtRange [INTERNAL]
1792 * Used internally by the hi-level Variant API to determine
1793 * if the vartypes are valid.
1795 static HRESULT WINAPI
ValidateVtRange( VARTYPE vt
)
1797 /* if by value we must make sure it is in the
1798 * range of the valid types.
1800 if( ( vt
& VT_TYPEMASK
) > VT_MAXVALIDTYPE
)
1802 return DISP_E_BADVARTYPE
;
1808 /******************************************************************************
1809 * ValidateVartype [INTERNAL]
1811 * Used internally by the hi-level Variant API to determine
1812 * if the vartypes are valid.
1814 static HRESULT WINAPI
ValidateVariantType( VARTYPE vt
)
1818 /* check if we have a valid argument.
1822 /* if by reference check that the type is in
1823 * the valid range and that it is not of empty or null type
1825 if( ( vt
& VT_TYPEMASK
) == VT_EMPTY
||
1826 ( vt
& VT_TYPEMASK
) == VT_NULL
||
1827 ( vt
& VT_TYPEMASK
) > VT_MAXVALIDTYPE
)
1829 res
= DISP_E_BADVARTYPE
;
1835 res
= ValidateVtRange( vt
);
1841 /******************************************************************************
1842 * ValidateVt [INTERNAL]
1844 * Used internally by the hi-level Variant API to determine
1845 * if the vartypes are valid.
1847 static HRESULT WINAPI
ValidateVt( VARTYPE vt
)
1851 /* check if we have a valid argument.
1855 /* if by reference check that the type is in
1856 * the valid range and that it is not of empty or null type
1858 if( ( vt
& VT_TYPEMASK
) == VT_EMPTY
||
1859 ( vt
& VT_TYPEMASK
) == VT_NULL
||
1860 ( vt
& VT_TYPEMASK
) > VT_MAXVALIDTYPE
)
1862 res
= DISP_E_BADVARTYPE
;
1868 res
= ValidateVtRange( vt
);
1878 /******************************************************************************
1879 * VariantInit [OLEAUT32.8]
1881 * Initializes the Variant. Unlike VariantClear it does not interpret
1882 * the current contents of the Variant.
1884 void WINAPI
VariantInit(VARIANTARG
* pvarg
)
1886 TRACE("(%p)\n",pvarg
);
1888 memset(pvarg
, 0, sizeof (VARIANTARG
));
1889 V_VT(pvarg
) = VT_EMPTY
;
1894 /******************************************************************************
1895 * VariantClear [OLEAUT32.9]
1897 * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1898 * sets the wReservedX field to 0. The current contents of the VARIANT are
1899 * freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1900 * released. If VT_ARRAY the array is freed.
1902 HRESULT WINAPI
VariantClear(VARIANTARG
* pvarg
)
1905 TRACE("(%p)\n",pvarg
);
1907 res
= ValidateVariantType( V_VT(pvarg
) );
1910 if( !( V_VT(pvarg
) & VT_BYREF
) )
1913 * The VT_ARRAY flag is a special case of a safe array.
1915 if ( (V_VT(pvarg
) & VT_ARRAY
) != 0)
1917 SafeArrayDestroy(V_UNION(pvarg
,parray
));
1921 switch( V_VT(pvarg
) & VT_TYPEMASK
)
1924 SysFreeString( V_UNION(pvarg
,bstrVal
) );
1926 case( VT_DISPATCH
):
1927 if(V_UNION(pvarg
,pdispVal
)!=NULL
)
1928 IDispatch_Release(V_UNION(pvarg
,pdispVal
));
1931 VariantClear(V_UNION(pvarg
,pvarVal
));
1934 if(V_UNION(pvarg
,punkVal
)!=NULL
)
1935 IUnknown_Release(V_UNION(pvarg
,punkVal
));
1937 case( VT_SAFEARRAY
):
1938 SafeArrayDestroy(V_UNION(pvarg
,parray
));
1947 * Empty all the fields and mark the type as empty.
1949 memset(pvarg
, 0, sizeof (VARIANTARG
));
1950 V_VT(pvarg
) = VT_EMPTY
;
1956 /******************************************************************************
1957 * VariantCopy [OLEAUT32.10]
1959 * Frees up the designation variant and makes a copy of the source.
1961 HRESULT WINAPI
VariantCopy(VARIANTARG
* pvargDest
, VARIANTARG
* pvargSrc
)
1965 TRACE("(%p, %p), vt=%d\n", pvargDest
, pvargSrc
, V_VT(pvargSrc
));
1967 res
= ValidateVariantType( V_VT(pvargSrc
) );
1969 /* If the pointer are to the same variant we don't need
1972 if( pvargDest
!= pvargSrc
&& res
== S_OK
)
1974 VariantClear( pvargDest
); /* result is not checked */
1976 if( V_VT(pvargSrc
) & VT_BYREF
)
1978 /* In the case of byreference we only need
1979 * to copy the pointer.
1981 pvargDest
->n1
.n2
.n3
= pvargSrc
->n1
.n2
.n3
;
1982 V_VT(pvargDest
) = V_VT(pvargSrc
);
1987 * The VT_ARRAY flag is another way to designate a safe array.
1989 if (V_VT(pvargSrc
) & VT_ARRAY
)
1991 SafeArrayCopy(V_UNION(pvargSrc
,parray
), &V_UNION(pvargDest
,parray
));
1995 /* In the case of by value we need to
1996 * copy the actual value. In the case of
1997 * VT_BSTR a copy of the string is made,
1998 * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1999 * called to increment the object's reference count.
2001 switch( V_VT(pvargSrc
) & VT_TYPEMASK
)
2004 V_UNION(pvargDest
,bstrVal
) = SYSDUPSTRING( V_UNION(pvargSrc
,bstrVal
) );
2006 case( VT_DISPATCH
):
2007 V_UNION(pvargDest
,pdispVal
) = V_UNION(pvargSrc
,pdispVal
);
2008 if (V_UNION(pvargDest
,pdispVal
)!=NULL
)
2009 IDispatch_AddRef(V_UNION(pvargDest
,pdispVal
));
2012 VariantCopy(V_UNION(pvargDest
,pvarVal
),V_UNION(pvargSrc
,pvarVal
));
2015 V_UNION(pvargDest
,punkVal
) = V_UNION(pvargSrc
,punkVal
);
2016 if (V_UNION(pvargDest
,pdispVal
)!=NULL
)
2017 IUnknown_AddRef(V_UNION(pvargDest
,punkVal
));
2019 case( VT_SAFEARRAY
):
2020 SafeArrayCopy(V_UNION(pvargSrc
,parray
), &V_UNION(pvargDest
,parray
));
2023 pvargDest
->n1
.n2
.n3
= pvargSrc
->n1
.n2
.n3
;
2027 V_VT(pvargDest
) = V_VT(pvargSrc
);
2028 dump_Variant(pvargDest
);
2036 /******************************************************************************
2037 * VariantCopyInd [OLEAUT32.11]
2039 * Frees up the destination variant and makes a copy of the source. If
2040 * the source is of type VT_BYREF it performs the necessary indirections.
2042 HRESULT WINAPI
VariantCopyInd(VARIANT
* pvargDest
, VARIANTARG
* pvargSrc
)
2046 TRACE("(%p, %p)\n", pvargDest
, pvargSrc
);
2048 res
= ValidateVariantType( V_VT(pvargSrc
) );
2053 if( V_VT(pvargSrc
) & VT_BYREF
)
2056 VariantInit( &varg
);
2058 /* handle the in place copy.
2060 if( pvargDest
== pvargSrc
)
2062 /* we will use a copy of the source instead.
2064 res
= VariantCopy( &varg
, pvargSrc
);
2070 res
= VariantClear( pvargDest
);
2075 * The VT_ARRAY flag is another way to designate a safearray variant.
2077 if ( V_VT(pvargSrc
) & VT_ARRAY
)
2079 SafeArrayCopy(*V_UNION(pvargSrc
,pparray
), &V_UNION(pvargDest
,parray
));
2083 /* In the case of by reference we need
2084 * to copy the date pointed to by the variant.
2087 /* Get the variant type.
2089 switch( V_VT(pvargSrc
) & VT_TYPEMASK
)
2092 V_UNION(pvargDest
,bstrVal
) = SYSDUPSTRING( *(V_UNION(pvargSrc
,pbstrVal
)) );
2094 case( VT_DISPATCH
):
2095 V_UNION(pvargDest
,pdispVal
) = *V_UNION(pvargSrc
,ppdispVal
);
2096 if (V_UNION(pvargDest
,pdispVal
)!=NULL
)
2097 IDispatch_AddRef(V_UNION(pvargDest
,pdispVal
));
2101 /* Prevent from cycling. According to tests on
2102 * VariantCopyInd in Windows and the documentation
2103 * this API dereferences the inner Variants to only one depth.
2104 * If the inner Variant itself contains an
2105 * other inner variant the E_INVALIDARG error is
2108 if( pvargSrc
->n1
.n2
.wReserved1
& PROCESSING_INNER_VARIANT
)
2110 /* If we get here we are attempting to deference
2111 * an inner variant that that is itself contained
2112 * in an inner variant so report E_INVALIDARG error.
2118 /* Set the processing inner variant flag.
2119 * We will set this flag in the inner variant
2120 * that will be passed to the VariantCopyInd function.
2122 (V_UNION(pvargSrc
,pvarVal
))->n1
.n2
.wReserved1
|= PROCESSING_INNER_VARIANT
;
2124 /* Dereference the inner variant.
2126 res
= VariantCopyInd( pvargDest
, V_UNION(pvargSrc
,pvarVal
) );
2127 /* We must also copy its type, I think.
2129 V_VT(pvargSrc
) = V_VT(V_UNION(pvargSrc
,pvarVal
));
2134 V_UNION(pvargDest
,punkVal
) = *V_UNION(pvargSrc
,ppunkVal
);
2135 if (V_UNION(pvargDest
,pdispVal
)!=NULL
)
2136 IUnknown_AddRef(V_UNION(pvargDest
,punkVal
));
2138 case( VT_SAFEARRAY
):
2139 SafeArrayCopy(*V_UNION(pvargSrc
,pparray
), &V_UNION(pvargDest
,parray
));
2142 /* This is a by reference Variant which means that the union
2143 * part of the Variant contains a pointer to some data of
2144 * type "V_VT(pvargSrc) & VT_TYPEMASK".
2145 * We will deference this data in a generic fashion using
2146 * the void pointer "Variant.u.byref".
2147 * We will copy this data into the union of the destination
2150 memcpy( &pvargDest
->n1
.n2
.n3
, V_UNION(pvargSrc
,byref
), SizeOfVariantData( pvargSrc
) );
2155 if (res
== S_OK
) V_VT(pvargDest
) = V_VT(pvargSrc
) & VT_TYPEMASK
;
2159 /* this should not fail.
2161 VariantClear( &varg
);
2165 res
= VariantCopy( pvargDest
, pvargSrc
);
2171 /******************************************************************************
2172 * Coerces a full safearray. Not optimal code.
2176 VARIANTARG
* src
, VARIANTARG
*dst
, LCID lcid
, USHORT wFlags
, VARTYPE vt
2178 SAFEARRAY
*sarr
= V_ARRAY(src
);
2183 SafeArrayGetVartype(sarr
,&vartype
);
2186 if (sarr
->cDims
!= 1) {
2187 FIXME("Can not coerce array with dim %d into BSTR\n", sarr
->cDims
);
2190 switch (V_VT(src
) & VT_TYPEMASK
) {
2192 hres
= SafeArrayAccessData(sarr
, &data
);
2193 if (FAILED(hres
)) return hres
;
2195 /* Yes, just memcpied apparently. */
2196 V_BSTR(dst
) = SysAllocStringByteLen(data
, sarr
->rgsabound
[0].cElements
);
2197 hres
= SafeArrayUnaccessData(sarr
);
2198 if (FAILED(hres
)) return hres
;
2201 FIXME("Cannot coerce array of %d into BSTR yet. Please report!\n", V_VT(src
) & VT_TYPEMASK
);
2206 V_VT(dst
) = VT_SAFEARRAY
;
2207 return SafeArrayCopy(sarr
, &V_ARRAY(dst
));
2209 FIXME("Cannot coerce array of vt 0x%x/0x%x into vt 0x%x yet. Please report/implement!\n", vartype
, V_VT(src
), vt
);
2215 /******************************************************************************
2216 * VariantChangeType [OLEAUT32.12]
2218 HRESULT WINAPI
VariantChangeType(VARIANTARG
* pvargDest
, VARIANTARG
* pvargSrc
,
2219 USHORT wFlags
, VARTYPE vt
)
2221 return VariantChangeTypeEx( pvargDest
, pvargSrc
, 0, wFlags
, vt
);
2224 /******************************************************************************
2225 * VariantChangeTypeEx [OLEAUT32.147]
2227 HRESULT WINAPI
VariantChangeTypeEx(VARIANTARG
* pvargDest
, VARIANTARG
* pvargSrc
,
2228 LCID lcid
, USHORT wFlags
, VARTYPE vt
)
2232 VariantInit( &varg
);
2234 TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest
, pvargSrc
, lcid
, wFlags
, vt
, V_VT(pvargSrc
));
2235 TRACE("Src Var:\n");
2236 dump_Variant(pvargSrc
);
2238 /* validate our source argument.
2240 res
= ValidateVariantType( V_VT(pvargSrc
) );
2242 /* validate the vartype.
2246 res
= ValidateVt( vt
);
2249 /* if we are doing an in-place conversion make a copy of the source.
2251 if( res
== S_OK
&& pvargDest
== pvargSrc
)
2253 res
= VariantCopy( &varg
, pvargSrc
);
2259 /* free up the destination variant.
2261 res
= VariantClear( pvargDest
);
2266 if( V_VT(pvargSrc
) & VT_BYREF
)
2268 /* Convert the source variant to a "byvalue" variant.
2272 if ((V_VT(pvargSrc
) & 0xf000) != VT_BYREF
) {
2273 FIXME("VT_TYPEMASK %x is unhandled.\n",V_VT(pvargSrc
) & VT_TYPEMASK
);
2277 VariantInit( &Variant
);
2278 res
= VariantCopyInd( &Variant
, pvargSrc
);
2281 res
= Coerce( pvargDest
, lcid
, wFlags
, &Variant
, vt
);
2282 /* this should not fail.
2284 VariantClear( &Variant
);
2287 if (V_VT(pvargSrc
) & VT_ARRAY
) {
2288 if ((V_VT(pvargSrc
) & 0xf000) != VT_ARRAY
) {
2289 FIXME("VT_TYPEMASK %x is unhandled in VT_ARRAY.\n",V_VT(pvargSrc
) & VT_TYPEMASK
);
2292 V_VT(pvargDest
) = VT_ARRAY
| vt
;
2293 res
= coerce_array(pvargSrc
, pvargDest
, lcid
, wFlags
, vt
);
2295 if ((V_VT(pvargSrc
) & 0xf000)) {
2296 FIXME("VT_TYPEMASK %x is unhandled in normal case.\n",V_VT(pvargSrc
) & VT_TYPEMASK
);
2299 /* Use the current "byvalue" source variant.
2301 res
= Coerce( pvargDest
, lcid
, wFlags
, pvargSrc
, vt
);
2305 /* this should not fail.
2307 VariantClear( &varg
);
2309 /* set the type of the destination
2312 V_VT(pvargDest
) = vt
;
2314 TRACE("Dest Var:\n");
2315 dump_Variant(pvargDest
);
2323 /******************************************************************************
2324 * VarUI1FromI2 [OLEAUT32.130]
2326 HRESULT WINAPI
VarUI1FromI2(short sIn
, BYTE
* pbOut
)
2328 TRACE("( %d, %p ), stub\n", sIn
, pbOut
);
2330 /* Check range of value.
2332 if( sIn
< UI1_MIN
|| sIn
> UI1_MAX
)
2334 return DISP_E_OVERFLOW
;
2337 *pbOut
= (BYTE
) sIn
;
2342 /******************************************************************************
2343 * VarUI1FromI4 [OLEAUT32.131]
2345 HRESULT WINAPI
VarUI1FromI4(LONG lIn
, BYTE
* pbOut
)
2347 TRACE("( %ld, %p ), stub\n", lIn
, pbOut
);
2349 /* Check range of value.
2351 if( lIn
< UI1_MIN
|| lIn
> UI1_MAX
)
2353 return DISP_E_OVERFLOW
;
2356 *pbOut
= (BYTE
) lIn
;
2362 /******************************************************************************
2363 * VarUI1FromR4 [OLEAUT32.132]
2365 HRESULT WINAPI
VarUI1FromR4(FLOAT fltIn
, BYTE
* pbOut
)
2367 TRACE("( %f, %p ), stub\n", fltIn
, pbOut
);
2369 /* Check range of value.
2371 fltIn
= round( fltIn
);
2372 if( fltIn
< UI1_MIN
|| fltIn
> UI1_MAX
)
2374 return DISP_E_OVERFLOW
;
2377 *pbOut
= (BYTE
) fltIn
;
2382 /******************************************************************************
2383 * VarUI1FromR8 [OLEAUT32.133]
2385 HRESULT WINAPI
VarUI1FromR8(double dblIn
, BYTE
* pbOut
)
2387 TRACE("( %f, %p ), stub\n", dblIn
, pbOut
);
2389 /* Check range of value.
2391 dblIn
= round( dblIn
);
2392 if( dblIn
< UI1_MIN
|| dblIn
> UI1_MAX
)
2394 return DISP_E_OVERFLOW
;
2397 *pbOut
= (BYTE
) dblIn
;
2402 /******************************************************************************
2403 * VarUI1FromDate [OLEAUT32.135]
2405 HRESULT WINAPI
VarUI1FromDate(DATE dateIn
, BYTE
* pbOut
)
2407 TRACE("( %f, %p ), stub\n", dateIn
, pbOut
);
2409 /* Check range of value.
2411 dateIn
= round( dateIn
);
2412 if( dateIn
< UI1_MIN
|| dateIn
> UI1_MAX
)
2414 return DISP_E_OVERFLOW
;
2417 *pbOut
= (BYTE
) dateIn
;
2422 /******************************************************************************
2423 * VarUI1FromBool [OLEAUT32.138]
2425 HRESULT WINAPI
VarUI1FromBool(VARIANT_BOOL boolIn
, BYTE
* pbOut
)
2427 TRACE("( %d, %p ), stub\n", boolIn
, pbOut
);
2429 *pbOut
= (BYTE
) boolIn
;
2434 /******************************************************************************
2435 * VarUI1FromI1 [OLEAUT32.237]
2437 HRESULT WINAPI
VarUI1FromI1(signed char cIn
, BYTE
* pbOut
)
2439 TRACE("( %c, %p ), stub\n", cIn
, pbOut
);
2446 /******************************************************************************
2447 * VarUI1FromUI2 [OLEAUT32.238]
2449 HRESULT WINAPI
VarUI1FromUI2(USHORT uiIn
, BYTE
* pbOut
)
2451 TRACE("( %d, %p ), stub\n", uiIn
, pbOut
);
2453 /* Check range of value.
2455 if( uiIn
> UI1_MAX
)
2457 return DISP_E_OVERFLOW
;
2460 *pbOut
= (BYTE
) uiIn
;
2465 /******************************************************************************
2466 * VarUI1FromUI4 [OLEAUT32.239]
2468 HRESULT WINAPI
VarUI1FromUI4(ULONG ulIn
, BYTE
* pbOut
)
2470 TRACE("( %ld, %p ), stub\n", ulIn
, pbOut
);
2472 /* Check range of value.
2474 if( ulIn
> UI1_MAX
)
2476 return DISP_E_OVERFLOW
;
2479 *pbOut
= (BYTE
) ulIn
;
2485 /******************************************************************************
2486 * VarUI1FromStr [OLEAUT32.136]
2488 HRESULT WINAPI
VarUI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, BYTE
* pbOut
)
2490 double dValue
= 0.0;
2491 LPSTR pNewString
= NULL
;
2493 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn
, lcid
, dwFlags
, pbOut
);
2495 /* Check if we have a valid argument
2497 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
2498 RemoveCharacterFromString( pNewString
, "," );
2499 if( IsValidRealString( pNewString
) == FALSE
)
2501 return DISP_E_TYPEMISMATCH
;
2504 /* Convert the valid string to a floating point number.
2506 dValue
= atof( pNewString
);
2508 /* We don't need the string anymore so free it.
2510 HeapFree( GetProcessHeap(), 0 , pNewString
);
2512 /* Check range of value.
2514 dValue
= round( dValue
);
2515 if( dValue
< UI1_MIN
|| dValue
> UI1_MAX
)
2517 return DISP_E_OVERFLOW
;
2520 *pbOut
= (BYTE
) dValue
;
2525 /**********************************************************************
2526 * VarUI1FromCy [OLEAUT32.134]
2527 * Convert currency to unsigned char
2529 HRESULT WINAPI
VarUI1FromCy(CY cyIn
, BYTE
* pbOut
) {
2530 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
2532 if (t
> UI1_MAX
|| t
< UI1_MIN
) return DISP_E_OVERFLOW
;
2538 /******************************************************************************
2539 * VarI2FromUI1 [OLEAUT32.48]
2541 HRESULT WINAPI
VarI2FromUI1(BYTE bIn
, short* psOut
)
2543 TRACE("( 0x%08x, %p ), stub\n", bIn
, psOut
);
2545 *psOut
= (short) bIn
;
2550 /******************************************************************************
2551 * VarI2FromI4 [OLEAUT32.49]
2553 HRESULT WINAPI
VarI2FromI4(LONG lIn
, short* psOut
)
2555 TRACE("( %lx, %p ), stub\n", lIn
, psOut
);
2557 /* Check range of value.
2559 if( lIn
< I2_MIN
|| lIn
> I2_MAX
)
2561 return DISP_E_OVERFLOW
;
2564 *psOut
= (short) lIn
;
2569 /******************************************************************************
2570 * VarI2FromR4 [OLEAUT32.50]
2572 HRESULT WINAPI
VarI2FromR4(FLOAT fltIn
, short* psOut
)
2574 TRACE("( %f, %p ), stub\n", fltIn
, psOut
);
2576 /* Check range of value.
2578 fltIn
= round( fltIn
);
2579 if( fltIn
< I2_MIN
|| fltIn
> I2_MAX
)
2581 return DISP_E_OVERFLOW
;
2584 *psOut
= (short) fltIn
;
2589 /******************************************************************************
2590 * VarI2FromR8 [OLEAUT32.51]
2592 HRESULT WINAPI
VarI2FromR8(double dblIn
, short* psOut
)
2594 TRACE("( %f, %p ), stub\n", dblIn
, psOut
);
2596 /* Check range of value.
2598 dblIn
= round( dblIn
);
2599 if( dblIn
< I2_MIN
|| dblIn
> I2_MAX
)
2601 return DISP_E_OVERFLOW
;
2604 *psOut
= (short) dblIn
;
2609 /******************************************************************************
2610 * VarI2FromDate [OLEAUT32.53]
2612 HRESULT WINAPI
VarI2FromDate(DATE dateIn
, short* psOut
)
2614 TRACE("( %f, %p ), stub\n", dateIn
, psOut
);
2616 /* Check range of value.
2618 dateIn
= round( dateIn
);
2619 if( dateIn
< I2_MIN
|| dateIn
> I2_MAX
)
2621 return DISP_E_OVERFLOW
;
2624 *psOut
= (short) dateIn
;
2629 /******************************************************************************
2630 * VarI2FromBool [OLEAUT32.56]
2632 HRESULT WINAPI
VarI2FromBool(VARIANT_BOOL boolIn
, short* psOut
)
2634 TRACE("( %d, %p ), stub\n", boolIn
, psOut
);
2636 *psOut
= (short) boolIn
;
2641 /******************************************************************************
2642 * VarI2FromI1 [OLEAUT32.205]
2644 HRESULT WINAPI
VarI2FromI1(signed char cIn
, short* psOut
)
2646 TRACE("( %c, %p ), stub\n", cIn
, psOut
);
2648 *psOut
= (short) cIn
;
2653 /******************************************************************************
2654 * VarI2FromUI2 [OLEAUT32.206]
2656 HRESULT WINAPI
VarI2FromUI2(USHORT uiIn
, short* psOut
)
2658 TRACE("( %d, %p ), stub\n", uiIn
, psOut
);
2660 /* Check range of value.
2664 return DISP_E_OVERFLOW
;
2667 *psOut
= (short) uiIn
;
2672 /******************************************************************************
2673 * VarI2FromUI4 [OLEAUT32.207]
2675 HRESULT WINAPI
VarI2FromUI4(ULONG ulIn
, short* psOut
)
2677 TRACE("( %lx, %p ), stub\n", ulIn
, psOut
);
2679 /* Check range of value.
2681 if( ulIn
< I2_MIN
|| ulIn
> I2_MAX
)
2683 return DISP_E_OVERFLOW
;
2686 *psOut
= (short) ulIn
;
2691 /******************************************************************************
2692 * VarI2FromStr [OLEAUT32.54]
2694 HRESULT WINAPI
VarI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, short* psOut
)
2696 double dValue
= 0.0;
2697 LPSTR pNewString
= NULL
;
2699 TRACE("( %s, 0x%08lx, 0x%08lx, %p ), stub\n", debugstr_w(strIn
), lcid
, dwFlags
, psOut
);
2701 /* Check if we have a valid argument
2703 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
2704 RemoveCharacterFromString( pNewString
, "," );
2705 if( IsValidRealString( pNewString
) == FALSE
)
2707 return DISP_E_TYPEMISMATCH
;
2710 /* Convert the valid string to a floating point number.
2712 dValue
= atof( pNewString
);
2714 /* We don't need the string anymore so free it.
2716 HeapFree( GetProcessHeap(), 0, pNewString
);
2718 /* Check range of value.
2720 dValue
= round( dValue
);
2721 if( dValue
< I2_MIN
|| dValue
> I2_MAX
)
2723 return DISP_E_OVERFLOW
;
2726 *psOut
= (short) dValue
;
2731 /**********************************************************************
2732 * VarI2FromCy [OLEAUT32.52]
2733 * Convert currency to signed short
2735 HRESULT WINAPI
VarI2FromCy(CY cyIn
, short* psOut
) {
2736 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
2738 if (t
> I2_MAX
|| t
< I2_MIN
) return DISP_E_OVERFLOW
;
2744 /******************************************************************************
2745 * VarI4FromUI1 [OLEAUT32.58]
2747 HRESULT WINAPI
VarI4FromUI1(BYTE bIn
, LONG
* plOut
)
2749 TRACE("( %X, %p ), stub\n", bIn
, plOut
);
2751 *plOut
= (LONG
) bIn
;
2757 /******************************************************************************
2758 * VarI4FromR4 [OLEAUT32.60]
2760 HRESULT WINAPI
VarI4FromR4(FLOAT fltIn
, LONG
* plOut
)
2762 TRACE("( %f, %p ), stub\n", fltIn
, plOut
);
2764 /* Check range of value.
2766 fltIn
= round( fltIn
);
2767 if( fltIn
< I4_MIN
|| fltIn
> I4_MAX
)
2769 return DISP_E_OVERFLOW
;
2772 *plOut
= (LONG
) fltIn
;
2777 /******************************************************************************
2778 * VarI4FromR8 [OLEAUT32.61]
2780 HRESULT WINAPI
VarI4FromR8(double dblIn
, LONG
* plOut
)
2782 TRACE("( %f, %p ), stub\n", dblIn
, plOut
);
2784 /* Check range of value.
2786 dblIn
= round( dblIn
);
2787 if( dblIn
< I4_MIN
|| dblIn
> I4_MAX
)
2789 return DISP_E_OVERFLOW
;
2792 *plOut
= (LONG
) dblIn
;
2797 /******************************************************************************
2798 * VarI4FromDate [OLEAUT32.63]
2800 HRESULT WINAPI
VarI4FromDate(DATE dateIn
, LONG
* plOut
)
2802 TRACE("( %f, %p ), stub\n", dateIn
, plOut
);
2804 /* Check range of value.
2806 dateIn
= round( dateIn
);
2807 if( dateIn
< I4_MIN
|| dateIn
> I4_MAX
)
2809 return DISP_E_OVERFLOW
;
2812 *plOut
= (LONG
) dateIn
;
2817 /******************************************************************************
2818 * VarI4FromBool [OLEAUT32.66]
2820 HRESULT WINAPI
VarI4FromBool(VARIANT_BOOL boolIn
, LONG
* plOut
)
2822 TRACE("( %d, %p ), stub\n", boolIn
, plOut
);
2824 *plOut
= (LONG
) boolIn
;
2829 /******************************************************************************
2830 * VarI4FromI1 [OLEAUT32.209]
2832 HRESULT WINAPI
VarI4FromI1(signed char cIn
, LONG
* plOut
)
2834 TRACE("( %c, %p ), stub\n", cIn
, plOut
);
2836 *plOut
= (LONG
) cIn
;
2841 /******************************************************************************
2842 * VarI4FromUI2 [OLEAUT32.210]
2844 HRESULT WINAPI
VarI4FromUI2(USHORT uiIn
, LONG
* plOut
)
2846 TRACE("( %d, %p ), stub\n", uiIn
, plOut
);
2848 *plOut
= (LONG
) uiIn
;
2853 /******************************************************************************
2854 * VarI4FromUI4 [OLEAUT32.211]
2856 HRESULT WINAPI
VarI4FromUI4(ULONG ulIn
, LONG
* plOut
)
2858 TRACE("( %lx, %p ), stub\n", ulIn
, plOut
);
2860 /* Check range of value.
2862 if( ulIn
< I4_MIN
|| ulIn
> I4_MAX
)
2864 return DISP_E_OVERFLOW
;
2867 *plOut
= (LONG
) ulIn
;
2872 /******************************************************************************
2873 * VarI4FromI2 [OLEAUT32.59]
2875 HRESULT WINAPI
VarI4FromI2(short sIn
, LONG
* plOut
)
2877 TRACE("( %d, %p ), stub\n", sIn
, plOut
);
2879 *plOut
= (LONG
) sIn
;
2884 /******************************************************************************
2885 * VarI4FromStr [OLEAUT32.64]
2887 HRESULT WINAPI
VarI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, LONG
* plOut
)
2889 double dValue
= 0.0;
2890 LPSTR pNewString
= NULL
;
2892 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn
, lcid
, dwFlags
, plOut
);
2894 /* Check if we have a valid argument
2896 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
2897 RemoveCharacterFromString( pNewString
, "," );
2898 if( IsValidRealString( pNewString
) == FALSE
)
2900 return DISP_E_TYPEMISMATCH
;
2903 /* Convert the valid string to a floating point number.
2905 dValue
= atof( pNewString
);
2907 /* We don't need the string anymore so free it.
2909 HeapFree( GetProcessHeap(), 0, pNewString
);
2911 /* Check range of value.
2913 dValue
= round( dValue
);
2914 if( dValue
< I4_MIN
|| dValue
> I4_MAX
)
2916 return DISP_E_OVERFLOW
;
2919 *plOut
= (LONG
) dValue
;
2924 /**********************************************************************
2925 * VarI4FromCy [OLEAUT32.62]
2926 * Convert currency to signed long
2928 HRESULT WINAPI
VarI4FromCy(CY cyIn
, LONG
* plOut
) {
2929 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
2931 if (t
> I4_MAX
|| t
< I4_MIN
) return DISP_E_OVERFLOW
;
2937 /******************************************************************************
2938 * VarR4FromUI1 [OLEAUT32.68]
2940 HRESULT WINAPI
VarR4FromUI1(BYTE bIn
, FLOAT
* pfltOut
)
2942 TRACE("( %X, %p ), stub\n", bIn
, pfltOut
);
2944 *pfltOut
= (FLOAT
) bIn
;
2949 /******************************************************************************
2950 * VarR4FromI2 [OLEAUT32.69]
2952 HRESULT WINAPI
VarR4FromI2(short sIn
, FLOAT
* pfltOut
)
2954 TRACE("( %d, %p ), stub\n", sIn
, pfltOut
);
2956 *pfltOut
= (FLOAT
) sIn
;
2961 /******************************************************************************
2962 * VarR4FromI4 [OLEAUT32.70]
2964 HRESULT WINAPI
VarR4FromI4(LONG lIn
, FLOAT
* pfltOut
)
2966 TRACE("( %lx, %p ), stub\n", lIn
, pfltOut
);
2968 *pfltOut
= (FLOAT
) lIn
;
2973 /******************************************************************************
2974 * VarR4FromR8 [OLEAUT32.71]
2976 HRESULT WINAPI
VarR4FromR8(double dblIn
, FLOAT
* pfltOut
)
2978 TRACE("( %f, %p ), stub\n", dblIn
, pfltOut
);
2980 /* Check range of value.
2982 if( dblIn
< -(FLT_MAX
) || dblIn
> FLT_MAX
)
2984 return DISP_E_OVERFLOW
;
2987 *pfltOut
= (FLOAT
) dblIn
;
2992 /******************************************************************************
2993 * VarR4FromDate [OLEAUT32.73]
2995 HRESULT WINAPI
VarR4FromDate(DATE dateIn
, FLOAT
* pfltOut
)
2997 TRACE("( %f, %p ), stub\n", dateIn
, pfltOut
);
2999 /* Check range of value.
3001 if( dateIn
< -(FLT_MAX
) || dateIn
> FLT_MAX
)
3003 return DISP_E_OVERFLOW
;
3006 *pfltOut
= (FLOAT
) dateIn
;
3011 /******************************************************************************
3012 * VarR4FromBool [OLEAUT32.76]
3014 HRESULT WINAPI
VarR4FromBool(VARIANT_BOOL boolIn
, FLOAT
* pfltOut
)
3016 TRACE("( %d, %p ), stub\n", boolIn
, pfltOut
);
3018 *pfltOut
= (FLOAT
) boolIn
;
3023 /******************************************************************************
3024 * VarR4FromI1 [OLEAUT32.213]
3026 HRESULT WINAPI
VarR4FromI1(signed char cIn
, FLOAT
* pfltOut
)
3028 TRACE("( %c, %p ), stub\n", cIn
, pfltOut
);
3030 *pfltOut
= (FLOAT
) cIn
;
3035 /******************************************************************************
3036 * VarR4FromUI2 [OLEAUT32.214]
3038 HRESULT WINAPI
VarR4FromUI2(USHORT uiIn
, FLOAT
* pfltOut
)
3040 TRACE("( %d, %p ), stub\n", uiIn
, pfltOut
);
3042 *pfltOut
= (FLOAT
) uiIn
;
3047 /******************************************************************************
3048 * VarR4FromUI4 [OLEAUT32.215]
3050 HRESULT WINAPI
VarR4FromUI4(ULONG ulIn
, FLOAT
* pfltOut
)
3052 TRACE("( %ld, %p ), stub\n", ulIn
, pfltOut
);
3054 *pfltOut
= (FLOAT
) ulIn
;
3059 /******************************************************************************
3060 * VarR4FromStr [OLEAUT32.74]
3062 HRESULT WINAPI
VarR4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, FLOAT
* pfltOut
)
3064 double dValue
= 0.0;
3065 LPSTR pNewString
= NULL
;
3067 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, pfltOut
);
3069 /* Check if we have a valid argument
3071 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
3072 RemoveCharacterFromString( pNewString
, "," );
3073 if( IsValidRealString( pNewString
) == FALSE
)
3075 return DISP_E_TYPEMISMATCH
;
3078 /* Convert the valid string to a floating point number.
3080 dValue
= atof( pNewString
);
3082 /* We don't need the string anymore so free it.
3084 HeapFree( GetProcessHeap(), 0, pNewString
);
3086 /* Check range of value.
3088 if( dValue
< -(FLT_MAX
) || dValue
> FLT_MAX
)
3090 return DISP_E_OVERFLOW
;
3093 *pfltOut
= (FLOAT
) dValue
;
3098 /**********************************************************************
3099 * VarR4FromCy [OLEAUT32.72]
3100 * Convert currency to float
3102 HRESULT WINAPI
VarR4FromCy(CY cyIn
, FLOAT
* pfltOut
) {
3103 *pfltOut
= (FLOAT
)((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
3108 /******************************************************************************
3109 * VarR8FromUI1 [OLEAUT32.78]
3111 HRESULT WINAPI
VarR8FromUI1(BYTE bIn
, double* pdblOut
)
3113 TRACE("( %d, %p ), stub\n", bIn
, pdblOut
);
3115 *pdblOut
= (double) bIn
;
3120 /******************************************************************************
3121 * VarR8FromI2 [OLEAUT32.79]
3123 HRESULT WINAPI
VarR8FromI2(short sIn
, double* pdblOut
)
3125 TRACE("( %d, %p ), stub\n", sIn
, pdblOut
);
3127 *pdblOut
= (double) sIn
;
3132 /******************************************************************************
3133 * VarR8FromI4 [OLEAUT32.80]
3135 HRESULT WINAPI
VarR8FromI4(LONG lIn
, double* pdblOut
)
3137 TRACE("( %ld, %p ), stub\n", lIn
, pdblOut
);
3139 *pdblOut
= (double) lIn
;
3144 /******************************************************************************
3145 * VarR8FromR4 [OLEAUT32.81]
3147 HRESULT WINAPI
VarR8FromR4(FLOAT fltIn
, double* pdblOut
)
3149 TRACE("( %f, %p ), stub\n", fltIn
, pdblOut
);
3151 *pdblOut
= (double) fltIn
;
3156 /******************************************************************************
3157 * VarR8FromDate [OLEAUT32.83]
3159 HRESULT WINAPI
VarR8FromDate(DATE dateIn
, double* pdblOut
)
3161 TRACE("( %f, %p ), stub\n", dateIn
, pdblOut
);
3163 *pdblOut
= (double) dateIn
;
3168 /******************************************************************************
3169 * VarR8FromBool [OLEAUT32.86]
3171 HRESULT WINAPI
VarR8FromBool(VARIANT_BOOL boolIn
, double* pdblOut
)
3173 TRACE("( %d, %p ), stub\n", boolIn
, pdblOut
);
3175 *pdblOut
= (double) boolIn
;
3180 /******************************************************************************
3181 * VarR8FromI1 [OLEAUT32.217]
3183 HRESULT WINAPI
VarR8FromI1(signed char cIn
, double* pdblOut
)
3185 TRACE("( %c, %p ), stub\n", cIn
, pdblOut
);
3187 *pdblOut
= (double) cIn
;
3192 /******************************************************************************
3193 * VarR8FromUI2 [OLEAUT32.218]
3195 HRESULT WINAPI
VarR8FromUI2(USHORT uiIn
, double* pdblOut
)
3197 TRACE("( %d, %p ), stub\n", uiIn
, pdblOut
);
3199 *pdblOut
= (double) uiIn
;
3204 /******************************************************************************
3205 * VarR8FromUI4 [OLEAUT32.219]
3207 HRESULT WINAPI
VarR8FromUI4(ULONG ulIn
, double* pdblOut
)
3209 TRACE("( %ld, %p ), stub\n", ulIn
, pdblOut
);
3211 *pdblOut
= (double) ulIn
;
3216 /******************************************************************************
3217 * VarR8FromStr [OLEAUT32.84]
3219 HRESULT WINAPI
VarR8FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, double* pdblOut
)
3221 double dValue
= 0.0;
3222 LPSTR pNewString
= NULL
;
3224 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
3225 TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString
, lcid
, dwFlags
, pdblOut
);
3227 /* Check if we have a valid argument
3229 RemoveCharacterFromString( pNewString
, "," );
3230 if( IsValidRealString( pNewString
) == FALSE
)
3232 return DISP_E_TYPEMISMATCH
;
3235 /* Convert the valid string to a floating point number.
3237 dValue
= atof( pNewString
);
3239 /* We don't need the string anymore so free it.
3241 HeapFree( GetProcessHeap(), 0, pNewString
);
3248 /**********************************************************************
3249 * VarR8FromCy [OLEAUT32.82]
3250 * Convert currency to double
3252 HRESULT WINAPI
VarR8FromCy(CY cyIn
, double* pdblOut
) {
3253 *pdblOut
= (double)((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
3254 TRACE("%lu %ld -> %f\n", cyIn
.s
.Hi
, cyIn
.s
.Lo
, *pdblOut
);
3258 /******************************************************************************
3259 * VarDateFromUI1 [OLEAUT32.88]
3261 HRESULT WINAPI
VarDateFromUI1(BYTE bIn
, DATE
* pdateOut
)
3263 TRACE("( %d, %p ), stub\n", bIn
, pdateOut
);
3265 *pdateOut
= (DATE
) bIn
;
3270 /******************************************************************************
3271 * VarDateFromI2 [OLEAUT32.89]
3273 HRESULT WINAPI
VarDateFromI2(short sIn
, DATE
* pdateOut
)
3275 TRACE("( %d, %p ), stub\n", sIn
, pdateOut
);
3277 *pdateOut
= (DATE
) sIn
;
3282 /******************************************************************************
3283 * VarDateFromI4 [OLEAUT32.90]
3285 HRESULT WINAPI
VarDateFromI4(LONG lIn
, DATE
* pdateOut
)
3287 TRACE("( %ld, %p ), stub\n", lIn
, pdateOut
);
3289 if( lIn
< DATE_MIN
|| lIn
> DATE_MAX
)
3291 return DISP_E_OVERFLOW
;
3294 *pdateOut
= (DATE
) lIn
;
3299 /******************************************************************************
3300 * VarDateFromR4 [OLEAUT32.91]
3302 HRESULT WINAPI
VarDateFromR4(FLOAT fltIn
, DATE
* pdateOut
)
3304 TRACE("( %f, %p ), stub\n", fltIn
, pdateOut
);
3306 if( ceil(fltIn
) < DATE_MIN
|| floor(fltIn
) > DATE_MAX
)
3308 return DISP_E_OVERFLOW
;
3311 *pdateOut
= (DATE
) fltIn
;
3316 /******************************************************************************
3317 * VarDateFromR8 [OLEAUT32.92]
3319 HRESULT WINAPI
VarDateFromR8(double dblIn
, DATE
* pdateOut
)
3321 TRACE("( %f, %p ), stub\n", dblIn
, pdateOut
);
3323 if( ceil(dblIn
) < DATE_MIN
|| floor(dblIn
) > DATE_MAX
)
3325 return DISP_E_OVERFLOW
;
3328 *pdateOut
= (DATE
) dblIn
;
3333 /******************************************************************************
3334 * VarDateFromStr [OLEAUT32.94]
3335 * The string representing the date is composed of two parts, a date and time.
3337 * The format of the time is has follows:
3338 * hh[:mm][:ss][AM|PM]
3339 * Whitespace can be inserted anywhere between these tokens. A whitespace consists
3340 * of space and/or tab characters, which are ignored.
3342 * The formats for the date part are has follows:
3346 * January dd[,] [yy]yy
3349 * Whitespace can be inserted anywhere between these tokens.
3351 * The formats for the date and time string are has follows.
3352 * date[whitespace][time]
3353 * [time][whitespace]date
3355 * These are the only characters allowed in a string representing a date and time:
3356 * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3358 HRESULT WINAPI
VarDateFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, DATE
* pdateOut
)
3363 memset( &TM
, 0, sizeof(TM
) );
3365 TRACE("( %p, %lx, %lx, %p ), stub\n", strIn
, lcid
, dwFlags
, pdateOut
);
3367 if( DateTimeStringToTm( strIn
, dwFlags
, &TM
) )
3369 if( TmToDATE( &TM
, pdateOut
) == FALSE
)
3376 ret
= DISP_E_TYPEMISMATCH
;
3378 TRACE("Return value %f\n", *pdateOut
);
3382 /******************************************************************************
3383 * VarDateFromI1 [OLEAUT32.221]
3385 HRESULT WINAPI
VarDateFromI1(signed char cIn
, DATE
* pdateOut
)
3387 TRACE("( %c, %p ), stub\n", cIn
, pdateOut
);
3389 *pdateOut
= (DATE
) cIn
;
3394 /******************************************************************************
3395 * VarDateFromUI2 [OLEAUT32.222]
3397 HRESULT WINAPI
VarDateFromUI2(USHORT uiIn
, DATE
* pdateOut
)
3399 TRACE("( %d, %p ), stub\n", uiIn
, pdateOut
);
3401 if( uiIn
> DATE_MAX
)
3403 return DISP_E_OVERFLOW
;
3406 *pdateOut
= (DATE
) uiIn
;
3411 /******************************************************************************
3412 * VarDateFromUI4 [OLEAUT32.223]
3414 HRESULT WINAPI
VarDateFromUI4(ULONG ulIn
, DATE
* pdateOut
)
3416 TRACE("( %ld, %p ), stub\n", ulIn
, pdateOut
);
3418 if( ulIn
< DATE_MIN
|| ulIn
> DATE_MAX
)
3420 return DISP_E_OVERFLOW
;
3423 *pdateOut
= (DATE
) ulIn
;
3428 /******************************************************************************
3429 * VarDateFromBool [OLEAUT32.96]
3431 HRESULT WINAPI
VarDateFromBool(VARIANT_BOOL boolIn
, DATE
* pdateOut
)
3433 TRACE("( %d, %p ), stub\n", boolIn
, pdateOut
);
3435 *pdateOut
= (DATE
) boolIn
;
3440 /**********************************************************************
3441 * VarDateFromCy [OLEAUT32.93]
3442 * Convert currency to date
3444 HRESULT WINAPI
VarDateFromCy(CY cyIn
, DATE
* pdateOut
) {
3445 *pdateOut
= (DATE
)((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
3447 if (*pdateOut
> DATE_MAX
|| *pdateOut
< DATE_MIN
) return DISP_E_TYPEMISMATCH
;
3451 /******************************************************************************
3452 * VarBstrFromUI1 [OLEAUT32.108]
3454 HRESULT WINAPI
VarBstrFromUI1(BYTE bVal
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3456 TRACE("( %d, %ld, %ld, %p ), stub\n", bVal
, lcid
, dwFlags
, pbstrOut
);
3457 sprintf( pBuffer
, "%d", bVal
);
3459 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3464 /******************************************************************************
3465 * VarBstrFromI2 [OLEAUT32.109]
3467 HRESULT WINAPI
VarBstrFromI2(short iVal
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3469 TRACE("( %d, %ld, %ld, %p ), stub\n", iVal
, lcid
, dwFlags
, pbstrOut
);
3470 sprintf( pBuffer
, "%d", iVal
);
3471 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3476 /******************************************************************************
3477 * VarBstrFromI4 [OLEAUT32.110]
3479 HRESULT WINAPI
VarBstrFromI4(LONG lIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3481 TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn
, lcid
, dwFlags
, pbstrOut
);
3483 sprintf( pBuffer
, "%ld", lIn
);
3484 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3489 /******************************************************************************
3490 * VarBstrFromR4 [OLEAUT32.111]
3492 HRESULT WINAPI
VarBstrFromR4(FLOAT fltIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3494 TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn
, lcid
, dwFlags
, pbstrOut
);
3496 sprintf( pBuffer
, "%.7G", fltIn
);
3497 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3502 /******************************************************************************
3503 * VarBstrFromR8 [OLEAUT32.112]
3505 HRESULT WINAPI
VarBstrFromR8(double dblIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3507 TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn
, lcid
, dwFlags
, pbstrOut
);
3509 sprintf( pBuffer
, "%.15G", dblIn
);
3510 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3515 /******************************************************************************
3516 * VarBstrFromCy [OLEAUT32.113]
3518 HRESULT WINAPI
VarBstrFromCy(CY cyIn
, LCID lcid
, ULONG dwFlags
, BSTR
*pbstrOut
) {
3520 double curVal
= 0.0;
3522 TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid
, dwFlags
, pbstrOut
);
3524 /* Firstly get the currency in a double, then put it in a buffer */
3525 rc
= VarR8FromCy(cyIn
, &curVal
);
3527 sprintf(pBuffer
, "%G", curVal
);
3528 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3534 /******************************************************************************
3535 * VarBstrFromDate [OLEAUT32.114]
3537 * The date is implemented using an 8 byte floating-point number.
3538 * Days are represented by whole numbers increments starting with 0.00 as
3539 * being December 30 1899, midnight.
3540 * The hours are expressed as the fractional part of the number.
3541 * December 30 1899 at midnight = 0.00
3542 * January 1 1900 at midnight = 2.00
3543 * January 4 1900 at 6 AM = 5.25
3544 * January 4 1900 at noon = 5.50
3545 * December 29 1899 at midnight = -1.00
3546 * December 18 1899 at midnight = -12.00
3547 * December 18 1899 at 6AM = -12.25
3548 * December 18 1899 at 6PM = -12.75
3549 * December 19 1899 at midnight = -11.00
3550 * The tm structure is as follows:
3552 * int tm_sec; seconds after the minute - [0,59]
3553 * int tm_min; minutes after the hour - [0,59]
3554 * int tm_hour; hours since midnight - [0,23]
3555 * int tm_mday; day of the month - [1,31]
3556 * int tm_mon; months since January - [0,11]
3557 * int tm_year; years
3558 * int tm_wday; days since Sunday - [0,6]
3559 * int tm_yday; days since January 1 - [0,365]
3560 * int tm_isdst; daylight savings time flag
3563 HRESULT WINAPI
VarBstrFromDate(DATE dateIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3566 memset( &TM
, 0, sizeof(TM
) );
3568 TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn
, lcid
, dwFlags
, pbstrOut
);
3570 if( DateToTm( dateIn
, dwFlags
, &TM
) == FALSE
)
3572 return E_INVALIDARG
;
3575 if( dwFlags
& VAR_DATEVALUEONLY
)
3576 strftime( pBuffer
, BUFFER_MAX
, "%x", &TM
);
3577 else if( dwFlags
& VAR_TIMEVALUEONLY
)
3578 strftime( pBuffer
, BUFFER_MAX
, "%X", &TM
);
3580 strftime( pBuffer
, BUFFER_MAX
, "%x %X", &TM
);
3582 TRACE("result: %s\n", pBuffer
);
3583 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3587 /******************************************************************************
3588 * VarBstrFromBool [OLEAUT32.116]
3590 HRESULT WINAPI
VarBstrFromBool(VARIANT_BOOL boolIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3592 TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn
, lcid
, dwFlags
, pbstrOut
);
3594 sprintf( pBuffer
, (boolIn
== VARIANT_FALSE
) ? "False" : "True" );
3596 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3601 /******************************************************************************
3602 * VarBstrFromI1 [OLEAUT32.229]
3604 HRESULT WINAPI
VarBstrFromI1(signed char cIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3606 TRACE("( %c, %ld, %ld, %p ), stub\n", cIn
, lcid
, dwFlags
, pbstrOut
);
3607 sprintf( pBuffer
, "%d", cIn
);
3608 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3613 /******************************************************************************
3614 * VarBstrFromUI2 [OLEAUT32.230]
3616 HRESULT WINAPI
VarBstrFromUI2(USHORT uiIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3618 TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn
, lcid
, dwFlags
, pbstrOut
);
3619 sprintf( pBuffer
, "%d", uiIn
);
3620 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3625 /******************************************************************************
3626 * VarBstrFromUI4 [OLEAUT32.231]
3628 HRESULT WINAPI
VarBstrFromUI4(ULONG ulIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3630 TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn
, lcid
, dwFlags
, pbstrOut
);
3631 sprintf( pBuffer
, "%ld", ulIn
);
3632 *pbstrOut
= StringDupAtoBstr( pBuffer
);
3637 /******************************************************************************
3638 * VarBstrFromDec [OLEAUT32.@]
3640 HRESULT WINAPI
VarBstrFromDec(DECIMAL
* pDecIn
, LCID lcid
, ULONG dwFlags
, BSTR
* pbstrOut
)
3642 if(!pDecIn
->u
.s
.sign
&& !pDecIn
->u
.s
.scale
&&
3643 !pDecIn
->Hi32
&& !pDecIn
->u1
.s1
.Mid32
)
3644 return VarBstrFromUI4(pDecIn
->u1
.s1
.Lo32
, lcid
, dwFlags
, pbstrOut
);
3645 FIXME("%c%08lx%08lx%08lx E%02x stub\n",
3646 (pDecIn
->u
.s
.sign
== DECIMAL_NEG
) ? '-' :
3647 (pDecIn
->u
.s
.sign
== 0) ? '+' : '?',
3648 pDecIn
->Hi32
, pDecIn
->u1
.s1
.Mid32
, pDecIn
->u1
.s1
.Lo32
,
3650 return E_INVALIDARG
;
3653 /******************************************************************************
3654 * VarBoolFromUI1 [OLEAUT32.118]
3656 HRESULT WINAPI
VarBoolFromUI1(BYTE bIn
, VARIANT_BOOL
* pboolOut
)
3658 TRACE("( %d, %p ), stub\n", bIn
, pboolOut
);
3662 *pboolOut
= VARIANT_FALSE
;
3666 *pboolOut
= VARIANT_TRUE
;
3672 /******************************************************************************
3673 * VarBoolFromI2 [OLEAUT32.119]
3675 HRESULT WINAPI
VarBoolFromI2(short sIn
, VARIANT_BOOL
* pboolOut
)
3677 TRACE("( %d, %p ), stub\n", sIn
, pboolOut
);
3679 *pboolOut
= (sIn
) ? VARIANT_TRUE
: VARIANT_FALSE
;
3684 /******************************************************************************
3685 * VarBoolFromI4 [OLEAUT32.120]
3687 HRESULT WINAPI
VarBoolFromI4(LONG lIn
, VARIANT_BOOL
* pboolOut
)
3689 TRACE("( %ld, %p ), stub\n", lIn
, pboolOut
);
3691 *pboolOut
= (lIn
) ? VARIANT_TRUE
: VARIANT_FALSE
;
3696 /******************************************************************************
3697 * VarBoolFromR4 [OLEAUT32.121]
3699 HRESULT WINAPI
VarBoolFromR4(FLOAT fltIn
, VARIANT_BOOL
* pboolOut
)
3701 TRACE("( %f, %p ), stub\n", fltIn
, pboolOut
);
3703 *pboolOut
= (fltIn
== 0.0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3708 /******************************************************************************
3709 * VarBoolFromR8 [OLEAUT32.122]
3711 HRESULT WINAPI
VarBoolFromR8(double dblIn
, VARIANT_BOOL
* pboolOut
)
3713 TRACE("( %f, %p ), stub\n", dblIn
, pboolOut
);
3715 *pboolOut
= (dblIn
== 0.0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3720 /******************************************************************************
3721 * VarBoolFromDate [OLEAUT32.123]
3723 HRESULT WINAPI
VarBoolFromDate(DATE dateIn
, VARIANT_BOOL
* pboolOut
)
3725 TRACE("( %f, %p ), stub\n", dateIn
, pboolOut
);
3727 *pboolOut
= (dateIn
== 0.0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3732 /******************************************************************************
3733 * VarBoolFromStr [OLEAUT32.125]
3735 HRESULT WINAPI
VarBoolFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, VARIANT_BOOL
* pboolOut
)
3738 char* pNewString
= NULL
;
3740 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, pboolOut
);
3742 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
3744 if( pNewString
== NULL
|| strlen( pNewString
) == 0 )
3746 ret
= DISP_E_TYPEMISMATCH
;
3751 if( strncasecmp( pNewString
, "True", strlen( pNewString
) ) == 0 )
3753 *pboolOut
= VARIANT_TRUE
;
3755 else if( strncasecmp( pNewString
, "False", strlen( pNewString
) ) == 0 )
3757 *pboolOut
= VARIANT_FALSE
;
3761 /* Try converting the string to a floating point number.
3763 double dValue
= 0.0;
3764 HRESULT res
= VarR8FromStr( strIn
, lcid
, dwFlags
, &dValue
);
3767 ret
= DISP_E_TYPEMISMATCH
;
3770 *pboolOut
= (dValue
== 0.0) ?
3771 VARIANT_FALSE
: VARIANT_TRUE
;
3775 HeapFree( GetProcessHeap(), 0, pNewString
);
3780 /******************************************************************************
3781 * VarBoolFromI1 [OLEAUT32.233]
3783 HRESULT WINAPI
VarBoolFromI1(signed char cIn
, VARIANT_BOOL
* pboolOut
)
3785 TRACE("( %c, %p ), stub\n", cIn
, pboolOut
);
3787 *pboolOut
= (cIn
== 0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3792 /******************************************************************************
3793 * VarBoolFromUI2 [OLEAUT32.234]
3795 HRESULT WINAPI
VarBoolFromUI2(USHORT uiIn
, VARIANT_BOOL
* pboolOut
)
3797 TRACE("( %d, %p ), stub\n", uiIn
, pboolOut
);
3799 *pboolOut
= (uiIn
== 0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3804 /******************************************************************************
3805 * VarBoolFromUI4 [OLEAUT32.235]
3807 HRESULT WINAPI
VarBoolFromUI4(ULONG ulIn
, VARIANT_BOOL
* pboolOut
)
3809 TRACE("( %ld, %p ), stub\n", ulIn
, pboolOut
);
3811 *pboolOut
= (ulIn
== 0) ? VARIANT_FALSE
: VARIANT_TRUE
;
3816 /**********************************************************************
3817 * VarBoolFromCy [OLEAUT32.124]
3818 * Convert currency to boolean
3820 HRESULT WINAPI
VarBoolFromCy(CY cyIn
, VARIANT_BOOL
* pboolOut
) {
3821 if (cyIn
.s
.Hi
|| cyIn
.s
.Lo
) *pboolOut
= -1;
3827 /******************************************************************************
3828 * VarI1FromUI1 [OLEAUT32.244]
3830 HRESULT WINAPI
VarI1FromUI1(BYTE bIn
, signed char *pcOut
)
3832 TRACE("( %d, %p ), stub\n", bIn
, pcOut
);
3834 /* Check range of value.
3836 if( bIn
> CHAR_MAX
)
3838 return DISP_E_OVERFLOW
;
3841 *pcOut
= (CHAR
) bIn
;
3846 /******************************************************************************
3847 * VarI1FromI2 [OLEAUT32.245]
3849 HRESULT WINAPI
VarI1FromI2(short uiIn
, signed char *pcOut
)
3851 TRACE("( %d, %p ), stub\n", uiIn
, pcOut
);
3853 if( uiIn
> CHAR_MAX
)
3855 return DISP_E_OVERFLOW
;
3858 *pcOut
= (CHAR
) uiIn
;
3863 /******************************************************************************
3864 * VarI1FromI4 [OLEAUT32.246]
3866 HRESULT WINAPI
VarI1FromI4(LONG lIn
, signed char *pcOut
)
3868 TRACE("( %ld, %p ), stub\n", lIn
, pcOut
);
3870 if( lIn
< CHAR_MIN
|| lIn
> CHAR_MAX
)
3872 return DISP_E_OVERFLOW
;
3875 *pcOut
= (CHAR
) lIn
;
3880 /******************************************************************************
3881 * VarI1FromR4 [OLEAUT32.247]
3883 HRESULT WINAPI
VarI1FromR4(FLOAT fltIn
, signed char *pcOut
)
3885 TRACE("( %f, %p ), stub\n", fltIn
, pcOut
);
3887 fltIn
= round( fltIn
);
3888 if( fltIn
< CHAR_MIN
|| fltIn
> CHAR_MAX
)
3890 return DISP_E_OVERFLOW
;
3893 *pcOut
= (CHAR
) fltIn
;
3898 /******************************************************************************
3899 * VarI1FromR8 [OLEAUT32.248]
3901 HRESULT WINAPI
VarI1FromR8(double dblIn
, signed char *pcOut
)
3903 TRACE("( %f, %p ), stub\n", dblIn
, pcOut
);
3905 dblIn
= round( dblIn
);
3906 if( dblIn
< CHAR_MIN
|| dblIn
> CHAR_MAX
)
3908 return DISP_E_OVERFLOW
;
3911 *pcOut
= (CHAR
) dblIn
;
3916 /******************************************************************************
3917 * VarI1FromDate [OLEAUT32.249]
3919 HRESULT WINAPI
VarI1FromDate(DATE dateIn
, signed char *pcOut
)
3921 TRACE("( %f, %p ), stub\n", dateIn
, pcOut
);
3923 dateIn
= round( dateIn
);
3924 if( dateIn
< CHAR_MIN
|| dateIn
> CHAR_MAX
)
3926 return DISP_E_OVERFLOW
;
3929 *pcOut
= (CHAR
) dateIn
;
3934 /******************************************************************************
3935 * VarI1FromStr [OLEAUT32.251]
3937 HRESULT WINAPI
VarI1FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, signed char *pcOut
)
3939 double dValue
= 0.0;
3940 LPSTR pNewString
= NULL
;
3942 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, pcOut
);
3944 /* Check if we have a valid argument
3946 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
3947 RemoveCharacterFromString( pNewString
, "," );
3948 if( IsValidRealString( pNewString
) == FALSE
)
3950 return DISP_E_TYPEMISMATCH
;
3953 /* Convert the valid string to a floating point number.
3955 dValue
= atof( pNewString
);
3957 /* We don't need the string anymore so free it.
3959 HeapFree( GetProcessHeap(), 0, pNewString
);
3961 /* Check range of value.
3963 dValue
= round( dValue
);
3964 if( dValue
< CHAR_MIN
|| dValue
> CHAR_MAX
)
3966 return DISP_E_OVERFLOW
;
3969 *pcOut
= (CHAR
) dValue
;
3974 /******************************************************************************
3975 * VarI1FromBool [OLEAUT32.253]
3977 HRESULT WINAPI
VarI1FromBool(VARIANT_BOOL boolIn
, signed char *pcOut
)
3979 TRACE("( %d, %p ), stub\n", boolIn
, pcOut
);
3981 *pcOut
= (CHAR
) boolIn
;
3986 /******************************************************************************
3987 * VarI1FromUI2 [OLEAUT32.254]
3989 HRESULT WINAPI
VarI1FromUI2(USHORT uiIn
, signed char *pcOut
)
3991 TRACE("( %d, %p ), stub\n", uiIn
, pcOut
);
3993 if( uiIn
> CHAR_MAX
)
3995 return DISP_E_OVERFLOW
;
3998 *pcOut
= (CHAR
) uiIn
;
4003 /******************************************************************************
4004 * VarI1FromUI4 [OLEAUT32.255]
4006 HRESULT WINAPI
VarI1FromUI4(ULONG ulIn
, signed char *pcOut
)
4008 TRACE("( %ld, %p ), stub\n", ulIn
, pcOut
);
4010 if( ulIn
> CHAR_MAX
)
4012 return DISP_E_OVERFLOW
;
4015 *pcOut
= (CHAR
) ulIn
;
4020 /**********************************************************************
4021 * VarI1FromCy [OLEAUT32.250]
4022 * Convert currency to signed char
4024 HRESULT WINAPI
VarI1FromCy(CY cyIn
, signed char *pcOut
) {
4025 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
4027 if (t
> CHAR_MAX
|| t
< CHAR_MIN
) return DISP_E_OVERFLOW
;
4033 /******************************************************************************
4034 * VarUI2FromUI1 [OLEAUT32.257]
4036 HRESULT WINAPI
VarUI2FromUI1(BYTE bIn
, USHORT
* puiOut
)
4038 TRACE("( %d, %p ), stub\n", bIn
, puiOut
);
4040 *puiOut
= (USHORT
) bIn
;
4045 /******************************************************************************
4046 * VarUI2FromI2 [OLEAUT32.258]
4048 HRESULT WINAPI
VarUI2FromI2(short uiIn
, USHORT
* puiOut
)
4050 TRACE("( %d, %p ), stub\n", uiIn
, puiOut
);
4052 if( uiIn
< UI2_MIN
)
4054 return DISP_E_OVERFLOW
;
4057 *puiOut
= (USHORT
) uiIn
;
4062 /******************************************************************************
4063 * VarUI2FromI4 [OLEAUT32.259]
4065 HRESULT WINAPI
VarUI2FromI4(LONG lIn
, USHORT
* puiOut
)
4067 TRACE("( %ld, %p ), stub\n", lIn
, puiOut
);
4069 if( lIn
< UI2_MIN
|| lIn
> UI2_MAX
)
4071 return DISP_E_OVERFLOW
;
4074 *puiOut
= (USHORT
) lIn
;
4079 /******************************************************************************
4080 * VarUI2FromR4 [OLEAUT32.260]
4082 HRESULT WINAPI
VarUI2FromR4(FLOAT fltIn
, USHORT
* puiOut
)
4084 TRACE("( %f, %p ), stub\n", fltIn
, puiOut
);
4086 fltIn
= round( fltIn
);
4087 if( fltIn
< UI2_MIN
|| fltIn
> UI2_MAX
)
4089 return DISP_E_OVERFLOW
;
4092 *puiOut
= (USHORT
) fltIn
;
4097 /******************************************************************************
4098 * VarUI2FromR8 [OLEAUT32.261]
4100 HRESULT WINAPI
VarUI2FromR8(double dblIn
, USHORT
* puiOut
)
4102 TRACE("( %f, %p ), stub\n", dblIn
, puiOut
);
4104 dblIn
= round( dblIn
);
4105 if( dblIn
< UI2_MIN
|| dblIn
> UI2_MAX
)
4107 return DISP_E_OVERFLOW
;
4110 *puiOut
= (USHORT
) dblIn
;
4115 /******************************************************************************
4116 * VarUI2FromDate [OLEAUT32.262]
4118 HRESULT WINAPI
VarUI2FromDate(DATE dateIn
, USHORT
* puiOut
)
4120 TRACE("( %f, %p ), stub\n", dateIn
, puiOut
);
4122 dateIn
= round( dateIn
);
4123 if( dateIn
< UI2_MIN
|| dateIn
> UI2_MAX
)
4125 return DISP_E_OVERFLOW
;
4128 *puiOut
= (USHORT
) dateIn
;
4133 /******************************************************************************
4134 * VarUI2FromStr [OLEAUT32.264]
4136 HRESULT WINAPI
VarUI2FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, USHORT
* puiOut
)
4138 double dValue
= 0.0;
4139 LPSTR pNewString
= NULL
;
4141 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, puiOut
);
4143 /* Check if we have a valid argument
4145 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
4146 RemoveCharacterFromString( pNewString
, "," );
4147 if( IsValidRealString( pNewString
) == FALSE
)
4149 return DISP_E_TYPEMISMATCH
;
4152 /* Convert the valid string to a floating point number.
4154 dValue
= atof( pNewString
);
4156 /* We don't need the string anymore so free it.
4158 HeapFree( GetProcessHeap(), 0, pNewString
);
4160 /* Check range of value.
4162 dValue
= round( dValue
);
4163 if( dValue
< UI2_MIN
|| dValue
> UI2_MAX
)
4165 return DISP_E_OVERFLOW
;
4168 *puiOut
= (USHORT
) dValue
;
4173 /******************************************************************************
4174 * VarUI2FromBool [OLEAUT32.266]
4176 HRESULT WINAPI
VarUI2FromBool(VARIANT_BOOL boolIn
, USHORT
* puiOut
)
4178 TRACE("( %d, %p ), stub\n", boolIn
, puiOut
);
4180 *puiOut
= (USHORT
) boolIn
;
4185 /******************************************************************************
4186 * VarUI2FromI1 [OLEAUT32.267]
4188 HRESULT WINAPI
VarUI2FromI1(signed char cIn
, USHORT
* puiOut
)
4190 TRACE("( %c, %p ), stub\n", cIn
, puiOut
);
4192 *puiOut
= (USHORT
) cIn
;
4197 /******************************************************************************
4198 * VarUI2FromUI4 [OLEAUT32.268]
4200 HRESULT WINAPI
VarUI2FromUI4(ULONG ulIn
, USHORT
* puiOut
)
4202 TRACE("( %ld, %p ), stub\n", ulIn
, puiOut
);
4204 if( ulIn
> UI2_MAX
)
4206 return DISP_E_OVERFLOW
;
4209 *puiOut
= (USHORT
) ulIn
;
4214 /******************************************************************************
4215 * VarUI4FromStr [OLEAUT32.277]
4217 HRESULT WINAPI
VarUI4FromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
, ULONG
* pulOut
)
4219 double dValue
= 0.0;
4220 LPSTR pNewString
= NULL
;
4222 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn
, lcid
, dwFlags
, pulOut
);
4224 /* Check if we have a valid argument
4226 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
4227 RemoveCharacterFromString( pNewString
, "," );
4228 if( IsValidRealString( pNewString
) == FALSE
)
4230 return DISP_E_TYPEMISMATCH
;
4233 /* Convert the valid string to a floating point number.
4235 dValue
= atof( pNewString
);
4237 /* We don't need the string anymore so free it.
4239 HeapFree( GetProcessHeap(), 0, pNewString
);
4241 /* Check range of value.
4243 dValue
= round( dValue
);
4244 if( dValue
< UI4_MIN
|| dValue
> UI4_MAX
)
4246 return DISP_E_OVERFLOW
;
4249 *pulOut
= (ULONG
) dValue
;
4254 /**********************************************************************
4255 * VarUI2FromCy [OLEAUT32.263]
4256 * Convert currency to unsigned short
4258 HRESULT WINAPI
VarUI2FromCy(CY cyIn
, USHORT
* pusOut
) {
4259 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
4261 if (t
> UI2_MAX
|| t
< UI2_MIN
) return DISP_E_OVERFLOW
;
4263 *pusOut
= (USHORT
)t
;
4268 /******************************************************************************
4269 * VarUI4FromUI1 [OLEAUT32.270]
4271 HRESULT WINAPI
VarUI4FromUI1(BYTE bIn
, ULONG
* pulOut
)
4273 TRACE("( %d, %p ), stub\n", bIn
, pulOut
);
4275 *pulOut
= (USHORT
) bIn
;
4280 /******************************************************************************
4281 * VarUI4FromI2 [OLEAUT32.271]
4283 HRESULT WINAPI
VarUI4FromI2(short uiIn
, ULONG
* pulOut
)
4285 TRACE("( %d, %p ), stub\n", uiIn
, pulOut
);
4287 if( uiIn
< UI4_MIN
)
4289 return DISP_E_OVERFLOW
;
4292 *pulOut
= (ULONG
) uiIn
;
4297 /******************************************************************************
4298 * VarUI4FromI4 [OLEAUT32.272]
4300 HRESULT WINAPI
VarUI4FromI4(LONG lIn
, ULONG
* pulOut
)
4302 TRACE("( %ld, %p ), stub\n", lIn
, pulOut
);
4306 return DISP_E_OVERFLOW
;
4309 *pulOut
= (ULONG
) lIn
;
4314 /******************************************************************************
4315 * VarUI4FromR4 [OLEAUT32.273]
4317 HRESULT WINAPI
VarUI4FromR4(FLOAT fltIn
, ULONG
* pulOut
)
4319 fltIn
= round( fltIn
);
4320 if( fltIn
< UI4_MIN
|| fltIn
> UI4_MAX
)
4322 return DISP_E_OVERFLOW
;
4325 *pulOut
= (ULONG
) fltIn
;
4330 /******************************************************************************
4331 * VarUI4FromR8 [OLEAUT32.274]
4333 HRESULT WINAPI
VarUI4FromR8(double dblIn
, ULONG
* pulOut
)
4335 TRACE("( %f, %p ), stub\n", dblIn
, pulOut
);
4337 dblIn
= round( dblIn
);
4338 if( dblIn
< UI4_MIN
|| dblIn
> UI4_MAX
)
4340 return DISP_E_OVERFLOW
;
4343 *pulOut
= (ULONG
) dblIn
;
4348 /******************************************************************************
4349 * VarUI4FromDate [OLEAUT32.275]
4351 HRESULT WINAPI
VarUI4FromDate(DATE dateIn
, ULONG
* pulOut
)
4353 TRACE("( %f, %p ), stub\n", dateIn
, pulOut
);
4355 dateIn
= round( dateIn
);
4356 if( dateIn
< UI4_MIN
|| dateIn
> UI4_MAX
)
4358 return DISP_E_OVERFLOW
;
4361 *pulOut
= (ULONG
) dateIn
;
4366 /******************************************************************************
4367 * VarUI4FromBool [OLEAUT32.279]
4369 HRESULT WINAPI
VarUI4FromBool(VARIANT_BOOL boolIn
, ULONG
* pulOut
)
4371 TRACE("( %d, %p ), stub\n", boolIn
, pulOut
);
4373 *pulOut
= (ULONG
) boolIn
;
4378 /******************************************************************************
4379 * VarUI4FromI1 [OLEAUT32.280]
4381 HRESULT WINAPI
VarUI4FromI1(signed char cIn
, ULONG
* pulOut
)
4383 TRACE("( %c, %p ), stub\n", cIn
, pulOut
);
4385 *pulOut
= (ULONG
) cIn
;
4390 /******************************************************************************
4391 * VarUI4FromUI2 [OLEAUT32.281]
4393 HRESULT WINAPI
VarUI4FromUI2(USHORT uiIn
, ULONG
* pulOut
)
4395 TRACE("( %d, %p ), stub\n", uiIn
, pulOut
);
4397 *pulOut
= (ULONG
) uiIn
;
4402 /**********************************************************************
4403 * VarUI4FromCy [OLEAUT32.276]
4404 * Convert currency to unsigned long
4406 HRESULT WINAPI
VarUI4FromCy(CY cyIn
, ULONG
* pulOut
) {
4407 double t
= round((((double)cyIn
.s
.Hi
* 4294967296.0) + (double)cyIn
.s
.Lo
) / 10000);
4409 if (t
> UI4_MAX
|| t
< UI4_MIN
) return DISP_E_OVERFLOW
;
4416 /**********************************************************************
4417 * VarCyFromUI1 [OLEAUT32.98]
4418 * Convert unsigned char to currency
4420 HRESULT WINAPI
VarCyFromUI1(BYTE bIn
, CY
* pcyOut
) {
4422 pcyOut
->s
.Lo
= ((ULONG
)bIn
) * 10000;
4427 /**********************************************************************
4428 * VarCyFromI2 [OLEAUT32.99]
4429 * Convert signed short to currency
4431 HRESULT WINAPI
VarCyFromI2(short sIn
, CY
* pcyOut
) {
4432 if (sIn
< 0) pcyOut
->s
.Hi
= -1;
4433 else pcyOut
->s
.Hi
= 0;
4434 pcyOut
->s
.Lo
= ((ULONG
)sIn
) * 10000;
4439 /**********************************************************************
4440 * VarCyFromI4 [OLEAUT32.100]
4441 * Convert signed long to currency
4443 HRESULT WINAPI
VarCyFromI4(LONG lIn
, CY
* pcyOut
) {
4444 double t
= (double)lIn
* (double)10000;
4445 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4446 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4447 if (lIn
< 0) pcyOut
->s
.Hi
--;
4452 /**********************************************************************
4453 * VarCyFromR4 [OLEAUT32.101]
4454 * Convert float to currency
4456 HRESULT WINAPI
VarCyFromR4(FLOAT fltIn
, CY
* pcyOut
) {
4457 double t
= round((double)fltIn
* (double)10000);
4458 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4459 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4460 if (fltIn
< 0) pcyOut
->s
.Hi
--;
4465 /**********************************************************************
4466 * VarCyFromR8 [OLEAUT32.102]
4467 * Convert double to currency
4469 HRESULT WINAPI
VarCyFromR8(double dblIn
, CY
* pcyOut
) {
4470 double t
= round(dblIn
* (double)10000);
4471 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4472 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4473 if (dblIn
< 0) pcyOut
->s
.Hi
--;
4478 /**********************************************************************
4479 * VarCyFromDate [OLEAUT32.103]
4480 * Convert date to currency
4482 HRESULT WINAPI
VarCyFromDate(DATE dateIn
, CY
* pcyOut
) {
4483 double t
= round((double)dateIn
* (double)10000);
4484 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4485 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4486 if (dateIn
< 0) pcyOut
->s
.Hi
--;
4491 /**********************************************************************
4492 * VarCyFromStr [OLEAUT32.104]
4493 * FIXME: Never tested with decimal separator other than '.'
4495 HRESULT WINAPI
VarCyFromStr(OLECHAR
*strIn
, LCID lcid
, ULONG dwFlags
, CY
*pcyOut
) {
4497 LPSTR pNewString
= NULL
;
4498 char *decSep
= NULL
;
4499 char *strPtr
,*curPtr
= NULL
;
4501 double currencyVal
= 0.0;
4504 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, strIn
);
4505 TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString
, lcid
, dwFlags
, pcyOut
);
4507 /* Get locale information - Decimal Separator (size includes 0x00) */
4508 size
= GetLocaleInfoA(lcid
, LOCALE_SDECIMAL
, NULL
, 0);
4509 decSep
= (char *) malloc(size
);
4510 rc
= GetLocaleInfoA(lcid
, LOCALE_SDECIMAL
, decSep
, size
);
4511 TRACE("Decimal Separator is '%s'\n", decSep
);
4513 /* Now copy to temporary buffer, skipping any character except 0-9 and
4514 the decimal separator */
4515 curPtr
= pBuffer
; /* Current position in string being built */
4516 strPtr
= pNewString
; /* Current position in supplied currenct string */
4519 /* If decimal separator, skip it and put '.' in string */
4520 if (strncmp(strPtr
, decSep
, (size
-1)) == 0) {
4521 strPtr
= strPtr
+ (size
-1);
4524 } else if ((*strPtr
== '+' || *strPtr
== '-') ||
4525 (*strPtr
>= '0' && *strPtr
<= '9')) {
4533 /* Try to get currency into a double */
4534 currencyVal
= atof(pBuffer
);
4535 TRACE("Converted string '%s' to %f\n", pBuffer
, currencyVal
);
4537 /* Free allocated storage */
4538 HeapFree( GetProcessHeap(), 0, pNewString
);
4541 /* Convert double -> currency using internal routine */
4542 return VarCyFromR8(currencyVal
, pcyOut
);
4546 /**********************************************************************
4547 * VarCyFromBool [OLEAUT32.106]
4548 * Convert boolean to currency
4550 HRESULT WINAPI
VarCyFromBool(VARIANT_BOOL boolIn
, CY
* pcyOut
) {
4551 if (boolIn
< 0) pcyOut
->s
.Hi
= -1;
4552 else pcyOut
->s
.Hi
= 0;
4553 pcyOut
->s
.Lo
= (ULONG
)boolIn
* (ULONG
)10000;
4558 /**********************************************************************
4559 * VarCyFromI1 [OLEAUT32.225]
4560 * Convert signed char to currency
4562 HRESULT WINAPI
VarCyFromI1(signed char cIn
, CY
* pcyOut
) {
4563 if (cIn
< 0) pcyOut
->s
.Hi
= -1;
4564 else pcyOut
->s
.Hi
= 0;
4565 pcyOut
->s
.Lo
= (ULONG
)cIn
* (ULONG
)10000;
4570 /**********************************************************************
4571 * VarCyFromUI2 [OLEAUT32.226]
4572 * Convert unsigned short to currency
4574 HRESULT WINAPI
VarCyFromUI2(USHORT usIn
, CY
* pcyOut
) {
4576 pcyOut
->s
.Lo
= (ULONG
)usIn
* (ULONG
)10000;
4581 /**********************************************************************
4582 * VarCyFromUI4 [OLEAUT32.227]
4583 * Convert unsigned long to currency
4585 HRESULT WINAPI
VarCyFromUI4(ULONG ulIn
, CY
* pcyOut
) {
4586 double t
= (double)ulIn
* (double)10000;
4587 pcyOut
->s
.Hi
= (LONG
)(t
/ (double)4294967296.0);
4588 pcyOut
->s
.Lo
= (ULONG
)fmod(t
, (double)4294967296.0);
4593 /**********************************************************************
4594 * VarDecFromStr [OLEAUT32.@]
4596 HRESULT WINAPI
VarDecFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
,
4602 DECIMAL_SETZERO(pdecOut
);
4604 if(*p
== (WCHAR
)'-')pdecOut
->u
.s
.sign
= DECIMAL_NEG
;
4605 if((*p
== (WCHAR
)'-') || (*p
== (WCHAR
)'+')) p
++;
4606 for(;*p
!= (WCHAR
)0; p
++) {
4607 if((*p
< (WCHAR
)'0')||(*p
> (WCHAR
)'9')) goto error
;
4608 t
= (ULONGLONG
)pdecOut
->u1
.s1
.Lo32
*(ULONGLONG
)10
4609 + (ULONGLONG
)(*p
-(WCHAR
)'0');
4610 cy
= (ULONG
)(t
>> 32);
4611 pdecOut
->u1
.s1
.Lo32
= (ULONG
)(t
& (ULONGLONG
)UI4_MAX
);
4612 t
= (ULONGLONG
)pdecOut
->u1
.s1
.Mid32
* (ULONGLONG
)10
4614 cy
= (ULONG
)(t
>> 32);
4615 pdecOut
->u1
.s1
.Mid32
= (ULONG
)(t
& (ULONGLONG
)UI4_MAX
);
4616 t
= (ULONGLONG
)pdecOut
->Hi32
* (ULONGLONG
)10
4618 cy
= (ULONG
)(t
>> 32);
4619 pdecOut
->Hi32
= (ULONG
)(t
& (ULONGLONG
)UI4_MAX
);
4620 if(cy
) goto overflow
;
4622 TRACE("%s -> sign %02x,hi %08lx,mid %08lx, lo%08lx, scale %08x\n",
4624 pdecOut
->u
.s
.sign
, pdecOut
->Hi32
, pdecOut
->u1
.s1
.Mid32
,
4625 pdecOut
->u1
.s1
.Lo32
, pdecOut
->u
.s
.scale
);
4630 pdecOut
->Hi32
= pdecOut
->u1
.s1
.Mid32
= pdecOut
->u1
.s1
.Lo32
= 0xffffffff;
4631 return DISP_E_OVERFLOW
;
4634 ERR("%s: unknown char at pos %d\n",
4635 debugstr_w(strIn
), p
- strIn
+ 1);
4636 return DISP_E_TYPEMISMATCH
;
4639 /**********************************************************************
4640 * DosDateTimeToVariantTime [OLEAUT32.14]
4641 * Convert dos representation of time to the date and time representation
4642 * stored in a variant.
4644 INT WINAPI
DosDateTimeToVariantTime(USHORT wDosDate
, USHORT wDosTime
,
4649 TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate
, wDosTime
, pvtime
);
4651 t
.tm_sec
= (wDosTime
& 0x001f) * 2;
4652 t
.tm_min
= (wDosTime
& 0x07e0) >> 5;
4653 t
.tm_hour
= (wDosTime
& 0xf800) >> 11;
4655 t
.tm_mday
= (wDosDate
& 0x001f);
4656 t
.tm_mon
= (wDosDate
& 0x01e0) >> 5;
4657 t
.tm_year
= ((wDosDate
& 0xfe00) >> 9) + 1980;
4659 return TmToDATE( &t
, pvtime
);
4663 /**********************************************************************
4664 * VarParseNumFromStr [OLEAUT32.46]
4666 HRESULT WINAPI
VarParseNumFromStr(OLECHAR
* strIn
, LCID lcid
, ULONG dwFlags
,
4667 NUMPARSE
* pnumprs
, BYTE
* rgbDig
)
4671 BOOL foundNum
=FALSE
;
4673 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn
),dwFlags
);
4674 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs
->cDig
,pnumprs
->dwInFlags
);
4676 /* The other struct components are to be set by us */
4677 memset(rgbDig
,0,pnumprs
->cDig
);
4679 /* FIXME: Just patching some values in */
4680 pnumprs
->nPwr10
= 0;
4681 pnumprs
->nBaseShift
= 0;
4682 pnumprs
->cchUsed
= lastent
;
4683 pnumprs
->dwOutFlags
= NUMPRS_DECIMAL
;
4686 for (i
=0; strIn
[i
] ;i
++) {
4687 if ((strIn
[i
]>='0') && (strIn
[i
]<='9')) {
4689 if (pnumprs
->cDig
> cDig
) {
4690 *(rgbDig
++)=strIn
[i
]-'0';
4694 } else if ((strIn
[i
]=='-') && (foundNum
==FALSE
)) {
4695 pnumprs
->dwOutFlags
|= NUMPRS_NEG
;
4698 pnumprs
->cDig
= cDig
;
4699 TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs
->cDig
,pnumprs
->dwOutFlags
);
4704 /**********************************************************************
4705 * VarNumFromParseNum [OLEAUT32.47]
4707 HRESULT WINAPI
VarNumFromParseNum(NUMPARSE
* pnumprs
, BYTE
* rgbDig
,
4708 ULONG dwVtBits
, VARIANT
* pvar
)
4712 FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits
);
4715 for (i
=0;i
<pnumprs
->cDig
;i
++)
4716 xint
= xint
*10 + rgbDig
[i
];
4718 if (pnumprs
->dwOutFlags
& NUMPRS_NEG
) {
4723 if (dwVtBits
& VTBIT_I4
) {
4725 V_UNION(pvar
,intVal
) = xint
;
4728 if (dwVtBits
& VTBIT_R8
) {
4730 V_UNION(pvar
,dblVal
) = xint
;
4733 if (dwVtBits
& VTBIT_R4
) {
4735 V_UNION(pvar
,fltVal
) = xint
;
4738 if (dwVtBits
& VTBIT_I2
) {
4740 V_UNION(pvar
,iVal
) = xint
;
4743 /* FIXME: Currency should be from a double */
4744 if (dwVtBits
& VTBIT_CY
) {
4746 TRACE("Calculated currency is xint=%ld\n", xint
);
4747 VarCyFromInt( (int) xint
, &V_UNION(pvar
,cyVal
) );
4748 TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar
,cyVal
).s
.Hi
, V_UNION(pvar
,cyVal
).s
.Lo
);
4749 return VarCyFromInt( (int) xint
, &V_UNION(pvar
,cyVal
) );
4752 FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits
, (int) xint
);
4757 /**********************************************************************
4758 * VarFormatDateTime [OLEAUT32.97]
4760 HRESULT WINAPI
VarFormatDateTime(LPVARIANT var
, INT format
, ULONG dwFlags
, BSTR
*out
)
4762 FIXME("%p %d %lx %p\n", var
, format
, dwFlags
, out
);
4766 /**********************************************************************
4767 * VarFormatCurrency [OLEAUT32.127]
4769 HRESULT WINAPI
VarFormatCurrency(LPVARIANT var
, INT digits
, INT lead
, INT paren
, INT group
, ULONG dwFlags
, BSTR
*out
)
4771 FIXME("%p %d %d %d %d %lx %p\n", var
, digits
, lead
, paren
, group
, dwFlags
, out
);
4775 /**********************************************************************
4776 * VariantTimeToDosDateTime [OLEAUT32.13]
4777 * Convert variant representation of time to the date and time representation
4780 INT WINAPI
VariantTimeToDosDateTime(DATE pvtime
, USHORT
*wDosDate
, USHORT
*wDosTime
)
4786 TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate
, *wDosTime
, &pvtime
);
4788 if (DateToTm(pvtime
, 0, &t
) < 0) return 0;
4790 *wDosTime
= *wDosTime
| (t
.tm_sec
/ 2);
4791 *wDosTime
= *wDosTime
| (t
.tm_min
<< 5);
4792 *wDosTime
= *wDosTime
| (t
.tm_hour
<< 11);
4794 *wDosDate
= *wDosDate
| t
.tm_mday
;
4795 *wDosDate
= *wDosDate
| t
.tm_mon
<< 5;
4796 *wDosDate
= *wDosDate
| ((t
.tm_year
- 1980) << 9) ;
4802 /***********************************************************************
4803 * SystemTimeToVariantTime [OLEAUT32.184]
4805 HRESULT WINAPI
SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime
, double *pvtime
)
4809 TRACE(" %d/%d/%d %d:%d:%d\n",
4810 lpSystemTime
->wMonth
, lpSystemTime
->wDay
,
4811 lpSystemTime
->wYear
, lpSystemTime
->wHour
,
4812 lpSystemTime
->wMinute
, lpSystemTime
->wSecond
);
4814 if (lpSystemTime
->wYear
>= 1900)
4816 t
.tm_sec
= lpSystemTime
->wSecond
;
4817 t
.tm_min
= lpSystemTime
->wMinute
;
4818 t
.tm_hour
= lpSystemTime
->wHour
;
4820 t
.tm_mday
= lpSystemTime
->wDay
;
4821 t
.tm_mon
= lpSystemTime
->wMonth
- 1; /* tm_mon is 0..11, wMonth is 1..12 */
4822 t
.tm_year
= lpSystemTime
->wYear
;
4824 return TmToDATE( &t
, pvtime
);
4829 long firstDayOfNextYear
;
4834 double decimalPart
= 0.0;
4836 t
.tm_sec
= lpSystemTime
->wSecond
;
4837 t
.tm_min
= lpSystemTime
->wMinute
;
4838 t
.tm_hour
= lpSystemTime
->wHour
;
4840 /* Step year forward the same number of years before 1900 */
4841 t
.tm_year
= 1900 + 1899 - lpSystemTime
->wYear
;
4842 t
.tm_mon
= lpSystemTime
->wMonth
- 1;
4843 t
.tm_mday
= lpSystemTime
->wDay
;
4845 /* Calculate date */
4846 TmToDATE( &t
, pvtime
);
4848 thisDay
= (double) floor( *pvtime
);
4849 decimalPart
= fmod( *pvtime
, thisDay
);
4851 /* Now, calculate the same time for the first of Jan that year */
4857 t
.tm_year
= t
.tm_year
+1;
4858 TmToDATE( &t
, &tmpDate
);
4859 firstDayOfNextYear
= (long) floor(tmpDate
);
4861 /* Finally since we know the size of the year, subtract the two to get
4862 remaining time in the year */
4863 leftInYear
= firstDayOfNextYear
- thisDay
;
4865 /* Now we want full years up to the year in question, and remainder of year
4866 of the year in question */
4867 if (isleap(lpSystemTime
->wYear
) ) {
4868 TRACE("Extra day due to leap year\n");
4869 result
= 2.0 - ((firstDayOfNextYear
- 366) + leftInYear
- 2.0);
4871 result
= 2.0 - ((firstDayOfNextYear
- 365) + leftInYear
- 2.0);
4873 *pvtime
= (double) result
+ decimalPart
;
4874 TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime
, firstDayOfNextYear
, thisDay
, leftInYear
);
4882 /***********************************************************************
4883 * VariantTimeToSystemTime [OLEAUT32.185]
4885 HRESULT WINAPI
VariantTimeToSystemTime( double vtime
, LPSYSTEMTIME lpSystemTime
)
4887 double t
= 0, timeofday
= 0;
4889 static const BYTE Days_Per_Month
[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4890 static const BYTE Days_Per_Month_LY
[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4892 /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4893 static const BYTE Month_Code
[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4894 static const BYTE Month_Code_LY
[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4896 /* The Century_Code is used to find the Day of the Week */
4897 static const BYTE Century_Code
[] = {0, 6, 4, 2};
4901 TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime
, lpSystemTime
);
4906 if (DateToTm(vtime
, 0, &r
) <= 0) return 0;
4908 lpSystemTime
->wSecond
= r
.tm_sec
;
4909 lpSystemTime
->wMinute
= r
.tm_min
;
4910 lpSystemTime
->wHour
= r
.tm_hour
;
4911 lpSystemTime
->wDay
= r
.tm_mday
;
4912 lpSystemTime
->wMonth
= r
.tm_mon
;
4914 if (lpSystemTime
->wMonth
== 12)
4915 lpSystemTime
->wMonth
= 1;
4917 lpSystemTime
->wMonth
++;
4919 lpSystemTime
->wYear
= r
.tm_year
;
4925 if (DateToTm(vtime
, 0, &r
) <= 0) return 0;
4927 lpSystemTime
->wSecond
= r
.tm_sec
;
4928 lpSystemTime
->wMinute
= r
.tm_min
;
4929 lpSystemTime
->wHour
= r
.tm_hour
;
4931 lpSystemTime
->wMonth
= 13 - r
.tm_mon
;
4933 if (lpSystemTime
->wMonth
== 1)
4934 lpSystemTime
->wMonth
= 12;
4936 lpSystemTime
->wMonth
--;
4938 lpSystemTime
->wYear
= 1899 - (r
.tm_year
- 1900);
4940 if (!isleap(lpSystemTime
->wYear
) )
4941 lpSystemTime
->wDay
= Days_Per_Month
[13 - lpSystemTime
->wMonth
] - r
.tm_mday
;
4943 lpSystemTime
->wDay
= Days_Per_Month_LY
[13 - lpSystemTime
->wMonth
] - r
.tm_mday
;
4948 if (!isleap(lpSystemTime
->wYear
))
4951 (Century_Code+Month_Code+Year_Code+Day) % 7
4953 The century code repeats every 400 years , so the array
4954 works out like this,
4956 Century_Code[0] is for 16th/20th Centry
4957 Century_Code[1] is for 17th/21th Centry
4958 Century_Code[2] is for 18th/22th Centry
4959 Century_Code[3] is for 19th/23th Centry
4961 The year code is found with the formula (year + (year / 4))
4962 the "year" must be between 0 and 99 .
4964 The Month Code (Month_Code[1]) starts with January and
4968 lpSystemTime
->wDayOfWeek
= (
4969 Century_Code
[(( (lpSystemTime
->wYear
+100) - lpSystemTime
->wYear
%100) /100) %4]+
4970 ((lpSystemTime
->wYear
%100)+(lpSystemTime
->wYear
%100)/4)+
4971 Month_Code
[lpSystemTime
->wMonth
]+
4972 lpSystemTime
->wDay
) % 7;
4974 if (lpSystemTime
->wDayOfWeek
== 0) lpSystemTime
->wDayOfWeek
= 7;
4975 else lpSystemTime
->wDayOfWeek
-= 1;
4979 lpSystemTime
->wDayOfWeek
= (
4980 Century_Code
[(((lpSystemTime
->wYear
+100) - lpSystemTime
->wYear
%100)/100)%4]+
4981 ((lpSystemTime
->wYear
%100)+(lpSystemTime
->wYear
%100)/4)+
4982 Month_Code_LY
[lpSystemTime
->wMonth
]+
4983 lpSystemTime
->wDay
) % 7;
4985 if (lpSystemTime
->wDayOfWeek
== 0) lpSystemTime
->wDayOfWeek
= 7;
4986 else lpSystemTime
->wDayOfWeek
-= 1;
4990 timeofday
= vtime
- t
;
4992 lpSystemTime
->wMilliseconds
= (timeofday
4993 - lpSystemTime
->wHour
*(1/24)
4994 - lpSystemTime
->wMinute
*(1/1440)
4995 - lpSystemTime
->wSecond
*(1/86400) )*(1/5184000);
5000 /***********************************************************************
5001 * VarUdateFromDate [OLEAUT32.331]
5003 HRESULT WINAPI
VarUdateFromDate( DATE datein
, ULONG dwFlags
, UDATE
*pudateout
)
5006 static const BYTE Days_Per_Month
[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
5007 static const BYTE Days_Per_Month_LY
[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
5009 TRACE("DATE = %f\n", (double)datein
);
5010 i
= VariantTimeToSystemTime(datein
, &(pudateout
->st
) );
5014 pudateout
->wDayOfYear
= 0;
5016 if (isleap(pudateout
->st
.wYear
))
5018 for (i
=1; i
<pudateout
->st
.wMonth
; i
++)
5019 pudateout
->wDayOfYear
+= Days_Per_Month
[i
];
5023 for (i
=1; i
<pudateout
->st
.wMonth
; i
++)
5024 pudateout
->wDayOfYear
+= Days_Per_Month_LY
[i
];
5027 pudateout
->wDayOfYear
+= pudateout
->st
.wDay
;
5028 dwFlags
= 0; /*VAR_VALIDDATE*/
5035 /***********************************************************************
5036 * VarDateFromUdate [OLEAUT32.330]
5038 HRESULT WINAPI
VarDateFromUdate(UDATE
*pudateout
,
5039 ULONG dwFlags
, DATE
*datein
)
5043 TRACE(" %d/%d/%d %d:%d:%d\n",
5044 pudateout
->st
.wMonth
, pudateout
->st
.wDay
,
5045 pudateout
->st
.wYear
, pudateout
->st
.wHour
,
5046 pudateout
->st
.wMinute
, pudateout
->st
.wSecond
);
5049 i
= SystemTimeToVariantTime(&(pudateout
->st
), &t
);
5053 else return E_INVALIDARG
;
5057 /**********************************************************************
5058 * VarBstrCmp [OLEAUT32.314]
5061 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
5062 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
5065 HRESULT WINAPI
VarBstrCmp(BSTR left
, BSTR right
, LCID lcid
, DWORD flags
)
5069 TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left
), debugstr_w(right
), lcid
, flags
);
5071 /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
5072 if((!left
) || (!right
)) {
5074 if (!left
&& (!right
|| *right
==0)) return VARCMP_EQ
;
5075 else if (!right
&& (!left
|| *left
==0)) return VARCMP_EQ
;
5076 else return VARCMP_NULL
;
5079 if(flags
&NORM_IGNORECASE
)
5080 r
= lstrcmpiW(left
,right
);
5082 r
= lstrcmpW(left
,right
);
5092 /**********************************************************************
5093 * VarBstrCat [OLEAUT32.313]
5095 HRESULT WINAPI
VarBstrCat(BSTR left
, BSTR right
, BSTR
*out
)
5100 TRACE("( %s %s %p )\n", debugstr_w(left
), debugstr_w(right
), out
);
5102 /* On Windows, NULL parms are still handled (as empty strings) */
5103 if (left
) size
=size
+ lstrlenW(left
);
5104 if (right
) size
=size
+ lstrlenW(right
);
5107 result
= SysAllocStringLen(NULL
, size
);
5109 if (left
) lstrcatW(result
,left
);
5110 if (right
) lstrcatW(result
,right
);
5111 TRACE("result = %s, [%p]\n", debugstr_w(result
), result
);
5116 /**********************************************************************
5117 * VarCat [OLEAUT32.318]
5119 HRESULT WINAPI
VarCat(LPVARIANT left
, LPVARIANT right
, LPVARIANT out
)
5121 /* Should we VariantClear out? */
5122 /* Can we handle array, vector, by ref etc. */
5123 if ((V_VT(left
)&VT_TYPEMASK
) == VT_NULL
&&
5124 (V_VT(right
)&VT_TYPEMASK
) == VT_NULL
)
5126 V_VT(out
) = VT_NULL
;
5130 if (V_VT(left
) == VT_BSTR
&& V_VT(right
) == VT_BSTR
)
5132 V_VT(out
) = VT_BSTR
;
5133 VarBstrCat (V_BSTR(left
), V_BSTR(right
), &V_BSTR(out
));
5136 if (V_VT(left
) == VT_BSTR
) {
5140 V_VT(out
) = VT_BSTR
;
5141 hres
= VariantChangeTypeEx(&bstrvar
,right
,0,0,VT_BSTR
);
5143 FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right
));
5146 VarBstrCat (V_BSTR(left
), V_BSTR(&bstrvar
), &V_BSTR(out
));
5149 if (V_VT(right
) == VT_BSTR
) {
5153 V_VT(out
) = VT_BSTR
;
5154 hres
= VariantChangeTypeEx(&bstrvar
,left
,0,0,VT_BSTR
);
5156 FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right
));
5159 VarBstrCat (V_BSTR(&bstrvar
), V_BSTR(right
), &V_BSTR(out
));
5162 FIXME ("types %d / %d not supported\n",V_VT(left
)&VT_TYPEMASK
, V_VT(right
)&VT_TYPEMASK
);
5166 /**********************************************************************
5167 * VarCmp [OLEAUT32.176]
5170 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
5171 * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
5174 HRESULT WINAPI
VarCmp(LPVARIANT left
, LPVARIANT right
, LCID lcid
, DWORD flags
)
5186 VariantInit(&lv
);VariantInit(&rv
);
5187 V_VT(right
) &= ~0x8000; /* hack since we sometime get this flag. */
5188 V_VT(left
) &= ~0x8000; /* hack since we sometime get this flag. */
5190 TRACE("Left Var:\n");
5192 TRACE("Right Var:\n");
5193 dump_Variant(right
);
5195 /* If either are null, then return VARCMP_NULL */
5196 if ((V_VT(left
)&VT_TYPEMASK
) == VT_NULL
||
5197 (V_VT(right
)&VT_TYPEMASK
) == VT_NULL
)
5200 /* Strings - use VarBstrCmp */
5201 if ((V_VT(left
)&VT_TYPEMASK
) == VT_BSTR
&&
5202 (V_VT(right
)&VT_TYPEMASK
) == VT_BSTR
) {
5203 return VarBstrCmp(V_BSTR(left
), V_BSTR(right
), lcid
, flags
);
5206 xmask
= (1<<(V_VT(left
)&VT_TYPEMASK
))|(1<<(V_VT(right
)&VT_TYPEMASK
));
5207 if (xmask
& (1<<VT_R8
)) {
5208 rc
= VariantChangeType(&lv
,left
,0,VT_R8
);
5209 if (FAILED(rc
)) return rc
;
5210 rc
= VariantChangeType(&rv
,right
,0,VT_R8
);
5211 if (FAILED(rc
)) return rc
;
5213 if (V_R8(&lv
) == V_R8(&rv
)) return VARCMP_EQ
;
5214 if (V_R8(&lv
) < V_R8(&rv
)) return VARCMP_LT
;
5215 if (V_R8(&lv
) > V_R8(&rv
)) return VARCMP_GT
;
5216 return E_FAIL
; /* can't get here */
5218 if (xmask
& (1<<VT_R4
)) {
5219 rc
= VariantChangeType(&lv
,left
,0,VT_R4
);
5220 if (FAILED(rc
)) return rc
;
5221 rc
= VariantChangeType(&rv
,right
,0,VT_R4
);
5222 if (FAILED(rc
)) return rc
;
5224 if (V_R4(&lv
) == V_R4(&rv
)) return VARCMP_EQ
;
5225 if (V_R4(&lv
) < V_R4(&rv
)) return VARCMP_LT
;
5226 if (V_R4(&lv
) > V_R4(&rv
)) return VARCMP_GT
;
5227 return E_FAIL
; /* can't get here */
5230 /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
5231 Use LONGLONG to maximize ranges */
5233 switch (V_VT(left
)&VT_TYPEMASK
) {
5234 case VT_I1
: lVal
= V_UNION(left
,cVal
); break;
5235 case VT_I2
: lVal
= V_UNION(left
,iVal
); break;
5236 case VT_I4
: lVal
= V_UNION(left
,lVal
); break;
5237 case VT_INT
: lVal
= V_UNION(left
,lVal
); break;
5238 case VT_UI1
: lVal
= V_UNION(left
,bVal
); break;
5239 case VT_UI2
: lVal
= V_UNION(left
,uiVal
); break;
5240 case VT_UI4
: lVal
= V_UNION(left
,ulVal
); break;
5241 case VT_UINT
: lVal
= V_UNION(left
,ulVal
); break;
5242 case VT_BOOL
: lVal
= V_UNION(left
,boolVal
); break;
5243 default: lOk
= FALSE
;
5247 switch (V_VT(right
)&VT_TYPEMASK
) {
5248 case VT_I1
: rVal
= V_UNION(right
,cVal
); break;
5249 case VT_I2
: rVal
= V_UNION(right
,iVal
); break;
5250 case VT_I4
: rVal
= V_UNION(right
,lVal
); break;
5251 case VT_INT
: rVal
= V_UNION(right
,lVal
); break;
5252 case VT_UI1
: rVal
= V_UNION(right
,bVal
); break;
5253 case VT_UI2
: rVal
= V_UNION(right
,uiVal
); break;
5254 case VT_UI4
: rVal
= V_UNION(right
,ulVal
); break;
5255 case VT_UINT
: rVal
= V_UNION(right
,ulVal
); break;
5256 case VT_BOOL
: rVal
= V_UNION(right
,boolVal
); break;
5257 default: rOk
= FALSE
;
5263 } else if (lVal
> rVal
) {
5270 /* Strings - use VarBstrCmp */
5271 if ((V_VT(left
)&VT_TYPEMASK
) == VT_DATE
&&
5272 (V_VT(right
)&VT_TYPEMASK
) == VT_DATE
) {
5274 if (floor(V_UNION(left
,date
)) == floor(V_UNION(right
,date
))) {
5275 /* Due to floating point rounding errors, calculate varDate in whole numbers) */
5276 double wholePart
= 0.0;
5280 /* Get the fraction * 24*60*60 to make it into whole seconds */
5281 wholePart
= (double) floor( V_UNION(left
,date
) );
5282 if (wholePart
== 0) wholePart
= 1;
5283 leftR
= floor(fmod( V_UNION(left
,date
), wholePart
) * (24*60*60));
5285 wholePart
= (double) floor( V_UNION(right
,date
) );
5286 if (wholePart
== 0) wholePart
= 1;
5287 rightR
= floor(fmod( V_UNION(right
,date
), wholePart
) * (24*60*60));
5289 if (leftR
< rightR
) {
5291 } else if (leftR
> rightR
) {
5297 } else if (V_UNION(left
,date
) < V_UNION(right
,date
)) {
5299 } else if (V_UNION(left
,date
) > V_UNION(right
,date
)) {
5303 FIXME("VarCmp partial implementation, doesnt support vt 0x%x / 0x%x\n",V_VT(left
), V_VT(right
));
5307 /**********************************************************************
5308 * VarAnd [OLEAUT32.142]
5311 HRESULT WINAPI
VarAnd(LPVARIANT left
, LPVARIANT right
, LPVARIANT result
)
5313 HRESULT rc
= E_FAIL
;
5315 TRACE("Left Var:\n");
5317 TRACE("Right Var:\n");
5318 dump_Variant(right
);
5320 if ((V_VT(left
)&VT_TYPEMASK
) == VT_BOOL
&&
5321 (V_VT(right
)&VT_TYPEMASK
) == VT_BOOL
) {
5323 V_VT(result
) = VT_BOOL
;
5324 if (V_BOOL(left
) && V_BOOL(right
)) {
5325 V_BOOL(result
) = VARIANT_TRUE
;
5327 V_BOOL(result
) = VARIANT_FALSE
;
5338 int resT
= 0; /* Testing has shown I2 & I2 == I2, all else
5339 becomes I4, even unsigned ints (incl. UI2) */
5342 switch (V_VT(left
)&VT_TYPEMASK
) {
5343 case VT_I1
: lVal
= V_UNION(left
,cVal
); resT
=VT_I4
; break;
5344 case VT_I2
: lVal
= V_UNION(left
,iVal
); resT
=VT_I2
; break;
5345 case VT_I4
: lVal
= V_UNION(left
,lVal
); resT
=VT_I4
; break;
5346 case VT_INT
: lVal
= V_UNION(left
,lVal
); resT
=VT_I4
; break;
5347 case VT_UI1
: lVal
= V_UNION(left
,bVal
); resT
=VT_I4
; break;
5348 case VT_UI2
: lVal
= V_UNION(left
,uiVal
); resT
=VT_I4
; break;
5349 case VT_UI4
: lVal
= V_UNION(left
,ulVal
); resT
=VT_I4
; break;
5350 case VT_UINT
: lVal
= V_UNION(left
,ulVal
); resT
=VT_I4
; break;
5351 default: lOk
= FALSE
;
5355 switch (V_VT(right
)&VT_TYPEMASK
) {
5356 case VT_I1
: rVal
= V_UNION(right
,cVal
); resT
=VT_I4
; break;
5357 case VT_I2
: rVal
= V_UNION(right
,iVal
); resT
=max(VT_I2
, resT
); break;
5358 case VT_I4
: rVal
= V_UNION(right
,lVal
); resT
=VT_I4
; break;
5359 case VT_INT
: rVal
= V_UNION(right
,lVal
); resT
=VT_I4
; break;
5360 case VT_UI1
: rVal
= V_UNION(right
,bVal
); resT
=VT_I4
; break;
5361 case VT_UI2
: rVal
= V_UNION(right
,uiVal
); resT
=VT_I4
; break;
5362 case VT_UI4
: rVal
= V_UNION(right
,ulVal
); resT
=VT_I4
; break;
5363 case VT_UINT
: rVal
= V_UNION(right
,ulVal
); resT
=VT_I4
; break;
5364 default: rOk
= FALSE
;
5368 res
= (lVal
& rVal
);
5369 V_VT(result
) = resT
;
5371 case VT_I2
: V_UNION(result
,iVal
) = res
; break;
5372 case VT_I4
: V_UNION(result
,lVal
) = res
; break;
5374 FIXME("Unexpected result variant type %x\n", resT
);
5375 V_UNION(result
,lVal
) = res
;
5380 FIXME("VarAnd stub\n");
5384 TRACE("rc=%d, Result:\n", (int) rc
);
5385 dump_Variant(result
);
5389 /**********************************************************************
5390 * VarAdd [OLEAUT32.141]
5391 * FIXME: From MSDN: If ... Then
5392 * Both expressions are of the string type Concatenated.
5393 * One expression is a string type and the other a character Addition.
5394 * One expression is numeric and the other is a string Addition.
5395 * Both expressions are numeric Addition.
5396 * Either expression is NULL NULL is returned.
5397 * Both expressions are empty Integer subtype is returned.
5400 HRESULT WINAPI
VarAdd(LPVARIANT left
, LPVARIANT right
, LPVARIANT result
)
5402 HRESULT rc
= E_FAIL
;
5404 TRACE("Left Var:\n");
5406 TRACE("Right Var:\n");
5407 dump_Variant(right
);
5409 if ((V_VT(left
)&VT_TYPEMASK
) == VT_EMPTY
)
5410 return VariantCopy(result
,right
);
5412 if ((V_VT(right
)&VT_TYPEMASK
) == VT_EMPTY
)
5413 return VariantCopy(result
,left
);
5415 if (((V_VT(left
)&VT_TYPEMASK
) == VT_R8
) || ((V_VT(right
)&VT_TYPEMASK
) == VT_R8
)) {
5423 switch (V_VT(left
)&VT_TYPEMASK
) {
5424 case VT_I1
: lVal
= V_UNION(left
,cVal
); break;
5425 case VT_I2
: lVal
= V_UNION(left
,iVal
); break;
5426 case VT_I4
: lVal
= V_UNION(left
,lVal
); break;
5427 case VT_INT
: lVal
= V_UNION(left
,lVal
); break;
5428 case VT_UI1
: lVal
= V_UNION(left
,bVal
); break;
5429 case VT_UI2
: lVal
= V_UNION(left
,uiVal
); break;
5430 case VT_UI4
: lVal
= V_UNION(left
,ulVal
); break;
5431 case VT_UINT
: lVal
= V_UNION(left
,ulVal
); break;
5432 case VT_R4
: lVal
= V_UNION(left
,fltVal
); break;
5433 case VT_R8
: lVal
= V_UNION(left
,dblVal
); break;
5434 case VT_NULL
: lVal
= 0.0; break;
5435 default: lOk
= FALSE
;
5439 switch (V_VT(right
)&VT_TYPEMASK
) {
5440 case VT_I1
: rVal
= V_UNION(right
,cVal
); break;
5441 case VT_I2
: rVal
= V_UNION(right
,iVal
); break;
5442 case VT_I4
: rVal
= V_UNION(right
,lVal
); break;
5443 case VT_INT
: rVal
= V_UNION(right
,lVal
); break;
5444 case VT_UI1
: rVal
= V_UNION(right
,bVal
); break;
5445 case VT_UI2
: rVal
= V_UNION(right
,uiVal
); break;
5446 case VT_UI4
: rVal
= V_UNION(right
,ulVal
); break;
5447 case VT_UINT
: rVal
= V_UNION(right
,ulVal
); break;
5448 case VT_R4
: rVal
= V_UNION(right
,fltVal
);break;
5449 case VT_R8
: rVal
= V_UNION(right
,dblVal
);break;
5450 case VT_NULL
: rVal
= 0.0; break;
5451 default: rOk
= FALSE
;
5455 res
= (lVal
+ rVal
);
5456 V_VT(result
) = VT_R8
;
5457 V_UNION(result
,dblVal
) = res
;
5460 FIXME("Unhandled type pair %d / %d in double addition.\n",
5461 (V_VT(left
)&VT_TYPEMASK
),
5462 (V_VT(right
)&VT_TYPEMASK
)
5468 /* Handle strings as concat */
5469 if ((V_VT(left
)&VT_TYPEMASK
) == VT_BSTR
&&
5470 (V_VT(right
)&VT_TYPEMASK
) == VT_BSTR
) {
5471 V_VT(result
) = VT_BSTR
;
5472 rc
= VarBstrCat(V_BSTR(left
), V_BSTR(right
), &V_BSTR(result
));
5481 int resT
= 0; /* Testing has shown I2 + I2 == I2, all else
5485 switch (V_VT(left
)&VT_TYPEMASK
) {
5486 case VT_I1
: lVal
= V_UNION(left
,cVal
); resT
=VT_I4
; break;
5487 case VT_I2
: lVal
= V_UNION(left
,iVal
); resT
=VT_I2
; break;
5488 case VT_I4
: lVal
= V_UNION(left
,lVal
); resT
=VT_I4
; break;
5489 case VT_INT
: lVal
= V_UNION(left
,lVal
); resT
=VT_I4
; break;
5490 case VT_UI1
: lVal
= V_UNION(left
,bVal
); resT
=VT_I4
; break;
5491 case VT_UI2
: lVal
= V_UNION(left
,uiVal
); resT
=VT_I4
; break;
5492 case VT_UI4
: lVal
= V_UNION(left
,ulVal
); resT
=VT_I4
; break;
5493 case VT_UINT
: lVal
= V_UNION(left
,ulVal
); resT
=VT_I4
; break;
5494 case VT_NULL
: lVal
= 0; resT
= VT_I4
; break;
5495 default: lOk
= FALSE
;
5499 switch (V_VT(right
)&VT_TYPEMASK
) {
5500 case VT_I1
: rVal
= V_UNION(right
,cVal
); resT
=VT_I4
; break;
5501 case VT_I2
: rVal
= V_UNION(right
,iVal
); resT
=max(VT_I2
, resT
); break;
5502 case VT_I4
: rVal
= V_UNION(right
,lVal
); resT
=VT_I4
; break;
5503 case VT_INT
: rVal
= V_UNION(right
,lVal
); resT
=VT_I4
; break;
5504 case VT_UI1
: rVal
= V_UNION(right
,bVal
); resT
=VT_I4
; break;
5505 case VT_UI2
: rVal
= V_UNION(right
,uiVal
); resT
=VT_I4
; break;
5506 case VT_UI4
: rVal
= V_UNION(right
,ulVal
); resT
=VT_I4
; break;
5507 case VT_UINT
: rVal
= V_UNION(right
,ulVal
); resT
=VT_I4
; break;
5508 case VT_NULL
: rVal
= 0; resT
=VT_I4
; break;
5509 default: rOk
= FALSE
;
5513 res
= (lVal
+ rVal
);
5514 V_VT(result
) = resT
;
5516 case VT_I2
: V_UNION(result
,iVal
) = res
; break;
5517 case VT_I4
: V_UNION(result
,lVal
) = res
; break;
5519 FIXME("Unexpected result variant type %x\n", resT
);
5520 V_UNION(result
,lVal
) = res
;
5525 FIXME("unimplemented part (0x%x + 0x%x)\n",V_VT(left
), V_VT(right
));
5529 TRACE("rc=%d, Result:\n", (int) rc
);
5530 dump_Variant(result
);
5534 /**********************************************************************
5535 * VarMul [OLEAUT32.156]
5538 HRESULT WINAPI
VarMul(LPVARIANT left
, LPVARIANT right
, LPVARIANT result
)
5540 HRESULT rc
= E_FAIL
;
5541 VARTYPE lvt
,rvt
,resvt
;
5545 TRACE("left: ");dump_Variant(left
);
5546 TRACE("right: ");dump_Variant(right
);
5548 VariantInit(&lv
);VariantInit(&rv
);
5549 lvt
= V_VT(left
)&VT_TYPEMASK
;
5550 rvt
= V_VT(right
)&VT_TYPEMASK
;
5551 found
= FALSE
;resvt
=VT_VOID
;
5552 if (((1<<lvt
) | (1<<rvt
)) & ((1<<VT_R4
)|(1<<VT_R8
))) {
5556 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
)))) {
5561 FIXME("can't expand vt %d vs %d to a target type.\n",lvt
,rvt
);
5564 rc
= VariantChangeType(&lv
, left
, 0, resvt
);
5566 FIXME("Could not convert 0x%x to %d?\n",V_VT(left
),resvt
);
5569 rc
= VariantChangeType(&rv
, right
, 0, resvt
);
5571 FIXME("Could not convert 0x%x to %d?\n",V_VT(right
),resvt
);
5576 V_VT(result
) = resvt
;
5577 V_R8(result
) = V_R8(&lv
) * V_R8(&rv
);
5581 V_VT(result
) = resvt
;
5582 V_I4(result
) = V_I4(&lv
) * V_I4(&rv
);
5586 TRACE("rc=%d, Result:\n", (int) rc
);
5587 dump_Variant(result
);
5591 /**********************************************************************
5592 * VarDiv [OLEAUT32.143]
5595 HRESULT WINAPI
VarDiv(LPVARIANT left
, LPVARIANT right
, LPVARIANT result
)
5597 HRESULT rc
= E_FAIL
;
5598 VARTYPE lvt
,rvt
,resvt
;
5602 TRACE("left: ");dump_Variant(left
);
5603 TRACE("right: ");dump_Variant(right
);
5605 VariantInit(&lv
);VariantInit(&rv
);
5606 lvt
= V_VT(left
)&VT_TYPEMASK
;
5607 rvt
= V_VT(right
)&VT_TYPEMASK
;
5608 found
= FALSE
;resvt
= VT_VOID
;
5609 if (((1<<lvt
) | (1<<rvt
)) & ((1<<VT_R4
)|(1<<VT_R8
))) {
5613 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
)))) {
5618 FIXME("can't expand vt %d vs %d to a target type.\n",lvt
,rvt
);
5621 rc
= VariantChangeType(&lv
, left
, 0, resvt
);
5623 FIXME("Could not convert 0x%x to %d?\n",V_VT(left
),resvt
);
5626 rc
= VariantChangeType(&rv
, right
, 0, resvt
);
5628 FIXME("Could not convert 0x%x to %d?\n",V_VT(right
),resvt
);
5633 V_VT(result
) = resvt
;
5634 V_R8(result
) = V_R8(&lv
) / V_R8(&rv
);
5638 V_VT(result
) = resvt
;
5639 V_I4(result
) = V_I4(&lv
) / V_I4(&rv
);
5643 TRACE("rc=%d, Result:\n", (int) rc
);
5644 dump_Variant(result
);
5648 /**********************************************************************
5649 * VarSub [OLEAUT32.159]
5652 HRESULT WINAPI
VarSub(LPVARIANT left
, LPVARIANT right
, LPVARIANT result
)
5654 HRESULT rc
= E_FAIL
;
5655 VARTYPE lvt
,rvt
,resvt
;
5659 TRACE("left: ");dump_Variant(left
);
5660 TRACE("right: ");dump_Variant(right
);
5662 VariantInit(&lv
);VariantInit(&rv
);
5663 lvt
= V_VT(left
)&VT_TYPEMASK
;
5664 rvt
= V_VT(right
)&VT_TYPEMASK
;
5665 found
= FALSE
;resvt
= VT_VOID
;
5666 if (((1<<lvt
) | (1<<rvt
)) & ((1<<VT_R4
)|(1<<VT_R8
))) {
5670 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
)))) {
5675 FIXME("can't expand vt %d vs %d to a target type.\n",lvt
,rvt
);
5678 rc
= VariantChangeType(&lv
, left
, 0, resvt
);
5680 FIXME("Could not convert 0x%x to %d?\n",V_VT(left
),resvt
);
5683 rc
= VariantChangeType(&rv
, right
, 0, resvt
);
5685 FIXME("Could not convert 0x%x to %d?\n",V_VT(right
),resvt
);
5690 V_VT(result
) = resvt
;
5691 V_R8(result
) = V_R8(&lv
) - V_R8(&rv
);
5695 V_VT(result
) = resvt
;
5696 V_I4(result
) = V_I4(&lv
) - V_I4(&rv
);
5700 TRACE("rc=%d, Result:\n", (int) rc
);
5701 dump_Variant(result
);
5705 /**********************************************************************
5706 * VarOr [OLEAUT32.157]
5709 HRESULT WINAPI
VarOr(LPVARIANT left
, LPVARIANT right
, LPVARIANT result
)
5711 HRESULT rc
= E_FAIL
;
5713 TRACE("Left Var:\n");
5715 TRACE("Right Var:\n");
5716 dump_Variant(right
);
5718 if ((V_VT(left
)&VT_TYPEMASK
) == VT_BOOL
&&
5719 (V_VT(right
)&VT_TYPEMASK
) == VT_BOOL
) {
5721 V_VT(result
) = VT_BOOL
;
5722 if (V_BOOL(left
) || V_BOOL(right
)) {
5723 V_BOOL(result
) = VARIANT_TRUE
;
5725 V_BOOL(result
) = VARIANT_FALSE
;
5736 int resT
= 0; /* Testing has shown I2 & I2 == I2, all else
5737 becomes I4, even unsigned ints (incl. UI2) */
5740 switch (V_VT(left
)&VT_TYPEMASK
) {
5741 case VT_I1
: lVal
= V_UNION(left
,cVal
); resT
=VT_I4
; break;
5742 case VT_I2
: lVal
= V_UNION(left
,iVal
); resT
=VT_I2
; break;
5743 case VT_I4
: lVal
= V_UNION(left
,lVal
); resT
=VT_I4
; break;
5744 case VT_INT
: lVal
= V_UNION(left
,lVal
); resT
=VT_I4
; break;
5745 case VT_UI1
: lVal
= V_UNION(left
,bVal
); resT
=VT_I4
; break;
5746 case VT_UI2
: lVal
= V_UNION(left
,uiVal
); resT
=VT_I4
; break;
5747 case VT_UI4
: lVal
= V_UNION(left
,ulVal
); resT
=VT_I4
; break;
5748 case VT_UINT
: lVal
= V_UNION(left
,ulVal
); resT
=VT_I4
; break;
5749 default: lOk
= FALSE
;
5753 switch (V_VT(right
)&VT_TYPEMASK
) {
5754 case VT_I1
: rVal
= V_UNION(right
,cVal
); resT
=VT_I4
; break;
5755 case VT_I2
: rVal
= V_UNION(right
,iVal
); resT
=max(VT_I2
, resT
); break;
5756 case VT_I4
: rVal
= V_UNION(right
,lVal
); resT
=VT_I4
; break;
5757 case VT_INT
: rVal
= V_UNION(right
,lVal
); resT
=VT_I4
; break;
5758 case VT_UI1
: rVal
= V_UNION(right
,bVal
); resT
=VT_I4
; break;
5759 case VT_UI2
: rVal
= V_UNION(right
,uiVal
); resT
=VT_I4
; break;
5760 case VT_UI4
: rVal
= V_UNION(right
,ulVal
); resT
=VT_I4
; break;
5761 case VT_UINT
: rVal
= V_UNION(right
,ulVal
); resT
=VT_I4
; break;
5762 default: rOk
= FALSE
;
5766 res
= (lVal
| rVal
);
5767 V_VT(result
) = resT
;
5769 case VT_I2
: V_UNION(result
,iVal
) = res
; break;
5770 case VT_I4
: V_UNION(result
,lVal
) = res
; break;
5772 FIXME("Unexpected result variant type %x\n", resT
);
5773 V_UNION(result
,lVal
) = res
;
5778 FIXME("unimplemented part\n");
5782 TRACE("rc=%d, Result:\n", (int) rc
);
5783 dump_Variant(result
);
5787 /**********************************************************************
5788 * VarNot [OLEAUT32.174]
5791 HRESULT WINAPI
VarNot(LPVARIANT in
, LPVARIANT result
)
5793 HRESULT rc
= E_FAIL
;
5798 if ((V_VT(in
)&VT_TYPEMASK
) == VT_BOOL
) {
5800 V_VT(result
) = VT_BOOL
;
5802 V_BOOL(result
) = VARIANT_FALSE
;
5804 V_BOOL(result
) = VARIANT_TRUE
;
5809 FIXME("VarNot stub\n");
5812 TRACE("rc=%d, Result:\n", (int) rc
);
5813 dump_Variant(result
);
5817 /**********************************************************************
5818 * VarTokenizeFormatString [OLEAUT32.140]
5820 * From investigation on W2K, a list is built up which is:
5822 * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
5823 * <token> - Insert appropriate token
5826 HRESULT WINAPI
VarTokenizeFormatString(LPOLESTR format
, LPBYTE rgbTok
,
5827 int cbTok
, int iFirstDay
, int iFirstWeek
,
5828 LCID lcid
, int *pcbActual
) {
5831 int realLen
, formatLeft
;
5833 LPSTR pFormatA
, pStart
;
5835 BOOL insertCopy
= FALSE
;
5836 LPSTR copyFrom
= NULL
;
5838 TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format
), rgbTok
, cbTok
,
5839 iFirstDay
, iFirstWeek
);
5841 /* Big enough for header? */
5842 if (cbTok
< sizeof(FORMATHDR
)) {
5843 return TYPE_E_BUFFERTOOSMALL
;
5847 hdr
= (FORMATHDR
*) rgbTok
;
5848 memset(hdr
, 0x00, sizeof(FORMATHDR
));
5849 hdr
->hex3
= 0x03; /* No idea what these are */
5852 /* Start parsing string */
5853 realLen
= sizeof(FORMATHDR
);
5854 pData
= rgbTok
+ realLen
;
5855 pFormatA
= HEAP_strdupWtoA( GetProcessHeap(), 0, format
);
5857 formatLeft
= strlen(pFormatA
);
5859 /* Work through the format */
5860 while (*pFormatA
!= 0x00) {
5863 while (checkStr
>=0 && (formatTokens
[checkStr
].tokenSize
!= 0x00)) {
5864 if (formatLeft
>= formatTokens
[checkStr
].tokenSize
&&
5865 strncmp(formatTokens
[checkStr
].str
, pFormatA
,
5866 formatTokens
[checkStr
].tokenSize
) == 0) {
5867 TRACE("match on '%s'\n", formatTokens
[checkStr
].str
);
5871 /* If we have skipped chars, insert the copy */
5872 if (insertCopy
== TRUE
) {
5874 if ((realLen
+ 3) > cbTok
) {
5875 HeapFree( GetProcessHeap(), 0, pFormatA
);
5876 return TYPE_E_BUFFERTOOSMALL
;
5881 *pData
= (BYTE
)(copyFrom
- pStart
);
5883 *pData
= (BYTE
)(pFormatA
- copyFrom
);
5885 realLen
= realLen
+ 3;
5889 /* Now insert the token itself */
5890 if ((realLen
+ 1) > cbTok
) {
5891 HeapFree( GetProcessHeap(), 0, pFormatA
);
5892 return TYPE_E_BUFFERTOOSMALL
;
5894 *pData
= formatTokens
[checkStr
].tokenId
;
5896 realLen
= realLen
+ 1;
5898 pFormatA
= pFormatA
+ formatTokens
[checkStr
].tokenSize
;
5899 formatLeft
= formatLeft
- formatTokens
[checkStr
].tokenSize
;
5900 checkStr
= -1; /* Flag as found and break out of while loop */
5906 /* Did we ever match a token? */
5907 if (checkStr
!= -1 && insertCopy
== FALSE
) {
5908 TRACE("No match - need to insert copy from %p [%p]\n", pFormatA
, pStart
);
5910 copyFrom
= pFormatA
;
5911 } else if (checkStr
!= -1) {
5912 pFormatA
= pFormatA
+ 1;
5917 /* Finally, if we have skipped chars, insert the copy */
5918 if (insertCopy
== TRUE
) {
5920 TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom
, pStart
, pFormatA
);
5921 if ((realLen
+ 3) > cbTok
) {
5922 HeapFree( GetProcessHeap(), 0, pFormatA
);
5923 return TYPE_E_BUFFERTOOSMALL
;
5928 *pData
= (BYTE
)(copyFrom
- pStart
);
5930 *pData
= (BYTE
)(pFormatA
- copyFrom
);
5932 realLen
= realLen
+ 3;
5935 /* Finally insert the terminator */
5936 if ((realLen
+ 1) > cbTok
) {
5937 HeapFree( GetProcessHeap(), 0, pFormatA
);
5938 return TYPE_E_BUFFERTOOSMALL
;
5941 realLen
= realLen
+ 1;
5943 /* Finally fill in the length */
5945 *pcbActual
= realLen
;
5949 for (i
=0; i
<realLen
; i
=i
+0x10) {
5950 printf(" %4.4x : ", i
);
5951 for (j
=0; j
<0x10 && (i
+j
< realLen
); j
++) {
5952 printf("%2.2x ", rgbTok
[i
+j
]);
5958 HeapFree( GetProcessHeap(), 0, pFormatA
);
5963 /**********************************************************************
5964 * VarFormatFromTokens [OLEAUT32.139]
5965 * FIXME: No account of flags or iFirstDay etc
5967 HRESULT WINAPI
VarFormatFromTokens(LPVARIANT varIn
, LPOLESTR format
,
5968 LPBYTE pbTokCur
, ULONG dwFlags
, BSTR
*pbstrOut
,
5971 FORMATHDR
*hdr
= (FORMATHDR
*)pbTokCur
;
5972 BYTE
*pData
= pbTokCur
+ sizeof (FORMATHDR
);
5973 LPSTR pFormatA
= HEAP_strdupWtoA( GetProcessHeap(), 0, format
);
5974 char output
[BUFFER_MAX
];
5976 int size
, whichToken
;
5982 TRACE("'%s', %p %lx %p only date support\n", pFormatA
, pbTokCur
, dwFlags
, pbstrOut
);
5984 dump_Variant(varIn
);
5986 memset(output
, 0x00, BUFFER_MAX
);
5989 while (*pData
!= TOK_END
&& ((pData
- pbTokCur
) <= (hdr
->len
))) {
5991 TRACE("Output looks like : '%s'\n", output
);
5993 /* Convert varient to appropriate data type */
5995 while ((formatTokens
[whichToken
].tokenSize
!= 0x00) &&
5996 (formatTokens
[whichToken
].tokenId
!= *pData
)) {
6000 /* Use Variant local from here downwards as always correct type */
6001 if (formatTokens
[whichToken
].tokenSize
> 0 &&
6002 formatTokens
[whichToken
].varTypeRequired
!= 0) {
6003 VariantInit( &Variant
);
6004 if (Coerce( &Variant
, lcid
, dwFlags
, varIn
,
6005 formatTokens
[whichToken
].varTypeRequired
) != S_OK
) {
6006 HeapFree( GetProcessHeap(), 0, pFormatA
);
6007 return DISP_E_TYPEMISMATCH
;
6008 } else if (formatTokens
[whichToken
].varTypeRequired
== VT_DATE
) {
6009 if( DateToTm( V_UNION(&Variant
,date
), dwFlags
, &TM
) == FALSE
) {
6010 HeapFree( GetProcessHeap(), 0, pFormatA
);
6011 return E_INVALIDARG
;
6016 TRACE("Looking for match on token '%x'\n", *pData
);
6019 TRACE("Copy from %d for %d bytes\n", *(pData
+1), *(pData
+2));
6020 memcpy(pNextPos
, &pFormatA
[*(pData
+1)], *(pData
+2));
6021 pNextPos
= pNextPos
+ *(pData
+2);
6026 /* Get locale information - Time Separator */
6027 size
= GetLocaleInfoA(lcid
, LOCALE_STIME
, NULL
, 0);
6028 GetLocaleInfoA(lcid
, LOCALE_STIME
, pNextPos
, size
);
6029 TRACE("TOK_COLON Time separator is '%s'\n", pNextPos
);
6030 pNextPos
= pNextPos
+ size
;
6035 /* Get locale information - Date Separator */
6036 size
= GetLocaleInfoA(lcid
, LOCALE_SDATE
, NULL
, 0);
6037 GetLocaleInfoA(lcid
, LOCALE_SDATE
, pNextPos
, size
);
6038 TRACE("TOK_COLON Time separator is '%s'\n", pNextPos
);
6039 pNextPos
= pNextPos
+ size
;
6044 sprintf(pNextPos
, "%d", TM
.tm_mday
);
6045 pNextPos
= pNextPos
+ strlen(pNextPos
);
6050 sprintf(pNextPos
, "%2.2d", TM
.tm_mday
);
6051 pNextPos
= pNextPos
+ strlen(pNextPos
);
6056 sprintf(pNextPos
, "%d", TM
.tm_wday
+1);
6057 pNextPos
= pNextPos
+ strlen(pNextPos
);
6062 sprintf(pNextPos
, "%d", TM
.tm_mon
+1);
6063 pNextPos
= pNextPos
+ strlen(pNextPos
);
6068 sprintf(pNextPos
, "%2.2d", TM
.tm_mon
+1);
6069 pNextPos
= pNextPos
+ strlen(pNextPos
);
6074 sprintf(pNextPos
, "%d", ((TM
.tm_mon
+1)/4)+1);
6075 pNextPos
= pNextPos
+ strlen(pNextPos
);
6080 sprintf(pNextPos
, "%2.2d", TM
.tm_yday
+1);
6081 pNextPos
= pNextPos
+ strlen(pNextPos
);
6086 sprintf(pNextPos
, "%2.2d", TM
.tm_year
);
6087 pNextPos
= pNextPos
+ strlen(pNextPos
);
6092 sprintf(pNextPos
, "%4.4d", TM
.tm_year
);
6093 pNextPos
= pNextPos
+ strlen(pNextPos
);
6098 sprintf(pNextPos
, "%d", TM
.tm_hour
);
6099 pNextPos
= pNextPos
+ strlen(pNextPos
);
6104 sprintf(pNextPos
, "%2.2d", TM
.tm_hour
);
6105 pNextPos
= pNextPos
+ strlen(pNextPos
);
6110 sprintf(pNextPos
, "%d", TM
.tm_min
);
6111 pNextPos
= pNextPos
+ strlen(pNextPos
);
6116 sprintf(pNextPos
, "%2.2d", TM
.tm_min
);
6117 pNextPos
= pNextPos
+ strlen(pNextPos
);
6122 sprintf(pNextPos
, "%d", TM
.tm_sec
);
6123 pNextPos
= pNextPos
+ strlen(pNextPos
);
6128 sprintf(pNextPos
, "%2.2d", TM
.tm_sec
);
6129 pNextPos
= pNextPos
+ strlen(pNextPos
);
6149 FIXME("Unhandled token for VarFormat %d\n", *pData
);
6150 HeapFree( GetProcessHeap(), 0, pFormatA
);
6151 return E_INVALIDARG
;
6156 *pbstrOut
= StringDupAtoBstr( output
);
6157 HeapFree( GetProcessHeap(), 0, pFormatA
);
6161 /**********************************************************************
6162 * VarFormat [OLEAUT32.87]
6165 HRESULT WINAPI
VarFormat(LPVARIANT varIn
, LPOLESTR format
,
6166 int firstDay
, int firstWeek
, ULONG dwFlags
,
6169 LPSTR pNewString
= NULL
;
6172 TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
6173 debugstr_w(format
), firstDay
, firstWeek
, dwFlags
);
6175 dump_Variant(varIn
);
6177 /* Note: Must Handle references type Variants (contain ptrs
6178 to values rather than values */
6180 /* Get format string */
6181 pNewString
= HEAP_strdupWtoA( GetProcessHeap(), 0, format
);
6183 /* FIXME: Handle some simple pre-definted format strings : */
6184 if (((V_VT(varIn
)&VT_TYPEMASK
) == VT_CY
) && (lstrcmpiA(pNewString
, "Currency") == 0)) {
6186 /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
6190 /* Handle references type Variants (contain ptrs to values rather than values */
6191 if (V_VT(varIn
)&VT_BYREF
) {
6192 rc
= VarR8FromCy(*(CY
*)V_UNION(varIn
,byref
), &curVal
);
6194 rc
= VarR8FromCy(V_UNION(varIn
,cyVal
), &curVal
);
6198 char tmpStr
[BUFFER_MAX
];
6199 sprintf(tmpStr
, "%f", curVal
);
6200 if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags
, tmpStr
, NULL
, pBuffer
, BUFFER_MAX
) == 0) {
6203 *pbstrOut
= StringDupAtoBstr( pBuffer
);
6207 } else if ((V_VT(varIn
)&VT_TYPEMASK
) == VT_DATE
) {
6209 /* Attempt to do proper formatting! */
6210 int firstToken
= -1;
6212 rc
= VarTokenizeFormatString(format
, pBuffer
, sizeof(pBuffer
), firstDay
,
6213 firstWeek
, GetUserDefaultLCID(), &firstToken
);
6215 rc
= VarFormatFromTokens(varIn
, format
, pBuffer
, dwFlags
, pbstrOut
, GetUserDefaultLCID());
6218 } else if ((V_VT(varIn
)&VT_TYPEMASK
) == VT_R8
) {
6219 if (V_VT(varIn
)&VT_BYREF
) {
6220 sprintf(pBuffer
, "%f", *V_UNION(varIn
,pdblVal
));
6222 sprintf(pBuffer
, "%f", V_UNION(varIn
,dblVal
));
6224 *pbstrOut
= StringDupAtoBstr( pBuffer
);
6225 } else if ((V_VT(varIn
)&VT_TYPEMASK
) == VT_I2
) {
6226 if (V_VT(varIn
)&VT_BYREF
) {
6227 sprintf(pBuffer
, "%d", *V_UNION(varIn
,piVal
));
6229 sprintf(pBuffer
, "%d", V_UNION(varIn
,iVal
));
6231 *pbstrOut
= StringDupAtoBstr( pBuffer
);
6232 } else if ((V_VT(varIn
)&VT_TYPEMASK
) == VT_BSTR
) {
6233 if (V_VT(varIn
)&VT_BYREF
)
6234 *pbstrOut
= SysAllocString( *V_UNION(varIn
,pbstrVal
) );
6236 *pbstrOut
= SysAllocString( V_UNION(varIn
,bstrVal
) );
6238 FIXME("VarFormat: Unsupported format %d!\n", V_VT(varIn
)&VT_TYPEMASK
);
6239 *pbstrOut
= StringDupAtoBstr( "??" );
6242 /* Free allocated storage */
6243 HeapFree( GetProcessHeap(), 0, pNewString
);
6244 TRACE("result: '%s'\n", debugstr_w(*pbstrOut
));
6248 /**********************************************************************
6249 * VarCyMulI4 [OLEAUT32.304]
6250 * Multiply currency value by integer
6252 HRESULT WINAPI
VarCyMulI4(CY cyIn
, LONG mulBy
, CY
*pcyOut
) {
6257 rc
= VarR8FromCy(cyIn
, &cyVal
);
6259 rc
= VarCyFromR8((cyVal
* (double) mulBy
), pcyOut
);
6260 TRACE("Multiply %f by %ld = %f [%ld,%lu]\n", cyVal
, mulBy
, (cyVal
* (double) mulBy
),
6261 pcyOut
->s
.Hi
, pcyOut
->s
.Lo
);