source: trunk/src/oleaut32/variant.c@ 6952

Last change on this file since 6952 was 6952, checked in by sandervl, 24 years ago

Wine 20011004 resync

File size: 116.2 KB
Line 
1/*
2 * VARIANT
3 *
4 * Copyright 1998 Jean-Claude Cote
5 *
6 * NOTES
7 * This implements the low-level and hi-level APIs for manipulating VARIANTs.
8 * The low-level APIs are used to do data coercion between different data types.
9 * The hi-level APIs are built on top of these low-level APIs and handle
10 * initialization, copying, destroying and changing the type of VARIANTs.
11 *
12 * TODO:
13 * - The Variant APIs do not support international languages, currency
14 * types, number formating and calendar. They only support U.S. English format.
15 * - The Variant APIs do not the following types: IUknown, IDispatch, DECIMAL and SafeArray.
16 * The prototypes for these are commented out in the oleauto.h file. They need
17 * to be implemented and cases need to be added to the switches of the existing APIs.
18 * - The parsing of date for the VarDateFromStr is not complete.
19 * - The date manipulations do not support dates prior to 1900.
20 * - The parsing does not accept as many formats as the Windows implementation.
21 */
22#ifdef __WIN32OS2__
23#define HAVE_FLOAT_H
24#define WINE_LARGE_INTEGER
25#include "oleaut32.h"
26
27#endif
28
29#include "config.h"
30
31#include <string.h>
32#include <stdlib.h>
33#include <stdio.h>
34#include <math.h>
35#include <time.h>
36
37#ifdef HAVE_FLOAT_H
38# include <float.h>
39#endif
40
41#include "windef.h"
42#include "oleauto.h"
43#include "heap.h"
44#include "debugtools.h"
45#include "winerror.h"
46#include "parsedt.h"
47
48DEFAULT_DEBUG_CHANNEL(ole);
49
50#define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
51
52#ifndef FLT_MAX
53# ifdef MAXFLOAT
54# define FLT_MAX MAXFLOAT
55# else
56# error "Can't find #define for MAXFLOAT/FLT_MAX"
57# endif
58#endif
59
60#undef CHAR_MAX
61#undef CHAR_MIN
62static const char CHAR_MAX = 127;
63static const char CHAR_MIN = -128;
64static const BYTE UI1_MAX = 255;
65static const BYTE UI1_MIN = 0;
66static const unsigned short UI2_MAX = 65535;
67static const unsigned short UI2_MIN = 0;
68static const short I2_MAX = 32767;
69static const short I2_MIN = -32768;
70static const unsigned long UI4_MAX = 4294967295U;
71static const unsigned long UI4_MIN = 0;
72static const long I4_MAX = 2147483647;
73static const long I4_MIN = -(2147483648U);
74static const DATE DATE_MIN = -657434;
75static const DATE DATE_MAX = 2958465;
76
77
78/* This mask is used to set a flag in wReserved1 of
79 * the VARIANTARG structure. The flag indicates if
80 * the API function is using an inner variant or not.
81 */
82#define PROCESSING_INNER_VARIANT 0x0001
83
84/* General use buffer.
85 */
86#define BUFFER_MAX 1024
87static char pBuffer[BUFFER_MAX];
88
89/*
90 * Note a leap year is one that is a multiple of 4
91 * but not of a 100. Except if it is a multiple of
92 * 400 then it is a leap year.
93 */
94/* According to postgreSQL date parsing functions there is
95 * a leap year when this expression is true.
96 * (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
97 * So according to this there is 365.2515 days in one year.
98 * One + every four years: 1/4 -> 365.25
99 * One - every 100 years: 1/100 -> 365.01
100 * One + every 400 years: 1/400 -> 365.0025
101 */
102/* static const double DAYS_IN_ONE_YEAR = 365.2515;
103 *
104 * ^^ Might this be the key to an easy way to factor large prime numbers?
105 * Let's try using arithmetic. <lawson_whitney@juno.com> 7 Mar 2000
106 */
107static const double DAYS_IN_ONE_YEAR = 365.2425;
108
109
110/******************************************************************************
111 * DateTimeStringToTm [INTERNAL]
112 *
113 * Converts a string representation of a date and/or time to a tm structure.
114 *
115 * Note this function uses the postgresql date parsing functions found
116 * in the parsedt.c file.
117 *
118 * Returns TRUE if successful.
119 *
120 * Note: This function does not parse the day of the week,
121 * daylight savings time. It will only fill the followin fields in
122 * the tm struct, tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
123 *
124 ******************************************************************************/
125static BOOL DateTimeStringToTm( OLECHAR* strIn, DWORD dwFlags, struct tm* pTm )
126{
127 BOOL res = FALSE;
128 double fsec;
129 int tzp;
130 int dtype;
131 int nf;
132 char *field[MAXDATEFIELDS];
133 int ftype[MAXDATEFIELDS];
134 char lowstr[MAXDATELEN + 1];
135 char* strDateTime = NULL;
136
137 /* Convert the string to ASCII since this is the only format
138 * postgesql can handle.
139 */
140 strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
141
142 if( strDateTime != NULL )
143 {
144 /* Make sure we don't go over the maximum length
145 * accepted by postgesql.
146 */
147 if( strlen( strDateTime ) <= MAXDATELEN )
148 {
149 if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
150 {
151 if( dwFlags & VAR_DATEVALUEONLY )
152 {
153 /* Get the date information.
154 * It returns 0 if date information was
155 * present and 1 if only time information was present.
156 * -1 if an error occures.
157 */
158 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
159 {
160 /* Eliminate the time information since we
161 * were asked to get date information only.
162 */
163 pTm->tm_sec = 0;
164 pTm->tm_min = 0;
165 pTm->tm_hour = 0;
166 res = TRUE;
167 }
168 }
169 if( dwFlags & VAR_TIMEVALUEONLY )
170 {
171 /* Get time information only.
172 */
173 if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
174 {
175 res = TRUE;
176 }
177 }
178 else
179 {
180 /* Get both date and time information.
181 * It returns 0 if date information was
182 * present and 1 if only time information was present.
183 * -1 if an error occures.
184 */
185 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
186 {
187 res = TRUE;
188 }
189 }
190 }
191 }
192 HeapFree( GetProcessHeap(), 0, strDateTime );
193 }
194
195 return res;
196}
197
198
199
200
201
202
203/******************************************************************************
204 * TmToDATE [INTERNAL]
205 *
206 * The date is implemented using an 8 byte floating-point number.
207 * Days are represented by whole numbers increments starting with 0.00 has
208 * being December 30 1899, midnight.
209 * The hours are expressed as the fractional part of the number.
210 * December 30 1899 at midnight = 0.00
211 * January 1 1900 at midnight = 2.00
212 * January 4 1900 at 6 AM = 5.25
213 * January 4 1900 at noon = 5.50
214 * December 29 1899 at midnight = -1.00
215 * December 18 1899 at midnight = -12.00
216 * December 18 1899 at 6AM = -12.25
217 * December 18 1899 at 6PM = -12.75
218 * December 19 1899 at midnight = -11.00
219 * The tm structure is as follows:
220 * struct tm {
221 * int tm_sec; seconds after the minute - [0,59]
222 * int tm_min; minutes after the hour - [0,59]
223 * int tm_hour; hours since midnight - [0,23]
224 * int tm_mday; day of the month - [1,31]
225 * int tm_mon; months since January - [0,11]
226 * int tm_year; years
227 * int tm_wday; days since Sunday - [0,6]
228 * int tm_yday; days since January 1 - [0,365]
229 * int tm_isdst; daylight savings time flag
230 * };
231 *
232 * Note: This function does not use the tm_wday, tm_yday, tm_wday,
233 * and tm_isdst fields of the tm structure. And only converts years
234 * after 1900.
235 *
236 * Returns TRUE if successful.
237 */
238static BOOL TmToDATE( struct tm* pTm, DATE *pDateOut )
239{
240 int leapYear = 0;
241
242 if( (pTm->tm_year - 1900) < 0 ) return FALSE;
243
244 /* Start at 1. This is the way DATE is defined.
245 * January 1, 1900 at Midnight is 1.00.
246 * January 1, 1900 at 6AM is 1.25.
247 * and so on.
248 */
249 *pDateOut = 1;
250
251 /* Add the number of days corresponding to
252 * tm_year.
253 */
254 *pDateOut += (pTm->tm_year - 1900) * 365;
255
256 /* Add the leap days in the previous years between now and 1900.
257 * Note a leap year is one that is a multiple of 4
258 * but not of a 100. Except if it is a multiple of
259 * 400 then it is a leap year.
260 */
261 *pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
262 *pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
263 *pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
264
265 /* Set the leap year flag if the
266 * current year specified by tm_year is a
267 * leap year. This will be used to add a day
268 * to the day count.
269 */
270 if( isleap( pTm->tm_year ) )
271 leapYear = 1;
272
273 /* Add the number of days corresponding to
274 * the month.
275 */
276 switch( pTm->tm_mon )
277 {
278 case 2:
279 *pDateOut += 31;
280 break;
281 case 3:
282 *pDateOut += ( 59 + leapYear );
283 break;
284 case 4:
285 *pDateOut += ( 90 + leapYear );
286 break;
287 case 5:
288 *pDateOut += ( 120 + leapYear );
289 break;
290 case 6:
291 *pDateOut += ( 151 + leapYear );
292 break;
293 case 7:
294 *pDateOut += ( 181 + leapYear );
295 break;
296 case 8:
297 *pDateOut += ( 212 + leapYear );
298 break;
299 case 9:
300 *pDateOut += ( 243 + leapYear );
301 break;
302 case 10:
303 *pDateOut += ( 273 + leapYear );
304 break;
305 case 11:
306 *pDateOut += ( 304 + leapYear );
307 break;
308 case 12:
309 *pDateOut += ( 334 + leapYear );
310 break;
311 }
312 /* Add the number of days in this month.
313 */
314 *pDateOut += pTm->tm_mday;
315
316 /* Add the number of seconds, minutes, and hours
317 * to the DATE. Note these are the fracionnal part
318 * of the DATE so seconds / number of seconds in a day.
319 */
320 *pDateOut += pTm->tm_hour / 24.0;
321 *pDateOut += pTm->tm_min / 1440.0;
322 *pDateOut += pTm->tm_sec / 86400.0;
323 return TRUE;
324}
325
326/******************************************************************************
327 * DateToTm [INTERNAL]
328 *
329 * This function converts a windows DATE to a tm structure.
330 *
331 * It does not fill all the fields of the tm structure.
332 * Here is a list of the fields that are filled:
333 * tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
334 *
335 * Note this function does not support dates before the January 1, 1900
336 * or ( dateIn < 2.0 ).
337 *
338 * Returns TRUE if successful.
339 */
340static BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )
341{
342 double decimalPart = 0.0;
343 double wholePart = 0.0;
344
345 /* Do not process dates smaller than January 1, 1900.
346 * Which corresponds to 2.0 in the windows DATE format.
347 */
348 if( dateIn < 2.0 ) return FALSE;
349
350 memset(pTm,0,sizeof(*pTm));
351
352 /* Because of the nature of DATE format which
353 * associates 2.0 to January 1, 1900. We will
354 * remove 1.0 from the whole part of the DATE
355 * so that in the following code 1.0
356 * will correspond to January 1, 1900.
357 * This simplifies the processing of the DATE value.
358 */
359 dateIn -= 1.0;
360
361 wholePart = (double) floor( dateIn );
362 decimalPart = fmod( dateIn, wholePart );
363
364 if( !(dwFlags & VAR_TIMEVALUEONLY) )
365 {
366 int nDay = 0;
367 int leapYear = 0;
368 double yearsSince1900 = 0;
369 /* Start at 1900, this is where the DATE time 0.0 starts.
370 */
371 pTm->tm_year = 1900;
372 /* find in what year the day in the "wholePart" falls into.
373 * add the value to the year field.
374 */
375 yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 );
376 pTm->tm_year += yearsSince1900;
377 /* determine if this is a leap year.
378 */
379 if( isleap( pTm->tm_year ) )
380 {
381 leapYear = 1;
382 wholePart++;
383 }
384
385 /* find what day of that year the "wholePart" corresponds to.
386 * Note: nDay is in [1-366] format
387 */
388 nDay = (int) ( wholePart - floor( yearsSince1900 * DAYS_IN_ONE_YEAR ) );
389 /* Set the tm_yday value.
390 * Note: The day must be converted from [1-366] to [0-365]
391 */
392 /*pTm->tm_yday = nDay - 1;*/
393 /* find which month this day corresponds to.
394 */
395 if( nDay <= 31 )
396 {
397 pTm->tm_mday = nDay;
398 pTm->tm_mon = 0;
399 }
400 else if( nDay <= ( 59 + leapYear ) )
401 {
402 pTm->tm_mday = nDay - 31;
403 pTm->tm_mon = 1;
404 }
405 else if( nDay <= ( 90 + leapYear ) )
406 {
407 pTm->tm_mday = nDay - ( 59 + leapYear );
408 pTm->tm_mon = 2;
409 }
410 else if( nDay <= ( 120 + leapYear ) )
411 {
412 pTm->tm_mday = nDay - ( 90 + leapYear );
413 pTm->tm_mon = 3;
414 }
415 else if( nDay <= ( 151 + leapYear ) )
416 {
417 pTm->tm_mday = nDay - ( 120 + leapYear );
418 pTm->tm_mon = 4;
419 }
420 else if( nDay <= ( 181 + leapYear ) )
421 {
422 pTm->tm_mday = nDay - ( 151 + leapYear );
423 pTm->tm_mon = 5;
424 }
425 else if( nDay <= ( 212 + leapYear ) )
426 {
427 pTm->tm_mday = nDay - ( 181 + leapYear );
428 pTm->tm_mon = 6;
429 }
430 else if( nDay <= ( 243 + leapYear ) )
431 {
432 pTm->tm_mday = nDay - ( 212 + leapYear );
433 pTm->tm_mon = 7;
434 }
435 else if( nDay <= ( 273 + leapYear ) )
436 {
437 pTm->tm_mday = nDay - ( 243 + leapYear );
438 pTm->tm_mon = 8;
439 }
440 else if( nDay <= ( 304 + leapYear ) )
441 {
442 pTm->tm_mday = nDay - ( 273 + leapYear );
443 pTm->tm_mon = 9;
444 }
445 else if( nDay <= ( 334 + leapYear ) )
446 {
447 pTm->tm_mday = nDay - ( 304 + leapYear );
448 pTm->tm_mon = 10;
449 }
450 else if( nDay <= ( 365 + leapYear ) )
451 {
452 pTm->tm_mday = nDay - ( 334 + leapYear );
453 pTm->tm_mon = 11;
454 }
455 }
456 if( !(dwFlags & VAR_DATEVALUEONLY) )
457 {
458 /* find the number of seconds in this day.
459 * fractional part times, hours, minutes, seconds.
460 */
461 pTm->tm_hour = (int) ( decimalPart * 24 );
462 pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
463 pTm->tm_sec = (int) ( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 );
464 }
465 return TRUE;
466}
467
468
469
470/******************************************************************************
471 * SizeOfVariantData [INTERNAL]
472 *
473 * This function finds the size of the data referenced by a Variant based
474 * the type "vt" of the Variant.
475 */
476static int SizeOfVariantData( VARIANT* parg )
477{
478 int size = 0;
479 switch( V_VT(parg) & VT_TYPEMASK )
480 {
481 case( VT_I2 ):
482 size = sizeof(short);
483 break;
484 case( VT_INT ):
485 size = sizeof(int);
486 break;
487 case( VT_I4 ):
488 size = sizeof(long);
489 break;
490 case( VT_UI1 ):
491 size = sizeof(BYTE);
492 break;
493 case( VT_UI2 ):
494 size = sizeof(unsigned short);
495 break;
496 case( VT_UINT ):
497 size = sizeof(unsigned int);
498 break;
499 case( VT_UI4 ):
500 size = sizeof(unsigned long);
501 break;
502 case( VT_R4 ):
503 size = sizeof(float);
504 break;
505 case( VT_R8 ):
506 size = sizeof(double);
507 break;
508 case( VT_DATE ):
509 size = sizeof(DATE);
510 break;
511 case( VT_BOOL ):
512 size = sizeof(VARIANT_BOOL);
513 break;
514 case( VT_BSTR ):
515 size = sizeof(void*);
516 break;
517 case( VT_CY ):
518 case( VT_DISPATCH ):
519 case( VT_UNKNOWN ):
520 case( VT_DECIMAL ):
521 default:
522 FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK );
523 break;
524 }
525
526 return size;
527}
528/******************************************************************************
529 * StringDupAtoBstr [INTERNAL]
530 *
531 */
532static BSTR StringDupAtoBstr( char* strIn )
533{
534 BSTR bstr = NULL;
535 OLECHAR* pNewString = NULL;
536 pNewString = HEAP_strdupAtoW( GetProcessHeap(), 0, strIn );
537 bstr = SysAllocString( pNewString );
538 HeapFree( GetProcessHeap(), 0, pNewString );
539 return bstr;
540}
541
542/******************************************************************************
543 * round [INTERNAL]
544 *
545 * Round the double value to the nearest integer value.
546 */
547static double round( double d )
548{
549 double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
550 BOOL bEvenNumber = FALSE;
551 int nSign = 0;
552
553 /* Save the sign of the number
554 */
555 nSign = (d >= 0.0) ? 1 : -1;
556 d = fabs( d );
557
558 /* Remove the decimals.
559 */
560 integerValue = floor( d );
561
562 /* Set the Even flag. This is used to round the number when
563 * the decimals are exactly 1/2. If the integer part is
564 * odd the number is rounded up. If the integer part
565 * is even the number is rounded down. Using this method
566 * numbers are rounded up|down half the time.
567 */
568 bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
569
570 /* Remove the integral part of the number.
571 */
572 decimals = d - integerValue;
573
574 /* Note: Ceil returns the smallest integer that is greater that x.
575 * and floor returns the largest integer that is less than or equal to x.
576 */
577 if( decimals > 0.5 )
578 {
579 /* If the decimal part is greater than 1/2
580 */
581 roundedValue = ceil( d );
582 }
583 else if( decimals < 0.5 )
584 {
585 /* If the decimal part is smaller than 1/2
586 */
587 roundedValue = floor( d );
588 }
589 else
590 {
591 /* the decimals are exactly 1/2 so round according to
592 * the bEvenNumber flag.
593 */
594 if( bEvenNumber )
595 {
596 roundedValue = floor( d );
597 }
598 else
599 {
600 roundedValue = ceil( d );
601 }
602 }
603
604 return roundedValue * nSign;
605}
606
607/******************************************************************************
608 * RemoveCharacterFromString [INTERNAL]
609 *
610 * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
611 */
612static void RemoveCharacterFromString( LPSTR str, LPSTR strOfCharToRemove )
613{
614 LPSTR pNewString = NULL;
615 LPSTR strToken = NULL;
616
617 /* Check if we have a valid argument
618 */
619 if( str != NULL )
620 {
621 pNewString = strdup( str );
622 str[0] = '\0';
623 strToken = strtok( pNewString, strOfCharToRemove );
624 while( strToken != NULL ) {
625 strcat( str, strToken );
626 strToken = strtok( NULL, strOfCharToRemove );
627 }
628 free( pNewString );
629 }
630 return;
631}
632
633/******************************************************************************
634 * GetValidRealString [INTERNAL]
635 *
636 * Checks if the string is of proper format to be converted to a real value.
637 */
638static BOOL IsValidRealString( LPSTR strRealString )
639{
640 /* Real values that have a decimal point are required to either have
641 * digits before or after the decimal point. We will assume that
642 * we do not have any digits at either position. If we do encounter
643 * some we will disable this flag.
644 */
645 BOOL bDigitsRequired = TRUE;
646 /* Processed fields in the string representation of the real number.
647 */
648 BOOL bWhiteSpaceProcessed = FALSE;
649 BOOL bFirstSignProcessed = FALSE;
650 BOOL bFirstDigitsProcessed = FALSE;
651 BOOL bDecimalPointProcessed = FALSE;
652 BOOL bSecondDigitsProcessed = FALSE;
653 BOOL bExponentProcessed = FALSE;
654 BOOL bSecondSignProcessed = FALSE;
655 BOOL bThirdDigitsProcessed = FALSE;
656 /* Assume string parameter "strRealString" is valid and try to disprove it.
657 */
658 BOOL bValidRealString = TRUE;
659
660 /* Used to count the number of tokens in the "strRealString".
661 */
662 LPSTR strToken = NULL;
663 int nTokens = 0;
664 LPSTR pChar = NULL;
665
666 /* Check if we have a valid argument
667 */
668 if( strRealString == NULL )
669 {
670 bValidRealString = FALSE;
671 }
672
673 if( bValidRealString == TRUE )
674 {
675 /* Make sure we only have ONE token in the string.
676 */
677 strToken = strtok( strRealString, " " );
678 while( strToken != NULL ) {
679 nTokens++;
680 strToken = strtok( NULL, " " );
681 }
682
683 if( nTokens != 1 )
684 {
685 bValidRealString = FALSE;
686 }
687 }
688
689
690 /* Make sure this token contains only valid characters.
691 * The string argument to atof has the following form:
692 * [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
693 * Whitespace consists of space and|or <TAB> characters, which are ignored.
694 * Sign is either plus '+' or minus '-'.
695 * Digits are one or more decimal digits.
696 * Note: If no digits appear before the decimal point, at least one must
697 * appear after the decimal point.
698 * The decimal digits may be followed by an exponent.
699 * An Exponent consists of an introductory letter ( D, d, E, or e) and
700 * an optionally signed decimal integer.
701 */
702 pChar = strRealString;
703 while( bValidRealString == TRUE && *pChar != '\0' )
704 {
705 switch( *pChar )
706 {
707 /* If whitespace...
708 */
709 case ' ':
710 case '\t':
711 if( bWhiteSpaceProcessed ||
712 bFirstSignProcessed ||
713 bFirstDigitsProcessed ||
714 bDecimalPointProcessed ||
715 bSecondDigitsProcessed ||
716 bExponentProcessed ||
717 bSecondSignProcessed ||
718 bThirdDigitsProcessed )
719 {
720 bValidRealString = FALSE;
721 }
722 break;
723 /* If sign...
724 */
725 case '+':
726 case '-':
727 if( bFirstSignProcessed == FALSE )
728 {
729 if( bFirstDigitsProcessed ||
730 bDecimalPointProcessed ||
731 bSecondDigitsProcessed ||
732 bExponentProcessed ||
733 bSecondSignProcessed ||
734 bThirdDigitsProcessed )
735 {
736 bValidRealString = FALSE;
737 }
738 bWhiteSpaceProcessed = TRUE;
739 bFirstSignProcessed = TRUE;
740 }
741 else if( bSecondSignProcessed == FALSE )
742 {
743 /* Note: The exponent must be present in
744 * order to accept the second sign...
745 */
746 if( bExponentProcessed == FALSE ||
747 bThirdDigitsProcessed ||
748 bDigitsRequired )
749 {
750 bValidRealString = FALSE;
751 }
752 bFirstSignProcessed = TRUE;
753 bWhiteSpaceProcessed = TRUE;
754 bFirstDigitsProcessed = TRUE;
755 bDecimalPointProcessed = TRUE;
756 bSecondDigitsProcessed = TRUE;
757 bSecondSignProcessed = TRUE;
758 }
759 break;
760
761 /* If decimals...
762 */
763 case '0':
764 case '1':
765 case '2':
766 case '3':
767 case '4':
768 case '5':
769 case '6':
770 case '7':
771 case '8':
772 case '9':
773 if( bFirstDigitsProcessed == FALSE )
774 {
775 if( bDecimalPointProcessed ||
776 bSecondDigitsProcessed ||
777 bExponentProcessed ||
778 bSecondSignProcessed ||
779 bThirdDigitsProcessed )
780 {
781 bValidRealString = FALSE;
782 }
783 bFirstSignProcessed = TRUE;
784 bWhiteSpaceProcessed = TRUE;
785 /* We have found some digits before the decimal point
786 * so disable the "Digits required" flag.
787 */
788 bDigitsRequired = FALSE;
789 }
790 else if( bSecondDigitsProcessed == FALSE )
791 {
792 if( bExponentProcessed ||
793 bSecondSignProcessed ||
794 bThirdDigitsProcessed )
795 {
796 bValidRealString = FALSE;
797 }
798 bFirstSignProcessed = TRUE;
799 bWhiteSpaceProcessed = TRUE;
800 bFirstDigitsProcessed = TRUE;
801 bDecimalPointProcessed = TRUE;
802 /* We have found some digits after the decimal point
803 * so disable the "Digits required" flag.
804 */
805 bDigitsRequired = FALSE;
806 }
807 else if( bThirdDigitsProcessed == FALSE )
808 {
809 /* Getting here means everything else should be processed.
810 * If we get anything else than a decimal following this
811 * digit it will be flagged by the other cases, so
812 * we do not really need to do anything in here.
813 */
814 }
815 break;
816 /* If DecimalPoint...
817 */
818 case '.':
819 if( bDecimalPointProcessed ||
820 bSecondDigitsProcessed ||
821 bExponentProcessed ||
822 bSecondSignProcessed ||
823 bThirdDigitsProcessed )
824 {
825 bValidRealString = FALSE;
826 }
827 bFirstSignProcessed = TRUE;
828 bWhiteSpaceProcessed = TRUE;
829 bFirstDigitsProcessed = TRUE;
830 bDecimalPointProcessed = TRUE;
831 break;
832 /* If Exponent...
833 */
834 case 'e':
835 case 'E':
836 case 'd':
837 case 'D':
838 if( bExponentProcessed ||
839 bSecondSignProcessed ||
840 bThirdDigitsProcessed ||
841 bDigitsRequired )
842 {
843 bValidRealString = FALSE;
844 }
845 bFirstSignProcessed = TRUE;
846 bWhiteSpaceProcessed = TRUE;
847 bFirstDigitsProcessed = TRUE;
848 bDecimalPointProcessed = TRUE;
849 bSecondDigitsProcessed = TRUE;
850 bExponentProcessed = TRUE;
851 break;
852 default:
853 bValidRealString = FALSE;
854 break;
855 }
856 /* Process next character.
857 */
858 pChar++;
859 }
860
861 /* If the required digits were not present we have an invalid
862 * string representation of a real number.
863 */
864 if( bDigitsRequired == TRUE )
865 {
866 bValidRealString = FALSE;
867 }
868
869 return bValidRealString;
870}
871
872
873/******************************************************************************
874 * Coerce [INTERNAL]
875 *
876 * This function dispatches execution to the proper conversion API
877 * to do the necessary coercion.
878 *
879 * FIXME: Passing down dwFlags to the conversion functions is wrong, this
880 * is a different flagmask. Check MSDN.
881 */
882static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
883{
884 HRESULT res = S_OK;
885 unsigned short vtFrom = 0;
886 vtFrom = V_VT(ps) & VT_TYPEMASK;
887
888
889 /* Note: Since "long" and "int" values both have 4 bytes and are
890 * both signed integers "int" will be treated as "long" in the
891 * following code.
892 * The same goes for their unsigned versions.
893 */
894
895 /* Trivial Case: If the coercion is from two types that are
896 * identical then we can blindly copy from one argument to another.*/
897 if ((vt==vtFrom))
898 {
899 return VariantCopy(pd,ps);
900 }
901
902 /* Cases requiring thought*/
903 switch( vt )
904 {
905
906 case( VT_EMPTY ):
907 res = VariantClear( pd );
908 break;
909 case( VT_NULL ):
910 res = VariantClear( pd );
911 if( res == S_OK )
912 {
913 V_VT(pd) = VT_NULL;
914 }
915 break;
916 case( VT_I1 ):
917 switch( vtFrom )
918 {
919 case( VT_I1 ):
920 res = VariantCopy( pd, ps );
921 break;
922 case( VT_I2 ):
923 res = VarI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,cVal) );
924 break;
925 case( VT_INT ):
926 case( VT_I4 ):
927 res = VarI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,cVal) );
928 break;
929 case( VT_UI1 ):
930 res = VarI1FromUI1( V_UNION(ps,bVal), &V_UNION(pd,cVal) );
931 break;
932 case( VT_UI2 ):
933 res = VarI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cVal) );
934 break;
935 case( VT_UINT ):
936 case( VT_UI4 ):
937 res = VarI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cVal) );
938 break;
939 case( VT_R4 ):
940 res = VarI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,cVal) );
941 break;
942 case( VT_R8 ):
943 res = VarI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,cVal) );
944 break;
945 case( VT_DATE ):
946 res = VarI1FromDate( V_UNION(ps,date), &V_UNION(pd,cVal) );
947 break;
948 case( VT_BOOL ):
949 res = VarI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,cVal) );
950 break;
951 case( VT_BSTR ):
952 res = VarI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cVal) );
953 break;
954 case( VT_CY ):
955 res = VarI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,cVal) );
956 break;
957 case( VT_DISPATCH ):
958 /*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
959 case( VT_DECIMAL ):
960 /*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
961 case( VT_UNKNOWN ):
962 default:
963 res = DISP_E_TYPEMISMATCH;
964 FIXME("Coercion from %d to %d\n", vtFrom, vt );
965 break;
966 }
967 break;
968
969 case( VT_I2 ):
970 switch( vtFrom )
971 {
972 case( VT_I1 ):
973 res = VarI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,iVal) );
974 break;
975 case( VT_I2 ):
976 res = VariantCopy( pd, ps );
977 break;
978 case( VT_INT ):
979 case( VT_I4 ):
980 res = VarI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,iVal) );
981 break;
982 case( VT_UI1 ):
983 res = VarI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,iVal) );
984 break;
985 case( VT_UI2 ):
986 res = VarI2FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,iVal) );
987 break;
988 case( VT_UINT ):
989 case( VT_UI4 ):
990 res = VarI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,iVal) );
991 break;
992 case( VT_R4 ):
993 res = VarI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,iVal) );
994 break;
995 case( VT_R8 ):
996 res = VarI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,iVal) );
997 break;
998 case( VT_DATE ):
999 res = VarI2FromDate( V_UNION(ps,date), &V_UNION(pd,iVal) );
1000 break;
1001 case( VT_BOOL ):
1002 res = VarI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,iVal) );
1003 break;
1004 case( VT_BSTR ):
1005 res = VarI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,iVal) );
1006 break;
1007 case( VT_CY ):
1008 res = VarI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,iVal) );
1009 break;
1010 case( VT_DISPATCH ):
1011 /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
1012 case( VT_DECIMAL ):
1013 /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
1014 case( VT_UNKNOWN ):
1015 default:
1016 res = DISP_E_TYPEMISMATCH;
1017 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1018 break;
1019 }
1020 break;
1021
1022 case( VT_INT ):
1023 case( VT_I4 ):
1024 switch( vtFrom )
1025 {
1026 case( VT_I1 ):
1027 res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
1028 break;
1029 case( VT_I2 ):
1030 res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
1031 break;
1032 case( VT_INT ):
1033 case( VT_I4 ):
1034#ifdef __WIN32OS2__
1035 case( VT_HRESULT ):
1036#endif
1037 res = VariantCopy( pd, ps );
1038 break;
1039 case( VT_UI1 ):
1040 res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
1041 break;
1042 case( VT_UI2 ):
1043 res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
1044 break;
1045 case( VT_UINT ):
1046 case( VT_UI4 ):
1047 res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
1048 break;
1049 case( VT_R4 ):
1050 res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
1051 break;
1052 case( VT_R8 ):
1053 res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
1054 break;
1055 case( VT_DATE ):
1056 res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
1057 break;
1058 case( VT_BOOL ):
1059 res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
1060 break;
1061 case( VT_BSTR ):
1062 res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
1063 break;
1064 case( VT_CY ):
1065 res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
1066 break;
1067 case( VT_DISPATCH ):
1068 /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1069 case( VT_DECIMAL ):
1070 /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1071 case( VT_UNKNOWN ):
1072 default:
1073 res = DISP_E_TYPEMISMATCH;
1074 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1075 break;
1076 }
1077 break;
1078
1079 case( VT_UI1 ):
1080 switch( vtFrom )
1081 {
1082 case( VT_I1 ):
1083 res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
1084 break;
1085 case( VT_I2 ):
1086 res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
1087 break;
1088 case( VT_INT ):
1089 case( VT_I4 ):
1090 res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
1091 break;
1092 case( VT_UI1 ):
1093 res = VariantCopy( pd, ps );
1094 break;
1095 case( VT_UI2 ):
1096 res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
1097 break;
1098 case( VT_UINT ):
1099 case( VT_UI4 ):
1100 res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
1101 break;
1102 case( VT_R4 ):
1103 res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
1104 break;
1105 case( VT_R8 ):
1106 res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
1107 break;
1108 case( VT_DATE ):
1109 res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
1110 break;
1111 case( VT_BOOL ):
1112 res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
1113 break;
1114 case( VT_BSTR ):
1115 res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
1116 break;
1117 case( VT_CY ):
1118 res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
1119 break;
1120 case( VT_DISPATCH ):
1121 /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1122 case( VT_DECIMAL ):
1123 /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1124 case( VT_UNKNOWN ):
1125 default:
1126 res = DISP_E_TYPEMISMATCH;
1127 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1128 break;
1129 }
1130 break;
1131
1132 case( VT_UI2 ):
1133 switch( vtFrom )
1134 {
1135 case( VT_I1 ):
1136 res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
1137 break;
1138 case( VT_I2 ):
1139 res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
1140 break;
1141 case( VT_INT ):
1142 case( VT_I4 ):
1143 res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
1144 break;
1145 case( VT_UI1 ):
1146 res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
1147 break;
1148 case( VT_UI2 ):
1149 res = VariantCopy( pd, ps );
1150 break;
1151 case( VT_UINT ):
1152 case( VT_UI4 ):
1153 res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
1154 break;
1155 case( VT_R4 ):
1156 res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
1157 break;
1158 case( VT_R8 ):
1159 res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
1160 break;
1161 case( VT_DATE ):
1162 res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
1163 break;
1164 case( VT_BOOL ):
1165 res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
1166 break;
1167 case( VT_BSTR ):
1168 res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
1169 break;
1170 case( VT_CY ):
1171 res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
1172 break;
1173 case( VT_DISPATCH ):
1174 /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1175 case( VT_DECIMAL ):
1176 /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1177 case( VT_UNKNOWN ):
1178 default:
1179 res = DISP_E_TYPEMISMATCH;
1180 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1181 break;
1182 }
1183 break;
1184
1185 case( VT_UINT ):
1186 case( VT_UI4 ):
1187 switch( vtFrom )
1188 {
1189 case( VT_I1 ):
1190 res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
1191 break;
1192 case( VT_I2 ):
1193 res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
1194 break;
1195 case( VT_INT ):
1196 case( VT_I4 ):
1197 res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
1198 break;
1199 case( VT_UI1 ):
1200 res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
1201 break;
1202 case( VT_UI2 ):
1203 res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
1204 break;
1205 case( VT_UI4 ):
1206 res = VariantCopy( pd, ps );
1207 break;
1208 case( VT_R4 ):
1209 res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
1210 break;
1211 case( VT_R8 ):
1212 res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
1213 break;
1214 case( VT_DATE ):
1215 res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
1216 break;
1217 case( VT_BOOL ):
1218 res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
1219 break;
1220 case( VT_BSTR ):
1221 res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
1222 break;
1223 case( VT_CY ):
1224 res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
1225 break;
1226 case( VT_DISPATCH ):
1227 /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1228 case( VT_DECIMAL ):
1229 /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1230 case( VT_UNKNOWN ):
1231 default:
1232 res = DISP_E_TYPEMISMATCH;
1233 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1234 break;
1235 }
1236 break;
1237
1238 case( VT_R4 ):
1239 switch( vtFrom )
1240 {
1241 case( VT_I1 ):
1242 res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
1243 break;
1244 case( VT_I2 ):
1245 res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
1246 break;
1247 case( VT_INT ):
1248 case( VT_I4 ):
1249 res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
1250 break;
1251 case( VT_UI1 ):
1252 res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
1253 break;
1254 case( VT_UI2 ):
1255 res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
1256 break;
1257 case( VT_UINT ):
1258 case( VT_UI4 ):
1259 res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
1260 break;
1261 case( VT_R4 ):
1262 res = VariantCopy( pd, ps );
1263 break;
1264 case( VT_R8 ):
1265 res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
1266 break;
1267 case( VT_DATE ):
1268 res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
1269 break;
1270 case( VT_BOOL ):
1271 res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
1272 break;
1273 case( VT_BSTR ):
1274 res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
1275 break;
1276 case( VT_CY ):
1277 res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
1278 break;
1279 case( VT_DISPATCH ):
1280 /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1281 case( VT_DECIMAL ):
1282 /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1283 case( VT_UNKNOWN ):
1284 default:
1285 res = DISP_E_TYPEMISMATCH;
1286 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1287 break;
1288 }
1289 break;
1290
1291 case( VT_R8 ):
1292 switch( vtFrom )
1293 {
1294 case( VT_I1 ):
1295 res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
1296 break;
1297 case( VT_I2 ):
1298 res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
1299 break;
1300 case( VT_INT ):
1301 case( VT_I4 ):
1302 res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
1303 break;
1304 case( VT_UI1 ):
1305 res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
1306 break;
1307 case( VT_UI2 ):
1308 res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
1309 break;
1310 case( VT_UINT ):
1311 case( VT_UI4 ):
1312 res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
1313 break;
1314 case( VT_R4 ):
1315 res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
1316 break;
1317 case( VT_R8 ):
1318 res = VariantCopy( pd, ps );
1319 break;
1320 case( VT_DATE ):
1321 res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
1322 break;
1323 case( VT_BOOL ):
1324 res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
1325 break;
1326 case( VT_BSTR ):
1327 res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
1328 break;
1329 case( VT_CY ):
1330 res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
1331 break;
1332 case( VT_DISPATCH ):
1333 /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1334 case( VT_DECIMAL ):
1335 /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1336 case( VT_UNKNOWN ):
1337 default:
1338 res = DISP_E_TYPEMISMATCH;
1339 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1340 break;
1341 }
1342 break;
1343
1344 case( VT_DATE ):
1345 switch( vtFrom )
1346 {
1347 case( VT_I1 ):
1348 res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
1349 break;
1350 case( VT_I2 ):
1351 res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
1352 break;
1353 case( VT_INT ):
1354 res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
1355 break;
1356 case( VT_I4 ):
1357 res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
1358 break;
1359 case( VT_UI1 ):
1360 res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
1361 break;
1362 case( VT_UI2 ):
1363 res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
1364 break;
1365 case( VT_UINT ):
1366 res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
1367 break;
1368 case( VT_UI4 ):
1369 res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
1370 break;
1371 case( VT_R4 ):
1372 res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
1373 break;
1374 case( VT_R8 ):
1375 res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
1376 break;
1377 case( VT_DATE ):
1378 res = VariantCopy( pd, ps );
1379 break;
1380 case( VT_BOOL ):
1381 res = VarDateFromBool( V_UNION(ps,boolVal), &V_UNION(pd,date) );
1382 break;
1383 case( VT_BSTR ):
1384 res = VarDateFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,date) );
1385 break;
1386 case( VT_CY ):
1387 res = VarDateFromCy( V_UNION(ps,cyVal), &V_UNION(pd,date) );
1388 break;
1389 case( VT_DISPATCH ):
1390 /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1391 case( VT_DECIMAL ):
1392 /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1393 case( VT_UNKNOWN ):
1394 default:
1395 res = DISP_E_TYPEMISMATCH;
1396 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1397 break;
1398 }
1399 break;
1400
1401 case( VT_BOOL ):
1402 switch( vtFrom )
1403 {
1404 case( VT_I1 ):
1405 res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
1406 break;
1407 case( VT_I2 ):
1408 res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
1409 break;
1410 case( VT_INT ):
1411 res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
1412 break;
1413 case( VT_I4 ):
1414 res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
1415 break;
1416 case( VT_UI1 ):
1417 res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
1418 break;
1419 case( VT_UI2 ):
1420 res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
1421 break;
1422 case( VT_UINT ):
1423 res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
1424 break;
1425 case( VT_UI4 ):
1426 res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
1427 break;
1428 case( VT_R4 ):
1429 res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
1430 break;
1431 case( VT_R8 ):
1432 res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
1433 break;
1434 case( VT_DATE ):
1435 res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
1436 break;
1437 case( VT_BOOL ):
1438 res = VariantCopy( pd, ps );
1439 break;
1440 case( VT_BSTR ):
1441 res = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
1442 break;
1443 case( VT_CY ):
1444 res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
1445 break;
1446 case( VT_DISPATCH ):
1447 /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1448 case( VT_DECIMAL ):
1449 /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1450 case( VT_UNKNOWN ):
1451 default:
1452 res = DISP_E_TYPEMISMATCH;
1453 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1454 break;
1455 }
1456 break;
1457
1458 case( VT_BSTR ):
1459 switch( vtFrom )
1460 {
1461 case( VT_EMPTY ):
1462 if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
1463 res = S_OK;
1464 else
1465 res = E_OUTOFMEMORY;
1466 break;
1467 case( VT_I1 ):
1468 res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
1469 break;
1470 case( VT_I2 ):
1471 res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
1472 break;
1473 case( VT_INT ):
1474 res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
1475 break;
1476 case( VT_I4 ):
1477 res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
1478 break;
1479 case( VT_UI1 ):
1480 res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
1481 break;
1482 case( VT_UI2 ):
1483 res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
1484 break;
1485 case( VT_UINT ):
1486 res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
1487 break;
1488 case( VT_UI4 ):
1489 res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
1490 break;
1491 case( VT_R4 ):
1492 res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
1493 break;
1494 case( VT_R8 ):
1495 res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
1496 break;
1497 case( VT_DATE ):
1498 res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
1499 break;
1500 case( VT_BOOL ):
1501 res = VarBstrFromBool( V_UNION(ps,boolVal), lcid, 0, &V_UNION(pd,bstrVal) );
1502 break;
1503 case( VT_BSTR ):
1504 res = VariantCopy( pd, ps );
1505 break;
1506 case( VT_CY ):
1507 res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
1508 break;
1509 case( VT_DISPATCH ):
1510 /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1511 case( VT_DECIMAL ):
1512 /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1513 case( VT_UNKNOWN ):
1514 default:
1515 res = DISP_E_TYPEMISMATCH;
1516 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1517 break;
1518 }
1519 break;
1520
1521 case( VT_CY ):
1522 switch( vtFrom )
1523 {
1524 case( VT_I1 ):
1525 res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
1526 break;
1527 case( VT_I2 ):
1528 res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
1529 break;
1530 case( VT_INT ):
1531 res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
1532 break;
1533 case( VT_I4 ):
1534 res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
1535 break;
1536 case( VT_UI1 ):
1537 res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
1538 break;
1539 case( VT_UI2 ):
1540 res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
1541 break;
1542 case( VT_UINT ):
1543 res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
1544 break;
1545 case( VT_UI4 ):
1546 res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
1547 break;
1548 case( VT_R4 ):
1549 res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
1550 break;
1551 case( VT_R8 ):
1552 res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
1553 break;
1554 case( VT_DATE ):
1555 res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1556 break;
1557 case( VT_BOOL ):
1558 res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1559 break;
1560 case( VT_CY ):
1561 res = VariantCopy( pd, ps );
1562 break;
1563 case( VT_BSTR ):
1564 res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
1565 break;
1566 case( VT_DISPATCH ):
1567 /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1568 case( VT_DECIMAL ):
1569 /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1570 break;
1571 case( VT_UNKNOWN ):
1572 default:
1573 res = DISP_E_TYPEMISMATCH;
1574 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1575 break;
1576 }
1577 break;
1578
1579 case( VT_UNKNOWN ):
1580 if (vtFrom == VT_DISPATCH)
1581 {
1582 res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1583 }
1584 else
1585 {
1586 res = DISP_E_TYPEMISMATCH;
1587 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1588 }
1589 break;
1590
1591 default:
1592 res = DISP_E_TYPEMISMATCH;
1593 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1594 break;
1595 }
1596
1597 return res;
1598}
1599
1600/******************************************************************************
1601 * ValidateVtRange [INTERNAL]
1602 *
1603 * Used internally by the hi-level Variant API to determine
1604 * if the vartypes are valid.
1605 */
1606static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
1607{
1608 /* if by value we must make sure it is in the
1609 * range of the valid types.
1610 */
1611 if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1612 {
1613 return DISP_E_BADVARTYPE;
1614 }
1615 return S_OK;
1616}
1617
1618
1619/******************************************************************************
1620 * ValidateVartype [INTERNAL]
1621 *
1622 * Used internally by the hi-level Variant API to determine
1623 * if the vartypes are valid.
1624 */
1625static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
1626{
1627 HRESULT res = S_OK;
1628
1629 /* check if we have a valid argument.
1630 */
1631 if( vt & VT_BYREF )
1632 {
1633 /* if by reference check that the type is in
1634 * the valid range and that it is not of empty or null type
1635 */
1636 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1637 ( vt & VT_TYPEMASK ) == VT_NULL ||
1638 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1639 {
1640 res = E_INVALIDARG;
1641 }
1642
1643 }
1644 else
1645 {
1646 res = ValidateVtRange( vt );
1647 }
1648
1649 return res;
1650}
1651
1652/******************************************************************************
1653 * ValidateVt [INTERNAL]
1654 *
1655 * Used internally by the hi-level Variant API to determine
1656 * if the vartypes are valid.
1657 */
1658static HRESULT WINAPI ValidateVt( VARTYPE vt )
1659{
1660 HRESULT res = S_OK;
1661
1662 /* check if we have a valid argument.
1663 */
1664 if( vt & VT_BYREF )
1665 {
1666 /* if by reference check that the type is in
1667 * the valid range and that it is not of empty or null type
1668 */
1669 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1670 ( vt & VT_TYPEMASK ) == VT_NULL ||
1671 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1672 {
1673 res = DISP_E_BADVARTYPE;
1674 }
1675
1676 }
1677 else
1678 {
1679 res = ValidateVtRange( vt );
1680 }
1681
1682 return res;
1683}
1684
1685
1686
1687
1688
1689/******************************************************************************
1690 * VariantInit [OLEAUT32.8]
1691 *
1692 * Initializes the Variant. Unlike VariantClear it does not interpret
1693 * the current contents of the Variant.
1694 */
1695void WINAPI VariantInit(VARIANTARG* pvarg)
1696{
1697 TRACE("(%p)\n",pvarg);
1698
1699 memset(pvarg, 0, sizeof (VARIANTARG));
1700 V_VT(pvarg) = VT_EMPTY;
1701
1702 return;
1703}
1704
1705/******************************************************************************
1706 * VariantClear [OLEAUT32.9]
1707 *
1708 * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
1709 * sets the wReservedX field to 0. The current contents of the VARIANT are
1710 * freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
1711 * released. If VT_ARRAY the array is freed.
1712 */
1713HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
1714{
1715 HRESULT res = S_OK;
1716 TRACE("(%p)\n",pvarg);
1717
1718 res = ValidateVariantType( V_VT(pvarg) );
1719 if( res == S_OK )
1720 {
1721 if( !( V_VT(pvarg) & VT_BYREF ) )
1722 {
1723 /*
1724 * The VT_ARRAY flag is a special case of a safe array.
1725 */
1726 if ( (V_VT(pvarg) & VT_ARRAY) != 0)
1727 {
1728 SafeArrayDestroy(V_UNION(pvarg,parray));
1729 }
1730 else
1731 {
1732 switch( V_VT(pvarg) & VT_TYPEMASK )
1733 {
1734 case( VT_BSTR ):
1735 SysFreeString( V_UNION(pvarg,bstrVal) );
1736 break;
1737 case( VT_DISPATCH ):
1738 if(V_UNION(pvarg,pdispVal)!=NULL)
1739 ICOM_CALL(Release,V_UNION(pvarg,pdispVal));
1740 break;
1741 case( VT_VARIANT ):
1742 VariantClear(V_UNION(pvarg,pvarVal));
1743 break;
1744 case( VT_UNKNOWN ):
1745 if(V_UNION(pvarg,punkVal)!=NULL)
1746 ICOM_CALL(Release,V_UNION(pvarg,punkVal));
1747 break;
1748 case( VT_SAFEARRAY ):
1749 SafeArrayDestroy(V_UNION(pvarg,parray));
1750 break;
1751 default:
1752 break;
1753 }
1754 }
1755 }
1756
1757 /*
1758 * Empty all the fields and mark the type as empty.
1759 */
1760 memset(pvarg, 0, sizeof (VARIANTARG));
1761 V_VT(pvarg) = VT_EMPTY;
1762 }
1763
1764 return res;
1765}
1766
1767/******************************************************************************
1768 * VariantCopy [OLEAUT32.10]
1769 *
1770 * Frees up the designation variant and makes a copy of the source.
1771 */
1772HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
1773{
1774 HRESULT res = S_OK;
1775
1776 TRACE("(%p, %p), vt=%d\n", pvargDest, pvargSrc, V_VT(pvargSrc));
1777
1778 res = ValidateVariantType( V_VT(pvargSrc) );
1779
1780 /* If the pointer are to the same variant we don't need
1781 * to do anything.
1782 */
1783 if( pvargDest != pvargSrc && res == S_OK )
1784 {
1785 res = VariantClear( pvargDest );
1786
1787 if( res == S_OK )
1788 {
1789 if( V_VT(pvargSrc) & VT_BYREF )
1790 {
1791 /* In the case of byreference we only need
1792 * to copy the pointer.
1793 */
1794 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1795 V_VT(pvargDest) = V_VT(pvargSrc);
1796 }
1797 else
1798 {
1799 /*
1800 * The VT_ARRAY flag is another way to designate a safe array.
1801 */
1802 if (V_VT(pvargSrc) & VT_ARRAY)
1803 {
1804 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1805 }
1806 else
1807 {
1808 /* In the case of by value we need to
1809 * copy the actual value. In the case of
1810 * VT_BSTR a copy of the string is made,
1811 * if VT_DISPATCH or VT_IUNKNOWN AddRef is
1812 * called to increment the object's reference count.
1813 */
1814 switch( V_VT(pvargSrc) & VT_TYPEMASK )
1815 {
1816 case( VT_BSTR ):
1817 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
1818 break;
1819 case( VT_DISPATCH ):
1820 V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
1821 if (V_UNION(pvargDest,pdispVal)!=NULL)
1822 ICOM_CALL(AddRef,V_UNION(pvargDest,pdispVal));
1823 break;
1824 case( VT_VARIANT ):
1825 VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
1826 break;
1827 case( VT_UNKNOWN ):
1828 V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
1829 if (V_UNION(pvargDest,pdispVal)!=NULL)
1830 ICOM_CALL(AddRef,V_UNION(pvargDest,punkVal));
1831 break;
1832 case( VT_SAFEARRAY ):
1833 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
1834 break;
1835 default:
1836 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
1837 break;
1838 }
1839 }
1840
1841 V_VT(pvargDest) = V_VT(pvargSrc);
1842 }
1843 }
1844 }
1845
1846 return res;
1847}
1848
1849
1850/******************************************************************************
1851 * VariantCopyInd [OLEAUT32.11]
1852 *
1853 * Frees up the destination variant and makes a copy of the source. If
1854 * the source is of type VT_BYREF it performs the necessary indirections.
1855 */
1856HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
1857{
1858 HRESULT res = S_OK;
1859
1860 TRACE("(%p, %p)\n", pvargDest, pvargSrc);
1861
1862 res = ValidateVariantType( V_VT(pvargSrc) );
1863
1864 if( res != S_OK )
1865 return res;
1866
1867 if( V_VT(pvargSrc) & VT_BYREF )
1868 {
1869 VARIANTARG varg;
1870 VariantInit( &varg );
1871
1872 /* handle the in place copy.
1873 */
1874 if( pvargDest == pvargSrc )
1875 {
1876 /* we will use a copy of the source instead.
1877 */
1878 res = VariantCopy( &varg, pvargSrc );
1879 pvargSrc = &varg;
1880 }
1881
1882 if( res == S_OK )
1883 {
1884 res = VariantClear( pvargDest );
1885
1886 if( res == S_OK )
1887 {
1888 /*
1889 * The VT_ARRAY flag is another way to designate a safearray variant.
1890 */
1891 if ( V_VT(pvargSrc) & VT_ARRAY)
1892 {
1893 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
1894 }
1895 else
1896 {
1897 /* In the case of by reference we need
1898 * to copy the date pointed to by the variant.
1899 */
1900
1901 /* Get the variant type.
1902 */
1903 switch( V_VT(pvargSrc) & VT_TYPEMASK )
1904 {
1905 case( VT_BSTR ):
1906 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
1907 break;
1908 case( VT_DISPATCH ):
1909 break;
1910 case( VT_VARIANT ):
1911 {
1912 /* Prevent from cycling. According to tests on
1913 * VariantCopyInd in Windows and the documentation
1914 * this API dereferences the inner Variants to only one depth.
1915 * If the inner Variant itself contains an
1916 * other inner variant the E_INVALIDARG error is
1917 * returned.
1918 */
1919 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
1920 {
1921 /* If we get here we are attempting to deference
1922 * an inner variant that that is itself contained
1923 * in an inner variant so report E_INVALIDARG error.
1924 */
1925 res = E_INVALIDARG;
1926 }
1927 else
1928 {
1929 /* Set the processing inner variant flag.
1930 * We will set this flag in the inner variant
1931 * that will be passed to the VariantCopyInd function.
1932 */
1933 (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
1934
1935 /* Dereference the inner variant.
1936 */
1937 res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
1938 /* We must also copy its type, I think.
1939 */
1940 V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
1941 }
1942 }
1943 break;
1944 case( VT_UNKNOWN ):
1945 break;
1946 case( VT_SAFEARRAY ):
1947 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
1948 break;
1949 default:
1950 /* This is a by reference Variant which means that the union
1951 * part of the Variant contains a pointer to some data of
1952 * type "V_VT(pvargSrc) & VT_TYPEMASK".
1953 * We will deference this data in a generic fashion using
1954 * the void pointer "Variant.u.byref".
1955 * We will copy this data into the union of the destination
1956 * Variant.
1957 */
1958 memcpy( &pvargDest->n1.n2, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
1959 break;
1960 }
1961 }
1962
1963 V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
1964 }
1965 }
1966
1967 /* this should not fail.
1968 */
1969 VariantClear( &varg );
1970 }
1971 else
1972 {
1973 res = VariantCopy( pvargDest, pvargSrc );
1974 }
1975
1976 return res;
1977}
1978
1979/******************************************************************************
1980 * VariantChangeType [OLEAUT32.12]
1981 */
1982HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
1983 USHORT wFlags, VARTYPE vt)
1984{
1985 return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
1986}
1987
1988/******************************************************************************
1989 * VariantChangeTypeEx [OLEAUT32.147]
1990 */
1991HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
1992 LCID lcid, USHORT wFlags, VARTYPE vt)
1993{
1994 HRESULT res = S_OK;
1995 VARIANTARG varg;
1996 VariantInit( &varg );
1997
1998 TRACE("(%p, %p, %ld, %u, %u) vt=%d\n", pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
1999
2000 /* validate our source argument.
2001 */
2002 res = ValidateVariantType( V_VT(pvargSrc) );
2003
2004 /* validate the vartype.
2005 */
2006 if( res == S_OK )
2007 {
2008 res = ValidateVt( vt );
2009 }
2010
2011 /* if we are doing an in-place conversion make a copy of the source.
2012 */
2013 if( res == S_OK && pvargDest == pvargSrc )
2014 {
2015 res = VariantCopy( &varg, pvargSrc );
2016 pvargSrc = &varg;
2017 }
2018
2019 if( res == S_OK )
2020 {
2021 /* free up the destination variant.
2022 */
2023 res = VariantClear( pvargDest );
2024 }
2025
2026 if( res == S_OK )
2027 {
2028 if( V_VT(pvargSrc) & VT_BYREF )
2029 {
2030 /* Convert the source variant to a "byvalue" variant.
2031 */
2032 VARIANTARG Variant;
2033 VariantInit( &Variant );
2034 res = VariantCopyInd( &Variant, pvargSrc );
2035 if( res == S_OK )
2036 {
2037 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2038 /* this should not fail.
2039 */
2040 VariantClear( &Variant );
2041 }
2042
2043 }
2044 else
2045 {
2046 /* Use the current "byvalue" source variant.
2047 */
2048 res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2049 }
2050 }
2051 /* this should not fail.
2052 */
2053 VariantClear( &varg );
2054
2055 /* set the type of the destination
2056 */
2057 if ( res == S_OK )
2058 V_VT(pvargDest) = vt;
2059
2060 return res;
2061}
2062
2063
2064
2065
2066/******************************************************************************
2067 * VarUI1FromI2 [OLEAUT32.130]
2068 */
2069HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2070{
2071 TRACE("( %d, %p ), stub\n", sIn, pbOut );
2072
2073 /* Check range of value.
2074 */
2075 if( sIn < UI1_MIN || sIn > UI1_MAX )
2076 {
2077 return DISP_E_OVERFLOW;
2078 }
2079
2080 *pbOut = (BYTE) sIn;
2081
2082 return S_OK;
2083}
2084
2085/******************************************************************************
2086 * VarUI1FromI4 [OLEAUT32.131]
2087 */
2088HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2089{
2090 TRACE("( %ld, %p ), stub\n", lIn, pbOut );
2091
2092 /* Check range of value.
2093 */
2094 if( lIn < UI1_MIN || lIn > UI1_MAX )
2095 {
2096 return DISP_E_OVERFLOW;
2097 }
2098
2099 *pbOut = (BYTE) lIn;
2100
2101 return S_OK;
2102}
2103
2104
2105/******************************************************************************
2106 * VarUI1FromR4 [OLEAUT32.132]
2107 */
2108HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2109{
2110 TRACE("( %f, %p ), stub\n", fltIn, pbOut );
2111
2112 /* Check range of value.
2113 */
2114 fltIn = round( fltIn );
2115 if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2116 {
2117 return DISP_E_OVERFLOW;
2118 }
2119
2120 *pbOut = (BYTE) fltIn;
2121
2122 return S_OK;
2123}
2124
2125/******************************************************************************
2126 * VarUI1FromR8 [OLEAUT32.133]
2127 */
2128HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2129{
2130 TRACE("( %f, %p ), stub\n", dblIn, pbOut );
2131
2132 /* Check range of value.
2133 */
2134 dblIn = round( dblIn );
2135 if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2136 {
2137 return DISP_E_OVERFLOW;
2138 }
2139
2140 *pbOut = (BYTE) dblIn;
2141
2142 return S_OK;
2143}
2144
2145/******************************************************************************
2146 * VarUI1FromDate [OLEAUT32.135]
2147 */
2148HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2149{
2150 TRACE("( %f, %p ), stub\n", dateIn, pbOut );
2151
2152 /* Check range of value.
2153 */
2154 dateIn = round( dateIn );
2155 if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2156 {
2157 return DISP_E_OVERFLOW;
2158 }
2159
2160 *pbOut = (BYTE) dateIn;
2161
2162 return S_OK;
2163}
2164
2165/******************************************************************************
2166 * VarUI1FromBool [OLEAUT32.138]
2167 */
2168HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2169{
2170 TRACE("( %d, %p ), stub\n", boolIn, pbOut );
2171
2172 *pbOut = (BYTE) boolIn;
2173
2174 return S_OK;
2175}
2176
2177/******************************************************************************
2178 * VarUI1FromI1 [OLEAUT32.237]
2179 */
2180HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
2181{
2182 TRACE("( %c, %p ), stub\n", cIn, pbOut );
2183
2184 *pbOut = cIn;
2185
2186 return S_OK;
2187}
2188
2189/******************************************************************************
2190 * VarUI1FromUI2 [OLEAUT32.238]
2191 */
2192HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2193{
2194 TRACE("( %d, %p ), stub\n", uiIn, pbOut );
2195
2196 /* Check range of value.
2197 */
2198 if( uiIn > UI1_MAX )
2199 {
2200 return DISP_E_OVERFLOW;
2201 }
2202
2203 *pbOut = (BYTE) uiIn;
2204
2205 return S_OK;
2206}
2207
2208/******************************************************************************
2209 * VarUI1FromUI4 [OLEAUT32.239]
2210 */
2211HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2212{
2213 TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
2214
2215 /* Check range of value.
2216 */
2217 if( ulIn > UI1_MAX )
2218 {
2219 return DISP_E_OVERFLOW;
2220 }
2221
2222 *pbOut = (BYTE) ulIn;
2223
2224 return S_OK;
2225}
2226
2227
2228/******************************************************************************
2229 * VarUI1FromStr [OLEAUT32.136]
2230 */
2231HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2232{
2233 double dValue = 0.0;
2234 LPSTR pNewString = NULL;
2235
2236 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
2237
2238 /* Check if we have a valid argument
2239 */
2240 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2241 RemoveCharacterFromString( pNewString, "," );
2242 if( IsValidRealString( pNewString ) == FALSE )
2243 {
2244 return DISP_E_TYPEMISMATCH;
2245 }
2246
2247 /* Convert the valid string to a floating point number.
2248 */
2249 dValue = atof( pNewString );
2250
2251 /* We don't need the string anymore so free it.
2252 */
2253 HeapFree( GetProcessHeap(), 0 , pNewString );
2254
2255 /* Check range of value.
2256 */
2257 dValue = round( dValue );
2258 if( dValue < UI1_MIN || dValue > UI1_MAX )
2259 {
2260 return DISP_E_OVERFLOW;
2261 }
2262
2263 *pbOut = (BYTE) dValue;
2264
2265 return S_OK;
2266}
2267
2268/**********************************************************************
2269 * VarUI1FromCy [OLEAUT32.134]
2270 * Convert currency to unsigned char
2271 */
2272HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
2273 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2274
2275 if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
2276
2277 *pbOut = (BYTE)t;
2278 return S_OK;
2279}
2280
2281/******************************************************************************
2282 * VarI2FromUI1 [OLEAUT32.48]
2283 */
2284HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2285{
2286 TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
2287
2288 *psOut = (short) bIn;
2289
2290 return S_OK;
2291}
2292
2293/******************************************************************************
2294 * VarI2FromI4 [OLEAUT32.49]
2295 */
2296HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2297{
2298 TRACE("( %lx, %p ), stub\n", lIn, psOut );
2299
2300 /* Check range of value.
2301 */
2302 if( lIn < I2_MIN || lIn > I2_MAX )
2303 {
2304 return DISP_E_OVERFLOW;
2305 }
2306
2307 *psOut = (short) lIn;
2308
2309 return S_OK;
2310}
2311
2312/******************************************************************************
2313 * VarI2FromR4 [OLEAUT32.50]
2314 */
2315HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2316{
2317 TRACE("( %f, %p ), stub\n", fltIn, psOut );
2318
2319 /* Check range of value.
2320 */
2321 fltIn = round( fltIn );
2322 if( fltIn < I2_MIN || fltIn > I2_MAX )
2323 {
2324 return DISP_E_OVERFLOW;
2325 }
2326
2327 *psOut = (short) fltIn;
2328
2329 return S_OK;
2330}
2331
2332/******************************************************************************
2333 * VarI2FromR8 [OLEAUT32.51]
2334 */
2335HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2336{
2337 TRACE("( %f, %p ), stub\n", dblIn, psOut );
2338
2339 /* Check range of value.
2340 */
2341 dblIn = round( dblIn );
2342 if( dblIn < I2_MIN || dblIn > I2_MAX )
2343 {
2344 return DISP_E_OVERFLOW;
2345 }
2346
2347 *psOut = (short) dblIn;
2348
2349 return S_OK;
2350}
2351
2352/******************************************************************************
2353 * VarI2FromDate [OLEAUT32.53]
2354 */
2355HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2356{
2357 TRACE("( %f, %p ), stub\n", dateIn, psOut );
2358
2359 /* Check range of value.
2360 */
2361 dateIn = round( dateIn );
2362 if( dateIn < I2_MIN || dateIn > I2_MAX )
2363 {
2364 return DISP_E_OVERFLOW;
2365 }
2366
2367 *psOut = (short) dateIn;
2368
2369 return S_OK;
2370}
2371
2372/******************************************************************************
2373 * VarI2FromBool [OLEAUT32.56]
2374 */
2375HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2376{
2377 TRACE("( %d, %p ), stub\n", boolIn, psOut );
2378
2379 *psOut = (short) boolIn;
2380
2381 return S_OK;
2382}
2383
2384/******************************************************************************
2385 * VarI2FromI1 [OLEAUT32.205]
2386 */
2387HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
2388{
2389 TRACE("( %c, %p ), stub\n", cIn, psOut );
2390
2391 *psOut = (short) cIn;
2392
2393 return S_OK;
2394}
2395
2396/******************************************************************************
2397 * VarI2FromUI2 [OLEAUT32.206]
2398 */
2399HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2400{
2401 TRACE("( %d, %p ), stub\n", uiIn, psOut );
2402
2403 /* Check range of value.
2404 */
2405 if( uiIn > I2_MAX )
2406 {
2407 return DISP_E_OVERFLOW;
2408 }
2409
2410 *psOut = (short) uiIn;
2411
2412 return S_OK;
2413}
2414
2415/******************************************************************************
2416 * VarI2FromUI4 [OLEAUT32.207]
2417 */
2418HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2419{
2420 TRACE("( %lx, %p ), stub\n", ulIn, psOut );
2421
2422 /* Check range of value.
2423 */
2424 if( ulIn < I2_MIN || ulIn > I2_MAX )
2425 {
2426 return DISP_E_OVERFLOW;
2427 }
2428
2429 *psOut = (short) ulIn;
2430
2431 return S_OK;
2432}
2433
2434/******************************************************************************
2435 * VarI2FromStr [OLEAUT32.54]
2436 */
2437HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2438{
2439 double dValue = 0.0;
2440 LPSTR pNewString = NULL;
2441
2442 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, psOut );
2443
2444 /* Check if we have a valid argument
2445 */
2446 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2447 RemoveCharacterFromString( pNewString, "," );
2448 if( IsValidRealString( pNewString ) == FALSE )
2449 {
2450 return DISP_E_TYPEMISMATCH;
2451 }
2452
2453 /* Convert the valid string to a floating point number.
2454 */
2455 dValue = atof( pNewString );
2456
2457 /* We don't need the string anymore so free it.
2458 */
2459 HeapFree( GetProcessHeap(), 0, pNewString );
2460
2461 /* Check range of value.
2462 */
2463 dValue = round( dValue );
2464 if( dValue < I2_MIN || dValue > I2_MAX )
2465 {
2466 return DISP_E_OVERFLOW;
2467 }
2468
2469 *psOut = (short) dValue;
2470
2471 return S_OK;
2472}
2473
2474/**********************************************************************
2475 * VarI2FromCy [OLEAUT32.52]
2476 * Convert currency to signed short
2477 */
2478HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
2479 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2480
2481 if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
2482
2483 *psOut = (SHORT)t;
2484 return S_OK;
2485}
2486
2487/******************************************************************************
2488 * VarI4FromUI1 [OLEAUT32.58]
2489 */
2490HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2491{
2492 TRACE("( %X, %p ), stub\n", bIn, plOut );
2493
2494 *plOut = (LONG) bIn;
2495
2496 return S_OK;
2497}
2498
2499
2500/******************************************************************************
2501 * VarI4FromR4 [OLEAUT32.60]
2502 */
2503HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2504{
2505 TRACE("( %f, %p ), stub\n", fltIn, plOut );
2506
2507 /* Check range of value.
2508 */
2509 fltIn = round( fltIn );
2510 if( fltIn < I4_MIN || fltIn > I4_MAX )
2511 {
2512 return DISP_E_OVERFLOW;
2513 }
2514
2515 *plOut = (LONG) fltIn;
2516
2517 return S_OK;
2518}
2519
2520/******************************************************************************
2521 * VarI4FromR8 [OLEAUT32.61]
2522 */
2523HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2524{
2525 TRACE("( %f, %p ), stub\n", dblIn, plOut );
2526
2527 /* Check range of value.
2528 */
2529 dblIn = round( dblIn );
2530 if( dblIn < I4_MIN || dblIn > I4_MAX )
2531 {
2532 return DISP_E_OVERFLOW;
2533 }
2534
2535 *plOut = (LONG) dblIn;
2536
2537 return S_OK;
2538}
2539
2540/******************************************************************************
2541 * VarI4FromDate [OLEAUT32.63]
2542 */
2543HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2544{
2545 TRACE("( %f, %p ), stub\n", dateIn, plOut );
2546
2547 /* Check range of value.
2548 */
2549 dateIn = round( dateIn );
2550 if( dateIn < I4_MIN || dateIn > I4_MAX )
2551 {
2552 return DISP_E_OVERFLOW;
2553 }
2554
2555 *plOut = (LONG) dateIn;
2556
2557 return S_OK;
2558}
2559
2560/******************************************************************************
2561 * VarI4FromBool [OLEAUT32.66]
2562 */
2563HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2564{
2565 TRACE("( %d, %p ), stub\n", boolIn, plOut );
2566
2567 *plOut = (LONG) boolIn;
2568
2569 return S_OK;
2570}
2571
2572/******************************************************************************
2573 * VarI4FromI1 [OLEAUT32.209]
2574 */
2575HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
2576{
2577 TRACE("( %c, %p ), stub\n", cIn, plOut );
2578
2579 *plOut = (LONG) cIn;
2580
2581 return S_OK;
2582}
2583
2584/******************************************************************************
2585 * VarI4FromUI2 [OLEAUT32.210]
2586 */
2587HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2588{
2589 TRACE("( %d, %p ), stub\n", uiIn, plOut );
2590
2591 *plOut = (LONG) uiIn;
2592
2593 return S_OK;
2594}
2595
2596/******************************************************************************
2597 * VarI4FromUI4 [OLEAUT32.211]
2598 */
2599HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2600{
2601 TRACE("( %lx, %p ), stub\n", ulIn, plOut );
2602
2603 /* Check range of value.
2604 */
2605 if( ulIn < I4_MIN || ulIn > I4_MAX )
2606 {
2607 return DISP_E_OVERFLOW;
2608 }
2609
2610 *plOut = (LONG) ulIn;
2611
2612 return S_OK;
2613}
2614
2615/******************************************************************************
2616 * VarI4FromI2 [OLEAUT32.59]
2617 */
2618HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2619{
2620 TRACE("( %d, %p ), stub\n", sIn, plOut );
2621
2622 *plOut = (LONG) sIn;
2623
2624 return S_OK;
2625}
2626
2627/******************************************************************************
2628 * VarI4FromStr [OLEAUT32.64]
2629 */
2630HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2631{
2632 double dValue = 0.0;
2633 LPSTR pNewString = NULL;
2634
2635 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
2636
2637 /* Check if we have a valid argument
2638 */
2639 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2640 RemoveCharacterFromString( pNewString, "," );
2641 if( IsValidRealString( pNewString ) == FALSE )
2642 {
2643 return DISP_E_TYPEMISMATCH;
2644 }
2645
2646 /* Convert the valid string to a floating point number.
2647 */
2648 dValue = atof( pNewString );
2649
2650 /* We don't need the string anymore so free it.
2651 */
2652 HeapFree( GetProcessHeap(), 0, pNewString );
2653
2654 /* Check range of value.
2655 */
2656 dValue = round( dValue );
2657 if( dValue < I4_MIN || dValue > I4_MAX )
2658 {
2659 return DISP_E_OVERFLOW;
2660 }
2661
2662 *plOut = (LONG) dValue;
2663
2664 return S_OK;
2665}
2666
2667/**********************************************************************
2668 * VarI4FromCy [OLEAUT32.62]
2669 * Convert currency to signed long
2670 */
2671HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
2672 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2673
2674 if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
2675
2676 *plOut = (LONG)t;
2677 return S_OK;
2678}
2679
2680/******************************************************************************
2681 * VarR4FromUI1 [OLEAUT32.68]
2682 */
2683HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
2684{
2685 TRACE("( %X, %p ), stub\n", bIn, pfltOut );
2686
2687 *pfltOut = (FLOAT) bIn;
2688
2689 return S_OK;
2690}
2691
2692/******************************************************************************
2693 * VarR4FromI2 [OLEAUT32.69]
2694 */
2695HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
2696{
2697 TRACE("( %d, %p ), stub\n", sIn, pfltOut );
2698
2699 *pfltOut = (FLOAT) sIn;
2700
2701 return S_OK;
2702}
2703
2704/******************************************************************************
2705 * VarR4FromI4 [OLEAUT32.70]
2706 */
2707HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
2708{
2709 TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
2710
2711 *pfltOut = (FLOAT) lIn;
2712
2713 return S_OK;
2714}
2715
2716/******************************************************************************
2717 * VarR4FromR8 [OLEAUT32.71]
2718 */
2719HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
2720{
2721 TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
2722
2723 /* Check range of value.
2724 */
2725 if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
2726 {
2727 return DISP_E_OVERFLOW;
2728 }
2729
2730 *pfltOut = (FLOAT) dblIn;
2731
2732 return S_OK;
2733}
2734
2735/******************************************************************************
2736 * VarR4FromDate [OLEAUT32.73]
2737 */
2738HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
2739{
2740 TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
2741
2742 /* Check range of value.
2743 */
2744 if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
2745 {
2746 return DISP_E_OVERFLOW;
2747 }
2748
2749 *pfltOut = (FLOAT) dateIn;
2750
2751 return S_OK;
2752}
2753
2754/******************************************************************************
2755 * VarR4FromBool [OLEAUT32.76]
2756 */
2757HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
2758{
2759 TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
2760
2761 *pfltOut = (FLOAT) boolIn;
2762
2763 return S_OK;
2764}
2765
2766/******************************************************************************
2767 * VarR4FromI1 [OLEAUT32.213]
2768 */
2769HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
2770{
2771 TRACE("( %c, %p ), stub\n", cIn, pfltOut );
2772
2773 *pfltOut = (FLOAT) cIn;
2774
2775 return S_OK;
2776}
2777
2778/******************************************************************************
2779 * VarR4FromUI2 [OLEAUT32.214]
2780 */
2781HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
2782{
2783 TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
2784
2785 *pfltOut = (FLOAT) uiIn;
2786
2787 return S_OK;
2788}
2789
2790/******************************************************************************
2791 * VarR4FromUI4 [OLEAUT32.215]
2792 */
2793HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
2794{
2795 TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
2796
2797 *pfltOut = (FLOAT) ulIn;
2798
2799 return S_OK;
2800}
2801
2802/******************************************************************************
2803 * VarR4FromStr [OLEAUT32.74]
2804 */
2805HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
2806{
2807 double dValue = 0.0;
2808 LPSTR pNewString = NULL;
2809
2810 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
2811
2812 /* Check if we have a valid argument
2813 */
2814 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2815 RemoveCharacterFromString( pNewString, "," );
2816 if( IsValidRealString( pNewString ) == FALSE )
2817 {
2818 return DISP_E_TYPEMISMATCH;
2819 }
2820
2821 /* Convert the valid string to a floating point number.
2822 */
2823 dValue = atof( pNewString );
2824
2825 /* We don't need the string anymore so free it.
2826 */
2827 HeapFree( GetProcessHeap(), 0, pNewString );
2828
2829 /* Check range of value.
2830 */
2831 if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
2832 {
2833 return DISP_E_OVERFLOW;
2834 }
2835
2836 *pfltOut = (FLOAT) dValue;
2837
2838 return S_OK;
2839}
2840
2841/**********************************************************************
2842 * VarR4FromCy [OLEAUT32.72]
2843 * Convert currency to float
2844 */
2845HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
2846 *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2847
2848 return S_OK;
2849}
2850
2851/******************************************************************************
2852 * VarR8FromUI1 [OLEAUT32.78]
2853 */
2854HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
2855{
2856 TRACE("( %d, %p ), stub\n", bIn, pdblOut );
2857
2858 *pdblOut = (double) bIn;
2859
2860 return S_OK;
2861}
2862
2863/******************************************************************************
2864 * VarR8FromI2 [OLEAUT32.79]
2865 */
2866HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
2867{
2868 TRACE("( %d, %p ), stub\n", sIn, pdblOut );
2869
2870 *pdblOut = (double) sIn;
2871
2872 return S_OK;
2873}
2874
2875/******************************************************************************
2876 * VarR8FromI4 [OLEAUT32.80]
2877 */
2878HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
2879{
2880 TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
2881
2882 *pdblOut = (double) lIn;
2883
2884 return S_OK;
2885}
2886
2887/******************************************************************************
2888 * VarR8FromR4 [OLEAUT32.81]
2889 */
2890HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
2891{
2892 TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
2893
2894 *pdblOut = (double) fltIn;
2895
2896 return S_OK;
2897}
2898
2899/******************************************************************************
2900 * VarR8FromDate [OLEAUT32.83]
2901 */
2902HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
2903{
2904 TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
2905
2906 *pdblOut = (double) dateIn;
2907
2908 return S_OK;
2909}
2910
2911/******************************************************************************
2912 * VarR8FromBool [OLEAUT32.86]
2913 */
2914HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
2915{
2916 TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
2917
2918 *pdblOut = (double) boolIn;
2919
2920 return S_OK;
2921}
2922
2923/******************************************************************************
2924 * VarR8FromI1 [OLEAUT32.217]
2925 */
2926HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
2927{
2928 TRACE("( %c, %p ), stub\n", cIn, pdblOut );
2929
2930 *pdblOut = (double) cIn;
2931
2932 return S_OK;
2933}
2934
2935/******************************************************************************
2936 * VarR8FromUI2 [OLEAUT32.218]
2937 */
2938HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
2939{
2940 TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
2941
2942 *pdblOut = (double) uiIn;
2943
2944 return S_OK;
2945}
2946
2947/******************************************************************************
2948 * VarR8FromUI4 [OLEAUT32.219]
2949 */
2950HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
2951{
2952 TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
2953
2954 *pdblOut = (double) ulIn;
2955
2956 return S_OK;
2957}
2958
2959/******************************************************************************
2960 * VarR8FromStr [OLEAUT32.84]
2961 */
2962HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
2963{
2964 double dValue = 0.0;
2965 LPSTR pNewString = NULL;
2966
2967 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pdblOut );
2968
2969 /* Check if we have a valid argument
2970 */
2971 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2972 RemoveCharacterFromString( pNewString, "," );
2973 if( IsValidRealString( pNewString ) == FALSE )
2974 {
2975 return DISP_E_TYPEMISMATCH;
2976 }
2977
2978 /* Convert the valid string to a floating point number.
2979 */
2980 dValue = atof( pNewString );
2981
2982 /* We don't need the string anymore so free it.
2983 */
2984 HeapFree( GetProcessHeap(), 0, pNewString );
2985
2986 *pdblOut = dValue;
2987
2988 return S_OK;
2989}
2990
2991/**********************************************************************
2992 * VarR8FromCy [OLEAUT32.82]
2993 * Convert currency to double
2994 */
2995HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
2996 *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2997
2998 return S_OK;
2999}
3000
3001/******************************************************************************
3002 * VarDateFromUI1 [OLEAUT32.88]
3003 */
3004HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
3005{
3006 TRACE("( %d, %p ), stub\n", bIn, pdateOut );
3007
3008 *pdateOut = (DATE) bIn;
3009
3010 return S_OK;
3011}
3012
3013/******************************************************************************
3014 * VarDateFromI2 [OLEAUT32.89]
3015 */
3016HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
3017{
3018 TRACE("( %d, %p ), stub\n", sIn, pdateOut );
3019
3020 *pdateOut = (DATE) sIn;
3021
3022 return S_OK;
3023}
3024
3025/******************************************************************************
3026 * VarDateFromI4 [OLEAUT32.90]
3027 */
3028HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3029{
3030 TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
3031
3032 if( lIn < DATE_MIN || lIn > DATE_MAX )
3033 {
3034 return DISP_E_OVERFLOW;
3035 }
3036
3037 *pdateOut = (DATE) lIn;
3038
3039 return S_OK;
3040}
3041
3042/******************************************************************************
3043 * VarDateFromR4 [OLEAUT32.91]
3044 */
3045HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3046{
3047 TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3048
3049 if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
3050 {
3051 return DISP_E_OVERFLOW;
3052 }
3053
3054 *pdateOut = (DATE) fltIn;
3055
3056 return S_OK;
3057}
3058
3059/******************************************************************************
3060 * VarDateFromR8 [OLEAUT32.92]
3061 */
3062HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3063{
3064 TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3065
3066 if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3067 {
3068 return DISP_E_OVERFLOW;
3069 }
3070
3071 *pdateOut = (DATE) dblIn;
3072
3073 return S_OK;
3074}
3075
3076/******************************************************************************
3077 * VarDateFromStr [OLEAUT32.94]
3078 * The string representing the date is composed of two parts, a date and time.
3079 *
3080 * The format of the time is has follows:
3081 * hh[:mm][:ss][AM|PM]
3082 * Whitespace can be inserted anywhere between these tokens. A whitespace consists
3083 * of space and/or tab characters, which are ignored.
3084 *
3085 * The formats for the date part are has follows:
3086 * mm/[dd/][yy]yy
3087 * [dd/]mm/[yy]yy
3088 * [yy]yy/mm/dd
3089 * January dd[,] [yy]yy
3090 * dd January [yy]yy
3091 * [yy]yy January dd
3092 * Whitespace can be inserted anywhere between these tokens.
3093 *
3094 * The formats for the date and time string are has follows.
3095 * date[whitespace][time]
3096 * [time][whitespace]date
3097 *
3098 * These are the only characters allowed in a string representing a date and time:
3099 * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3100 */
3101HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3102{
3103 HRESULT ret = S_OK;
3104 struct tm TM;
3105
3106 memset( &TM, 0, sizeof(TM) );
3107
3108 TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3109
3110 if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
3111 {
3112 if( TmToDATE( &TM, pdateOut ) == FALSE )
3113 {
3114 ret = E_INVALIDARG;
3115 }
3116 }
3117 else
3118 {
3119 ret = DISP_E_TYPEMISMATCH;
3120 }
3121
3122
3123 return ret;
3124}
3125
3126/******************************************************************************
3127 * VarDateFromI1 [OLEAUT32.221]
3128 */
3129HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
3130{
3131 TRACE("( %c, %p ), stub\n", cIn, pdateOut );
3132
3133 *pdateOut = (DATE) cIn;
3134
3135 return S_OK;
3136}
3137
3138/******************************************************************************
3139 * VarDateFromUI2 [OLEAUT32.222]
3140 */
3141HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3142{
3143 TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
3144
3145 if( uiIn > DATE_MAX )
3146 {
3147 return DISP_E_OVERFLOW;
3148 }
3149
3150 *pdateOut = (DATE) uiIn;
3151
3152 return S_OK;
3153}
3154
3155/******************************************************************************
3156 * VarDateFromUI4 [OLEAUT32.223]
3157 */
3158HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3159{
3160 TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
3161
3162 if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3163 {
3164 return DISP_E_OVERFLOW;
3165 }
3166
3167 *pdateOut = (DATE) ulIn;
3168
3169 return S_OK;
3170}
3171
3172/******************************************************************************
3173 * VarDateFromBool [OLEAUT32.96]
3174 */
3175HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3176{
3177 TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
3178
3179 *pdateOut = (DATE) boolIn;
3180
3181 return S_OK;
3182}
3183
3184/**********************************************************************
3185 * VarDateFromCy [OLEAUT32.93]
3186 * Convert currency to date
3187 */
3188HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
3189 *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3190
3191 if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3192 return S_OK;
3193}
3194
3195/******************************************************************************
3196 * VarBstrFromUI1 [OLEAUT32.108]
3197 */
3198HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3199{
3200 TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3201 sprintf( pBuffer, "%d", bVal );
3202
3203 *pbstrOut = StringDupAtoBstr( pBuffer );
3204
3205 return S_OK;
3206}
3207
3208/******************************************************************************
3209 * VarBstrFromI2 [OLEAUT32.109]
3210 */
3211HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3212{
3213 TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3214 sprintf( pBuffer, "%d", iVal );
3215 *pbstrOut = StringDupAtoBstr( pBuffer );
3216
3217 return S_OK;
3218}
3219
3220/******************************************************************************
3221 * VarBstrFromI4 [OLEAUT32.110]
3222 */
3223HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3224{
3225 TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
3226
3227 sprintf( pBuffer, "%ld", lIn );
3228 *pbstrOut = StringDupAtoBstr( pBuffer );
3229
3230 return S_OK;
3231}
3232
3233/******************************************************************************
3234 * VarBstrFromR4 [OLEAUT32.111]
3235 */
3236HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3237{
3238 TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
3239
3240 sprintf( pBuffer, "%.7g", fltIn );
3241 *pbstrOut = StringDupAtoBstr( pBuffer );
3242
3243 return S_OK;
3244}
3245
3246/******************************************************************************
3247 * VarBstrFromR8 [OLEAUT32.112]
3248 */
3249HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3250{
3251 TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
3252
3253 sprintf( pBuffer, "%.15g", dblIn );
3254 *pbstrOut = StringDupAtoBstr( pBuffer );
3255
3256 return S_OK;
3257}
3258
3259/******************************************************************************
3260 * VarBstrFromCy [OLEAUT32.113]
3261 */
3262HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
3263 FIXME("([cyIn], %08lx, %08lx, %p), stub.\n", lcid, dwFlags, pbstrOut);
3264 return E_NOTIMPL;
3265}
3266
3267
3268/******************************************************************************
3269 * VarBstrFromDate [OLEAUT32.114]
3270 *
3271 * The date is implemented using an 8 byte floating-point number.
3272 * Days are represented by whole numbers increments starting with 0.00 as
3273 * being December 30 1899, midnight.
3274 * The hours are expressed as the fractional part of the number.
3275 * December 30 1899 at midnight = 0.00
3276 * January 1 1900 at midnight = 2.00
3277 * January 4 1900 at 6 AM = 5.25
3278 * January 4 1900 at noon = 5.50
3279 * December 29 1899 at midnight = -1.00
3280 * December 18 1899 at midnight = -12.00
3281 * December 18 1899 at 6AM = -12.25
3282 * December 18 1899 at 6PM = -12.75
3283 * December 19 1899 at midnight = -11.00
3284 * The tm structure is as follows:
3285 * struct tm {
3286 * int tm_sec; seconds after the minute - [0,59]
3287 * int tm_min; minutes after the hour - [0,59]
3288 * int tm_hour; hours since midnight - [0,23]
3289 * int tm_mday; day of the month - [1,31]
3290 * int tm_mon; months since January - [0,11]
3291 * int tm_year; years
3292 * int tm_wday; days since Sunday - [0,6]
3293 * int tm_yday; days since January 1 - [0,365]
3294 * int tm_isdst; daylight savings time flag
3295 * };
3296 */
3297HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3298{
3299 struct tm TM;
3300 memset( &TM, 0, sizeof(TM) );
3301
3302 TRACE("( %f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
3303
3304 if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
3305 {
3306 return E_INVALIDARG;
3307 }
3308
3309 if( dwFlags & VAR_DATEVALUEONLY )
3310 strftime( pBuffer, BUFFER_MAX, "%x", &TM );
3311 else if( dwFlags & VAR_TIMEVALUEONLY )
3312 strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3313 else
3314 strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3315
3316 *pbstrOut = StringDupAtoBstr( pBuffer );
3317
3318 return S_OK;
3319}
3320
3321/******************************************************************************
3322 * VarBstrFromBool [OLEAUT32.116]
3323 */
3324HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3325{
3326 TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
3327
3328 sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
3329
3330 *pbstrOut = StringDupAtoBstr( pBuffer );
3331
3332 return S_OK;
3333}
3334
3335/******************************************************************************
3336 * VarBstrFromI1 [OLEAUT32.229]
3337 */
3338HRESULT WINAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3339{
3340 TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3341 sprintf( pBuffer, "%d", cIn );
3342 *pbstrOut = StringDupAtoBstr( pBuffer );
3343
3344 return S_OK;
3345}
3346
3347/******************************************************************************
3348 * VarBstrFromUI2 [OLEAUT32.230]
3349 */
3350HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3351{
3352 TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3353 sprintf( pBuffer, "%d", uiIn );
3354 *pbstrOut = StringDupAtoBstr( pBuffer );
3355
3356 return S_OK;
3357}
3358
3359/******************************************************************************
3360 * VarBstrFromUI4 [OLEAUT32.231]
3361 */
3362HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3363{
3364 TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3365 sprintf( pBuffer, "%ld", ulIn );
3366 *pbstrOut = StringDupAtoBstr( pBuffer );
3367
3368 return S_OK;
3369}
3370
3371/******************************************************************************
3372 * VarBoolFromUI1 [OLEAUT32.118]
3373 */
3374HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3375{
3376 TRACE("( %d, %p ), stub\n", bIn, pboolOut );
3377
3378 if( bIn == 0 )
3379 {
3380 *pboolOut = VARIANT_FALSE;
3381 }
3382 else
3383 {
3384 *pboolOut = VARIANT_TRUE;
3385 }
3386
3387 return S_OK;
3388}
3389
3390/******************************************************************************
3391 * VarBoolFromI2 [OLEAUT32.119]
3392 */
3393HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3394{
3395 TRACE("( %d, %p ), stub\n", sIn, pboolOut );
3396
3397 *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
3398
3399 return S_OK;
3400}
3401
3402/******************************************************************************
3403 * VarBoolFromI4 [OLEAUT32.120]
3404 */
3405HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3406{
3407 TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
3408
3409 *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
3410
3411 return S_OK;
3412}
3413
3414/******************************************************************************
3415 * VarBoolFromR4 [OLEAUT32.121]
3416 */
3417HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3418{
3419 TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
3420
3421 *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3422
3423 return S_OK;
3424}
3425
3426/******************************************************************************
3427 * VarBoolFromR8 [OLEAUT32.122]
3428 */
3429HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3430{
3431 TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
3432
3433 *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3434
3435 return S_OK;
3436}
3437
3438/******************************************************************************
3439 * VarBoolFromDate [OLEAUT32.123]
3440 */
3441HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3442{
3443 TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
3444
3445 *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3446
3447 return S_OK;
3448}
3449
3450/******************************************************************************
3451 * VarBoolFromStr [OLEAUT32.125]
3452 */
3453HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3454{
3455 HRESULT ret = S_OK;
3456 char* pNewString = NULL;
3457
3458 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
3459
3460 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3461
3462 if( pNewString == NULL || strlen( pNewString ) == 0 )
3463 {
3464 ret = DISP_E_TYPEMISMATCH;
3465 }
3466
3467 if( ret == S_OK )
3468 {
3469 if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
3470 {
3471 *pboolOut = VARIANT_TRUE;
3472 }
3473 else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
3474 {
3475 *pboolOut = VARIANT_FALSE;
3476 }
3477 else
3478 {
3479 /* Try converting the string to a floating point number.
3480 */
3481 double dValue = 0.0;
3482 HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3483 if( res != S_OK )
3484 {
3485 ret = DISP_E_TYPEMISMATCH;
3486 }
3487 else
3488 *pboolOut = (dValue == 0.0) ?
3489 VARIANT_FALSE : VARIANT_TRUE;
3490 }
3491 }
3492
3493 HeapFree( GetProcessHeap(), 0, pNewString );
3494
3495 return ret;
3496}
3497
3498/******************************************************************************
3499 * VarBoolFromI1 [OLEAUT32.233]
3500 */
3501HRESULT WINAPI VarBoolFromI1(CHAR cIn, VARIANT_BOOL* pboolOut)
3502{
3503 TRACE("( %c, %p ), stub\n", cIn, pboolOut );
3504
3505 *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3506
3507 return S_OK;
3508}
3509
3510/******************************************************************************
3511 * VarBoolFromUI2 [OLEAUT32.234]
3512 */
3513HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3514{
3515 TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
3516
3517 *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3518
3519 return S_OK;
3520}
3521
3522/******************************************************************************
3523 * VarBoolFromUI4 [OLEAUT32.235]
3524 */
3525HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3526{
3527 TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
3528
3529 *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3530
3531 return S_OK;
3532}
3533
3534/**********************************************************************
3535 * VarBoolFromCy [OLEAUT32.124]
3536 * Convert currency to boolean
3537 */
3538HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
3539 if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
3540 else *pboolOut = 0;
3541
3542 return S_OK;
3543}
3544
3545/******************************************************************************
3546 * VarI1FromUI1 [OLEAUT32.244]
3547 */
3548HRESULT WINAPI VarI1FromUI1(BYTE bIn, CHAR* pcOut)
3549{
3550 TRACE("( %d, %p ), stub\n", bIn, pcOut );
3551
3552 /* Check range of value.
3553 */
3554 if( bIn > CHAR_MAX )
3555 {
3556 return DISP_E_OVERFLOW;
3557 }
3558
3559 *pcOut = (CHAR) bIn;
3560
3561 return S_OK;
3562}
3563
3564/******************************************************************************
3565 * VarI1FromI2 [OLEAUT32.245]
3566 */
3567HRESULT WINAPI VarI1FromI2(short uiIn, CHAR* pcOut)
3568{
3569 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3570
3571 if( uiIn > CHAR_MAX )
3572 {
3573 return DISP_E_OVERFLOW;
3574 }
3575
3576 *pcOut = (CHAR) uiIn;
3577
3578 return S_OK;
3579}
3580
3581/******************************************************************************
3582 * VarI1FromI4 [OLEAUT32.246]
3583 */
3584HRESULT WINAPI VarI1FromI4(LONG lIn, CHAR* pcOut)
3585{
3586 TRACE("( %ld, %p ), stub\n", lIn, pcOut );
3587
3588 if( lIn < CHAR_MIN || lIn > CHAR_MAX )
3589 {
3590 return DISP_E_OVERFLOW;
3591 }
3592
3593 *pcOut = (CHAR) lIn;
3594
3595 return S_OK;
3596}
3597
3598/******************************************************************************
3599 * VarI1FromR4 [OLEAUT32.247]
3600 */
3601HRESULT WINAPI VarI1FromR4(FLOAT fltIn, CHAR* pcOut)
3602{
3603 TRACE("( %f, %p ), stub\n", fltIn, pcOut );
3604
3605 fltIn = round( fltIn );
3606 if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
3607 {
3608 return DISP_E_OVERFLOW;
3609 }
3610
3611 *pcOut = (CHAR) fltIn;
3612
3613 return S_OK;
3614}
3615
3616/******************************************************************************
3617 * VarI1FromR8 [OLEAUT32.248]
3618 */
3619HRESULT WINAPI VarI1FromR8(double dblIn, CHAR* pcOut)
3620{
3621 TRACE("( %f, %p ), stub\n", dblIn, pcOut );
3622
3623 dblIn = round( dblIn );
3624 if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
3625 {
3626 return DISP_E_OVERFLOW;
3627 }
3628
3629 *pcOut = (CHAR) dblIn;
3630
3631 return S_OK;
3632}
3633
3634/******************************************************************************
3635 * VarI1FromDate [OLEAUT32.249]
3636 */
3637HRESULT WINAPI VarI1FromDate(DATE dateIn, CHAR* pcOut)
3638{
3639 TRACE("( %f, %p ), stub\n", dateIn, pcOut );
3640
3641 dateIn = round( dateIn );
3642 if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
3643 {
3644 return DISP_E_OVERFLOW;
3645 }
3646
3647 *pcOut = (CHAR) dateIn;
3648
3649 return S_OK;
3650}
3651
3652/******************************************************************************
3653 * VarI1FromStr [OLEAUT32.251]
3654 */
3655HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CHAR* pcOut)
3656{
3657 double dValue = 0.0;
3658 LPSTR pNewString = NULL;
3659
3660 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
3661
3662 /* Check if we have a valid argument
3663 */
3664 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3665 RemoveCharacterFromString( pNewString, "," );
3666 if( IsValidRealString( pNewString ) == FALSE )
3667 {
3668 return DISP_E_TYPEMISMATCH;
3669 }
3670
3671 /* Convert the valid string to a floating point number.
3672 */
3673 dValue = atof( pNewString );
3674
3675 /* We don't need the string anymore so free it.
3676 */
3677 HeapFree( GetProcessHeap(), 0, pNewString );
3678
3679 /* Check range of value.
3680 */
3681 dValue = round( dValue );
3682 if( dValue < CHAR_MIN || dValue > CHAR_MAX )
3683 {
3684 return DISP_E_OVERFLOW;
3685 }
3686
3687 *pcOut = (CHAR) dValue;
3688
3689 return S_OK;
3690}
3691
3692/******************************************************************************
3693 * VarI1FromBool [OLEAUT32.253]
3694 */
3695HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
3696{
3697 TRACE("( %d, %p ), stub\n", boolIn, pcOut );
3698
3699 *pcOut = (CHAR) boolIn;
3700
3701 return S_OK;
3702}
3703
3704/******************************************************************************
3705 * VarI1FromUI2 [OLEAUT32.254]
3706 */
3707HRESULT WINAPI VarI1FromUI2(USHORT uiIn, CHAR* pcOut)
3708{
3709 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3710
3711 if( uiIn > CHAR_MAX )
3712 {
3713 return DISP_E_OVERFLOW;
3714 }
3715
3716 *pcOut = (CHAR) uiIn;
3717
3718 return S_OK;
3719}
3720
3721/******************************************************************************
3722 * VarI1FromUI4 [OLEAUT32.255]
3723 */
3724HRESULT WINAPI VarI1FromUI4(ULONG ulIn, CHAR* pcOut)
3725{
3726 TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
3727
3728 if( ulIn > CHAR_MAX )
3729 {
3730 return DISP_E_OVERFLOW;
3731 }
3732
3733 *pcOut = (CHAR) ulIn;
3734
3735 return S_OK;
3736}
3737
3738/**********************************************************************
3739 * VarI1FromCy [OLEAUT32.250]
3740 * Convert currency to signed char
3741 */
3742HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
3743 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3744
3745 if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
3746
3747 *pcOut = (CHAR)t;
3748 return S_OK;
3749}
3750
3751/******************************************************************************
3752 * VarUI2FromUI1 [OLEAUT32.257]
3753 */
3754HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
3755{
3756 TRACE("( %d, %p ), stub\n", bIn, puiOut );
3757
3758 *puiOut = (USHORT) bIn;
3759
3760 return S_OK;
3761}
3762
3763/******************************************************************************
3764 * VarUI2FromI2 [OLEAUT32.258]
3765 */
3766HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
3767{
3768 TRACE("( %d, %p ), stub\n", uiIn, puiOut );
3769
3770 if( uiIn < UI2_MIN )
3771 {
3772 return DISP_E_OVERFLOW;
3773 }
3774
3775 *puiOut = (USHORT) uiIn;
3776
3777 return S_OK;
3778}
3779
3780/******************************************************************************
3781 * VarUI2FromI4 [OLEAUT32.259]
3782 */
3783HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
3784{
3785 TRACE("( %ld, %p ), stub\n", lIn, puiOut );
3786
3787 if( lIn < UI2_MIN || lIn > UI2_MAX )
3788 {
3789 return DISP_E_OVERFLOW;
3790 }
3791
3792 *puiOut = (USHORT) lIn;
3793
3794 return S_OK;
3795}
3796
3797/******************************************************************************
3798 * VarUI2FromR4 [OLEAUT32.260]
3799 */
3800HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
3801{
3802 TRACE("( %f, %p ), stub\n", fltIn, puiOut );
3803
3804 fltIn = round( fltIn );
3805 if( fltIn < UI2_MIN || fltIn > UI2_MAX )
3806 {
3807 return DISP_E_OVERFLOW;
3808 }
3809
3810 *puiOut = (USHORT) fltIn;
3811
3812 return S_OK;
3813}
3814
3815/******************************************************************************
3816 * VarUI2FromR8 [OLEAUT32.261]
3817 */
3818HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
3819{
3820 TRACE("( %f, %p ), stub\n", dblIn, puiOut );
3821
3822 dblIn = round( dblIn );
3823 if( dblIn < UI2_MIN || dblIn > UI2_MAX )
3824 {
3825 return DISP_E_OVERFLOW;
3826 }
3827
3828 *puiOut = (USHORT) dblIn;
3829
3830 return S_OK;
3831}
3832
3833/******************************************************************************
3834 * VarUI2FromDate [OLEAUT32.262]
3835 */
3836HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
3837{
3838 TRACE("( %f, %p ), stub\n", dateIn, puiOut );
3839
3840 dateIn = round( dateIn );
3841 if( dateIn < UI2_MIN || dateIn > UI2_MAX )
3842 {
3843 return DISP_E_OVERFLOW;
3844 }
3845
3846 *puiOut = (USHORT) dateIn;
3847
3848 return S_OK;
3849}
3850
3851/******************************************************************************
3852 * VarUI2FromStr [OLEAUT32.264]
3853 */
3854HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
3855{
3856 double dValue = 0.0;
3857 LPSTR pNewString = NULL;
3858
3859 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
3860
3861 /* Check if we have a valid argument
3862 */
3863 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3864 RemoveCharacterFromString( pNewString, "," );
3865 if( IsValidRealString( pNewString ) == FALSE )
3866 {
3867 return DISP_E_TYPEMISMATCH;
3868 }
3869
3870 /* Convert the valid string to a floating point number.
3871 */
3872 dValue = atof( pNewString );
3873
3874 /* We don't need the string anymore so free it.
3875 */
3876 HeapFree( GetProcessHeap(), 0, pNewString );
3877
3878 /* Check range of value.
3879 */
3880 dValue = round( dValue );
3881 if( dValue < UI2_MIN || dValue > UI2_MAX )
3882 {
3883 return DISP_E_OVERFLOW;
3884 }
3885
3886 *puiOut = (USHORT) dValue;
3887
3888 return S_OK;
3889}
3890
3891/******************************************************************************
3892 * VarUI2FromBool [OLEAUT32.266]
3893 */
3894HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
3895{
3896 TRACE("( %d, %p ), stub\n", boolIn, puiOut );
3897
3898 *puiOut = (USHORT) boolIn;
3899
3900 return S_OK;
3901}
3902
3903/******************************************************************************
3904 * VarUI2FromI1 [OLEAUT32.267]
3905 */
3906HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
3907{
3908 TRACE("( %c, %p ), stub\n", cIn, puiOut );
3909
3910 *puiOut = (USHORT) cIn;
3911
3912 return S_OK;
3913}
3914
3915/******************************************************************************
3916 * VarUI2FromUI4 [OLEAUT32.268]
3917 */
3918HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
3919{
3920 TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
3921
3922 if( ulIn < UI2_MIN || ulIn > UI2_MAX )
3923 {
3924 return DISP_E_OVERFLOW;
3925 }
3926
3927 *puiOut = (USHORT) ulIn;
3928
3929 return S_OK;
3930}
3931
3932/******************************************************************************
3933 * VarUI4FromStr [OLEAUT32.277]
3934 */
3935HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
3936{
3937 double dValue = 0.0;
3938 LPSTR pNewString = NULL;
3939
3940 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
3941
3942 /* Check if we have a valid argument
3943 */
3944 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3945 RemoveCharacterFromString( pNewString, "," );
3946 if( IsValidRealString( pNewString ) == FALSE )
3947 {
3948 return DISP_E_TYPEMISMATCH;
3949 }
3950
3951 /* Convert the valid string to a floating point number.
3952 */
3953 dValue = atof( pNewString );
3954
3955 /* We don't need the string anymore so free it.
3956 */
3957 HeapFree( GetProcessHeap(), 0, pNewString );
3958
3959 /* Check range of value.
3960 */
3961 dValue = round( dValue );
3962 if( dValue < UI4_MIN || dValue > UI4_MAX )
3963 {
3964 return DISP_E_OVERFLOW;
3965 }
3966
3967 *pulOut = (ULONG) dValue;
3968
3969 return S_OK;
3970}
3971
3972/**********************************************************************
3973 * VarUI2FromCy [OLEAUT32.263]
3974 * Convert currency to unsigned short
3975 */
3976HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
3977 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3978
3979 if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
3980
3981 *pusOut = (USHORT)t;
3982
3983 return S_OK;
3984}
3985
3986/******************************************************************************
3987 * VarUI4FromUI1 [OLEAUT32.270]
3988 */
3989HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
3990{
3991 TRACE("( %d, %p ), stub\n", bIn, pulOut );
3992
3993 *pulOut = (USHORT) bIn;
3994
3995 return S_OK;
3996}
3997
3998/******************************************************************************
3999 * VarUI4FromI2 [OLEAUT32.271]
4000 */
4001HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
4002{
4003 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4004
4005 if( uiIn < UI4_MIN )
4006 {
4007 return DISP_E_OVERFLOW;
4008 }
4009
4010 *pulOut = (ULONG) uiIn;
4011
4012 return S_OK;
4013}
4014
4015/******************************************************************************
4016 * VarUI4FromI4 [OLEAUT32.272]
4017 */
4018HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
4019{
4020 TRACE("( %ld, %p ), stub\n", lIn, pulOut );
4021
4022 if( lIn < UI4_MIN )
4023 {
4024 return DISP_E_OVERFLOW;
4025 }
4026
4027 *pulOut = (ULONG) lIn;
4028
4029 return S_OK;
4030}
4031
4032/******************************************************************************
4033 * VarUI4FromR4 [OLEAUT32.273]
4034 */
4035HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
4036{
4037 fltIn = round( fltIn );
4038 if( fltIn < UI4_MIN || fltIn > UI4_MAX )
4039 {
4040 return DISP_E_OVERFLOW;
4041 }
4042
4043 *pulOut = (ULONG) fltIn;
4044
4045 return S_OK;
4046}
4047
4048/******************************************************************************
4049 * VarUI4FromR8 [OLEAUT32.274]
4050 */
4051HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
4052{
4053 TRACE("( %f, %p ), stub\n", dblIn, pulOut );
4054
4055 dblIn = round( dblIn );
4056 if( dblIn < UI4_MIN || dblIn > UI4_MAX )
4057 {
4058 return DISP_E_OVERFLOW;
4059 }
4060
4061 *pulOut = (ULONG) dblIn;
4062
4063 return S_OK;
4064}
4065
4066/******************************************************************************
4067 * VarUI4FromDate [OLEAUT32.275]
4068 */
4069HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
4070{
4071 TRACE("( %f, %p ), stub\n", dateIn, pulOut );
4072
4073 dateIn = round( dateIn );
4074 if( dateIn < UI4_MIN || dateIn > UI4_MAX )
4075 {
4076 return DISP_E_OVERFLOW;
4077 }
4078
4079 *pulOut = (ULONG) dateIn;
4080
4081 return S_OK;
4082}
4083
4084/******************************************************************************
4085 * VarUI4FromBool [OLEAUT32.279]
4086 */
4087HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
4088{
4089 TRACE("( %d, %p ), stub\n", boolIn, pulOut );
4090
4091 *pulOut = (ULONG) boolIn;
4092
4093 return S_OK;
4094}
4095
4096/******************************************************************************
4097 * VarUI4FromI1 [OLEAUT32.280]
4098 */
4099HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
4100{
4101 TRACE("( %c, %p ), stub\n", cIn, pulOut );
4102
4103 *pulOut = (ULONG) cIn;
4104
4105 return S_OK;
4106}
4107
4108/******************************************************************************
4109 * VarUI4FromUI2 [OLEAUT32.281]
4110 */
4111HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4112{
4113 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4114
4115 *pulOut = (ULONG) uiIn;
4116
4117 return S_OK;
4118}
4119
4120/**********************************************************************
4121 * VarUI4FromCy [OLEAUT32.276]
4122 * Convert currency to unsigned long
4123 */
4124HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
4125 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4126
4127 if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4128
4129 *pulOut = (ULONG)t;
4130
4131 return S_OK;
4132}
4133
4134/**********************************************************************
4135 * VarCyFromUI1 [OLEAUT32.98]
4136 * Convert unsigned char to currency
4137 */
4138HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
4139 pcyOut->s.Hi = 0;
4140 pcyOut->s.Lo = ((ULONG)bIn) * 10000;
4141
4142 return S_OK;
4143}
4144
4145/**********************************************************************
4146 * VarCyFromI2 [OLEAUT32.99]
4147 * Convert signed short to currency
4148 */
4149HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
4150 if (sIn < 0) pcyOut->s.Hi = -1;
4151 else pcyOut->s.Hi = 0;
4152 pcyOut->s.Lo = ((ULONG)sIn) * 10000;
4153
4154 return S_OK;
4155}
4156
4157/**********************************************************************
4158 * VarCyFromI4 [OLEAUT32.100]
4159 * Convert signed long to currency
4160 */
4161HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4162 double t = (double)lIn * (double)10000;
4163 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4164 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4165 if (lIn < 0) pcyOut->s.Hi--;
4166
4167 return S_OK;
4168}
4169
4170/**********************************************************************
4171 * VarCyFromR4 [OLEAUT32.101]
4172 * Convert float to currency
4173 */
4174HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
4175 double t = round((double)fltIn * (double)10000);
4176 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4177 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4178 if (fltIn < 0) pcyOut->s.Hi--;
4179
4180 return S_OK;
4181}
4182
4183/**********************************************************************
4184 * VarCyFromR8 [OLEAUT32.102]
4185 * Convert double to currency
4186 */
4187HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
4188 double t = round(dblIn * (double)10000);
4189 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4190 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4191 if (dblIn < 0) pcyOut->s.Hi--;
4192
4193 return S_OK;
4194}
4195
4196/**********************************************************************
4197 * VarCyFromDate [OLEAUT32.103]
4198 * Convert date to currency
4199 */
4200HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
4201 double t = round((double)dateIn * (double)10000);
4202 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4203 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4204 if (dateIn < 0) pcyOut->s.Hi--;
4205
4206 return S_OK;
4207}
4208
4209/**********************************************************************
4210 * VarCyFromStr [OLEAUT32.104]
4211 */
4212HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
4213 FIXME("(%p, %08lx, %08lx, %p), stub.\n", strIn, lcid, dwFlags, pcyOut);
4214 return E_NOTIMPL;
4215}
4216
4217
4218/**********************************************************************
4219 * VarCyFromBool [OLEAUT32.106]
4220 * Convert boolean to currency
4221 */
4222HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
4223 if (boolIn < 0) pcyOut->s.Hi = -1;
4224 else pcyOut->s.Hi = 0;
4225 pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
4226
4227 return S_OK;
4228}
4229
4230/**********************************************************************
4231 * VarCyFromI1 [OLEAUT32.225]
4232 * Convert signed char to currency
4233 */
4234HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
4235 if (cIn < 0) pcyOut->s.Hi = -1;
4236 else pcyOut->s.Hi = 0;
4237 pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
4238
4239 return S_OK;
4240}
4241
4242/**********************************************************************
4243 * VarCyFromUI2 [OLEAUT32.226]
4244 * Convert unsigned short to currency
4245 */
4246HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
4247 pcyOut->s.Hi = 0;
4248 pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
4249
4250 return S_OK;
4251}
4252
4253/**********************************************************************
4254 * VarCyFromUI4 [OLEAUT32.227]
4255 * Convert unsigned long to currency
4256 */
4257HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4258 double t = (double)ulIn * (double)10000;
4259 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4260 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4261
4262 return S_OK;
4263}
4264
4265
4266/**********************************************************************
4267 * DosDateTimeToVariantTime [OLEAUT32.14]
4268 * Convert dos representation of time to the date and time representation
4269 * stored in a variant.
4270 */
4271INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4272 DATE *pvtime)
4273{
4274 struct tm t;
4275
4276 TRACE("( 0x%x, 0x%x, 0x%p ), stub\n", wDosDate, wDosTime, pvtime );
4277
4278 t.tm_sec = (wDosTime & 0x001f) * 2;
4279 t.tm_min = (wDosTime & 0x07e0) >> 5;
4280 t.tm_hour = (wDosTime & 0xf800) >> 11;
4281
4282 t.tm_mday = (wDosDate & 0x001f);
4283 t.tm_mon = (wDosDate & 0x01e0) >> 5;
4284 t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
4285
4286 return TmToDATE( &t, pvtime );
4287}
4288
4289
4290/**********************************************************************
4291 * VarParseNumFromStr [OLEAUT32.46]
4292 */
4293HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
4294 NUMPARSE * pnumprs, BYTE * rgbDig)
4295{
4296 int i,lastent=0;
4297 int cDig;
4298 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
4299 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
4300
4301 /* The other struct components are to be set by us */
4302
4303 memset(rgbDig,0,pnumprs->cDig);
4304
4305 cDig = 0;
4306 for (i=0; strIn[i] ;i++) {
4307 if ((strIn[i]>='0') && (strIn[i]<='9')) {
4308 if (pnumprs->cDig > cDig) {
4309 *(rgbDig++)=strIn[i]-'0';
4310 cDig++;
4311 lastent = i;
4312 }
4313 }
4314 }
4315 pnumprs->cDig = cDig;
4316
4317 /* FIXME: Just patching some values in */
4318 pnumprs->nPwr10 = 0;
4319 pnumprs->nBaseShift = 0;
4320 pnumprs->cchUsed = lastent;
4321 pnumprs->dwOutFlags = NUMPRS_DECIMAL;
4322 return S_OK;
4323}
4324
4325
4326/**********************************************************************
4327 * VarNumFromParseNum [OLEAUT32.47]
4328 */
4329HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
4330 ULONG dwVtBits, VARIANT * pvar)
4331{
4332 DWORD xint;
4333 int i;
4334 FIXME("(,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
4335
4336 xint = 0;
4337 for (i=0;i<pnumprs->cDig;i++)
4338 xint = xint*10 + rgbDig[i];
4339
4340 VariantInit(pvar);
4341 if (dwVtBits & VTBIT_I4) {
4342 V_VT(pvar) = VT_I4;
4343 V_UNION(pvar,intVal) = xint;
4344 return S_OK;
4345 }
4346 if (dwVtBits & VTBIT_R8) {
4347 V_VT(pvar) = VT_R8;
4348 V_UNION(pvar,dblVal) = xint;
4349 return S_OK;
4350 } else {
4351 FIXME("vtbitmask is unsupported %lx\n",dwVtBits);
4352 return E_FAIL;
4353 }
4354}
4355
4356
4357/**********************************************************************
4358 * VariantTimeToDosDateTime [OLEAUT32.13]
4359 * Convert variant representation of time to the date and time representation
4360 * stored in dos.
4361 */
4362INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
4363{
4364 struct tm t;
4365 wDosTime = 0;
4366 wDosDate = 0;
4367
4368 TRACE("( 0x%x, 0x%x, 0x%p ), stub\n", *wDosDate, *wDosTime, &pvtime );
4369
4370 if (DateToTm(pvtime, 0, &t) < 0) return 0;
4371
4372 *wDosTime = *wDosTime | (t.tm_sec / 2);
4373 *wDosTime = *wDosTime | (t.tm_min << 5);
4374 *wDosTime = *wDosTime | (t.tm_hour << 11);
4375
4376 *wDosDate = *wDosDate | t.tm_mday ;
4377 *wDosDate = *wDosDate | t.tm_mon << 5;
4378 *wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
4379
4380 return 1;
4381}
4382
4383
4384/***********************************************************************
4385 * SystemTimeToVariantTime [OLEAUT32.184]
4386 */
4387HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime, double *pvtime )
4388{
4389 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4390 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4391
4392 struct tm t;
4393
4394 TRACE(" %d/%d/%d %d:%d:%d\n",
4395 lpSystemTime->wMonth, lpSystemTime->wDay,
4396 lpSystemTime->wYear, lpSystemTime->wHour,
4397 lpSystemTime->wMinute, lpSystemTime->wSecond);
4398
4399 if (lpSystemTime->wYear >= 1900)
4400 {
4401 t.tm_sec = lpSystemTime->wSecond;
4402 t.tm_min = lpSystemTime->wMinute;
4403 t.tm_hour = lpSystemTime->wHour;
4404
4405 t.tm_mday = lpSystemTime->wDay;
4406 t.tm_mon = lpSystemTime->wMonth;
4407 t.tm_year = lpSystemTime->wYear;
4408
4409 return TmToDATE( &t, pvtime );
4410 }
4411 else
4412 {
4413 t.tm_sec = lpSystemTime->wSecond;
4414 t.tm_min = lpSystemTime->wMinute;
4415 t.tm_hour = lpSystemTime->wHour;
4416
4417 if (isleap(lpSystemTime->wYear) )
4418 t.tm_mday = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - lpSystemTime->wDay;
4419 else
4420 t.tm_mday = Days_Per_Month[13 - lpSystemTime->wMonth] - lpSystemTime->wDay;
4421
4422 t.tm_mon = 13 - lpSystemTime->wMonth;
4423 t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
4424
4425 TmToDATE( &t, pvtime );
4426
4427 *pvtime *= -1;
4428
4429 return 1;
4430 }
4431
4432 return 0;
4433}
4434
4435/***********************************************************************
4436 * VariantTimeToSystemTime [OLEAUT32.185]
4437 */
4438HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME lpSystemTime )
4439{
4440 double t = 0, timeofday = 0;
4441
4442 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4443 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4444
4445 /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
4446 static const BYTE Month_Code[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4447 static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
4448
4449 /* The Century_Code is used to find the Day of the Week */
4450 static const BYTE Century_Code[] = {0, 6, 4, 2};
4451
4452 struct tm r;
4453
4454 TRACE(" Variant = %f SYSTEMTIME ptr %p", vtime, lpSystemTime);
4455
4456 if (vtime >= 0)
4457 {
4458
4459 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4460
4461 lpSystemTime->wSecond = r.tm_sec;
4462 lpSystemTime->wMinute = r.tm_min;
4463 lpSystemTime->wHour = r.tm_hour;
4464 lpSystemTime->wDay = r.tm_mday;
4465 lpSystemTime->wMonth = r.tm_mon;
4466
4467 if (lpSystemTime->wMonth == 12)
4468 lpSystemTime->wMonth = 1;
4469 else
4470 lpSystemTime->wMonth++;
4471
4472 lpSystemTime->wYear = r.tm_year;
4473 }
4474 else
4475 {
4476 vtime = -1*vtime;
4477
4478 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
4479
4480 lpSystemTime->wSecond = r.tm_sec;
4481 lpSystemTime->wMinute = r.tm_min;
4482 lpSystemTime->wHour = r.tm_hour;
4483
4484 lpSystemTime->wMonth = 13 - r.tm_mon;
4485
4486 if (lpSystemTime->wMonth == 1)
4487 lpSystemTime->wMonth = 12;
4488 else
4489 lpSystemTime->wMonth--;
4490
4491 lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
4492
4493 if (!isleap(lpSystemTime->wYear) )
4494 lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
4495 else
4496 lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
4497
4498
4499 }
4500
4501 if (!isleap(lpSystemTime->wYear))
4502 {
4503 /*
4504 (Century_Code+Month_Code+Year_Code+Day) % 7
4505
4506 The century code repeats every 400 years , so the array
4507 works out like this,
4508
4509 Century_Code[0] is for 16th/20th Centry
4510 Century_Code[1] is for 17th/21th Centry
4511 Century_Code[2] is for 18th/22th Centry
4512 Century_Code[3] is for 19th/23th Centry
4513
4514 The year code is found with the formula (year + (year / 4))
4515 the "year" must be between 0 and 99 .
4516
4517 The Month Code (Month_Code[1]) starts with January and
4518 ends with December.
4519 */
4520
4521 lpSystemTime->wDayOfWeek = (
4522 Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
4523 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4524 Month_Code[lpSystemTime->wMonth]+
4525 lpSystemTime->wDay) % 7;
4526
4527 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4528 else lpSystemTime->wDayOfWeek -= 1;
4529 }
4530 else
4531 {
4532 lpSystemTime->wDayOfWeek = (
4533 Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
4534 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
4535 Month_Code_LY[lpSystemTime->wMonth]+
4536 lpSystemTime->wDay) % 7;
4537
4538 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
4539 else lpSystemTime->wDayOfWeek -= 1;
4540 }
4541
4542 t = floor(vtime);
4543 timeofday = vtime - t;
4544
4545 lpSystemTime->wMilliseconds = (timeofday
4546 - lpSystemTime->wHour*(1/24)
4547 - lpSystemTime->wMinute*(1/1440)
4548 - lpSystemTime->wSecond*(1/86400) )*(1/5184000);
4549
4550 return 1;
4551}
4552
4553/***********************************************************************
4554 * VarUdateFromDate [OLEAUT32.331]
4555 */
4556HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
4557{
4558 HRESULT i = 0;
4559 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4560 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4561
4562 TRACE("DATE = %f\n", (double)datein);
4563 i = VariantTimeToSystemTime(datein, &(pudateout->st) );
4564
4565 if (i)
4566 {
4567 pudateout->wDayOfYear = 0;
4568
4569 if (isleap(pudateout->st.wYear))
4570 {
4571 for (i =1; i<pudateout->st.wMonth; i++)
4572 pudateout->wDayOfYear += Days_Per_Month[i];
4573 }
4574 else
4575 {
4576 for (i =1; i<pudateout->st.wMonth; i++)
4577 pudateout->wDayOfYear += Days_Per_Month_LY[i];
4578 }
4579
4580 pudateout->wDayOfYear += pudateout->st.wDay;
4581 dwFlags = 0; /*VAR_VALIDDATE*/
4582 }
4583 else dwFlags = 0;
4584
4585 return i;
4586}
4587
4588/***********************************************************************
4589 * VarDateFromUdate [OLEAUT32.330]
4590 */
4591HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
4592 ULONG dwFlags, DATE *datein)
4593{
4594 HRESULT i;
4595 double t = 0;
4596 TRACE(" %d/%d/%d %d:%d:%d\n",
4597 pudateout->st.wMonth, pudateout->st.wDay,
4598 pudateout->st.wYear, pudateout->st.wHour,
4599 pudateout->st.wMinute, pudateout->st.wSecond);
4600
4601
4602 i = SystemTimeToVariantTime(&(pudateout->st), &t);
4603 *datein = t;
4604
4605 if (i) dwFlags = 0; /*VAR_VALIDDATE*/
4606 else dwFlags = 0;
4607
4608 return i;
4609}
4610
4611
4612/**********************************************************************
4613 * VarBstrCmp [OLEAUT32.440]
4614 *
4615 * flags can be:
4616 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
4617 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
4618 *
4619 */
4620HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
4621{
4622 DWORD r;
4623
4624 FIXME("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
4625
4626 if((!left) || (!right))
4627 return VARCMP_NULL;
4628
4629 if(flags&NORM_IGNORECASE)
4630 r = lstrcmpiW(left,right);
4631 else
4632 r = lstrcmpW(left,right);
4633
4634 if(r<0)
4635 return VARCMP_LT;
4636 if(r>0)
4637 return VARCMP_GT;
4638
4639 return VARCMP_EQ;
4640}
4641
4642/**********************************************************************
4643 * VarBstrCat [OLEAUT32.439]
4644 */
4645HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
4646{
4647 BSTR result;
4648
4649 TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
4650
4651 if( (!left) || (!right) || (!out) )
4652 return 0;
4653
4654 result = SysAllocStringLen(left, lstrlenW(left)+lstrlenW(right));
4655 lstrcatW(result,right);
4656
4657 *out = result;
4658
4659 return 1;
4660}
4661
Note: See TracBrowser for help on using the repository browser.