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

Last change on this file since 6648 was 6648, checked in by bird, 24 years ago

Added $Id:$ keyword.

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