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