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

Last change on this file since 8450 was 8450, checked in by sandervl, 23 years ago

Wine resync

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