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

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

wine typelib update

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